XGraph v1.1.1.0 : Real time data plotting.

Post your working scripts, libraries and tools for AHK v1.1 and older
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

XGraph v1.1.1.0 : Real time data plotting.

05 May 2014, 19:14

Easy to use, Light weight, fast, efficient GDI based function library for graphically plotting real time data.
Typical applications include real time usage/performance charts for CPU, HDD, Network etc and to a limited extent, it can also be used for historical charts like Weather, Stock etc.

Simple example follows. ( Another example )

Image

Code: Select all

ListLines, Off
#NoEnv
#SingleInstance, Force
#Include XGraph.ahk

Gui, Add, Text, w300 h105 hwndErrorLevel            ; Create a Text control
pGraph := XGraph( ErrorLevel )                      ; Attach XGraph
Gui, Show,, XGraph : Plotting Random values

SetTimer, RandomPlot

F1::Msgbox, 0x1040, XGraph, % XGraph_Info( pGraph ) ; // end of auto-execute section //

RandomPlot:
 Random, MY2, 0, 100
 XGraph_Plot( pGraph, MY2 )                         ; Plot values 
Return
The Library: XGraph.ahk

Code: Select all

/*
     __    __  __          __ __       __    __                 _       __                   
    / /_  / /_/ /_____  _ / // /____ _/ /_  / /________________(_)___  / /_ ____  _______
   / __ \/ __/ __/ __ \(_) // // __ '/ __ \/ //_/ ___/ ___/ __/ / __ \/ __// __ \/ __/ _ \     
  / / / / /_/ /_/ /_/ / / // // /_/ / / / / ,< (__  ) /__/ / / / /_/ / /__/ /_/ / / / // / 
 /_/ /_/\__/\__/ .___(_) // / \__,_/_/ /_/_/|_/____/\___/_/ /_/ .___/\__(_)____/_/  \__ /  
              /_/     /_//_/                                 /_/                   (___/   
              
  Script      :  XGraph v1.1.1.0 : Real time data plotting.
                 http://ahkscript.org/boards/viewtopic.php?t=3492
                 Created: 24-Apr-2014,  Last Modified: 09-May-2014 

  Description :  Easy to use, Light weight, fast, efficient GDI based function library for 
                 graphically plotting real time data.

  Author      :  SKAN - Suresh Kumar A N ( [email protected] )
  Demos       :  CPU Load Monitor > http://ahkscript.org/boards/viewtopic.php?t=3413
  
- -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
*/

XGraph( hCtrl, hBM := 0, ColumnW := 3, LTRB := "0,2,0,2", PenColor := 0x808080, PenSize := 1, SV := 0 ) {
Static WM_SETREDRAW := 0xB, STM_SETIMAGE := 0x172, PS_SOLID := 0, cbSize := 136, SRCCOPY := 0x00CC0020 
     , GPTR := 0x40, OBJ_BMP := 0x7, LR_CREATEDIBSECTION := 0x2000, LR_COPYDELETEORG := 0x8

; Validate control  
  WinGetClass, Class,   ahk_id %hCtrl%  
  Control, Style, +0x5000010E,, ahk_id %hCtrl% 
  ControlGet, Style, Style,,, ahk_id %hCtrl%
  ControlGet, ExStyle, ExStyle,,, ahk_id %hCtrl%
  ControlGetPos,,, CtrlW, CtrlH,, ahk_id %hCtrl% 
  If not ( Class == "Static" and Style = 0x5000010E and ExStyle = 0 and CtrlW > 0 and CtrlH > 0 ) 
     Return 0, ErrorLevel := -1

; Validate Bitmap
  If ( DllCall( "GetObjectType", "Ptr",hBM ) <> OBJ_BMP )
       hTargetBM := DllCall( "CreateBitmap", "Int",2, "Int",2, "UInt",1, "UInt",16, "Ptr",0, "Ptr" )
    ,  hTargetBM := DllCall( "CopyImage", "Ptr",hTargetBM, "UInt",0, "Int",CtrlW, "Int",CtrlH
                           , "UInt",LR_CREATEDIBSECTION|LR_COPYDELETEORG, "Ptr" )
  else hTargetBM := hBM  

  VarSetCapacity( BITMAP,32,0 )    
  DllCall( "GetObject", "Ptr",hTargetBM, "Int",( A_PtrSize = 8 ? 32 : 24 ), "Ptr",&BITMAP )
  If NumGet( BITMAP, 18, "UInt" ) < 16 ; Checking if BPP < 16  
     Return 0, ErrorLevel := -2
  Else BitmapW := NumGet( BITMAP,  4, "UInt" ),  BitmapH := NumGet( BITMAP, 8, "UInt" )     
  If ( BitmapW <> CtrlW or BitmapH <> CtrlH )               
     Return 0, ErrorLevel := -3

; Validate Margins and Column width   
  StringSplit, M, LTRB, `, , %A_Space% ; Left,Top,Right,Bottom
  MarginL := ( M1+0 < 0 ? 0 : M1 ),    MarginT     := ( M2+0 < 0 ? 0 : M2 )
  MarginR := ( M3+0 < 0 ? 0 : M3 ),    MarginB     := ( M4+0 < 0 ? 0 : M4 )  
  ColumnW := ( ColumnW+0 < 0 ? 3 : ColumnW & 0xff ) ; 1 - 255

; Derive Columns, BitBlt dimensions, Movement coords for Lineto() and MoveToEx()  
  Columns := ( BitmapW - MarginL - MarginR ) // ColumnW 
  BitBltW := Columns * ColumnW,                BitBltH := BitmapH - MarginT - MarginB
  MX1     := BitBltW - ColumnW,                    MY1 := BitBltH - 1 
  MX2     := MX1 + ColumnW - ( PenSize < 1 ) ;     MY2 := < user defined >

; Initialize Memory Bitmap
  hSourceDC  := DllCall( "CreateCompatibleDC", "Ptr",0, "Ptr" ) 
  hSourceBM  := DllCall( "CopyImage", "Ptr",hTargetBM, "UInt",0, "Int",ColumnW * 2 + BitBltW
                       , "Int",BitBltH, "UInt",LR_CREATEDIBSECTION, "Ptr" )   
  DllCall( "SaveDC", "Ptr",hSourceDC ) 
  DllCall( "SelectObject", "Ptr",hSourceDC, "Ptr",hSourceBM )

  hTempDC    := DllCall( "CreateCompatibleDC", "Ptr",0, "Ptr" )
  DllCall( "SaveDC", "Ptr",hTempDC )
  DllCall( "SelectObject", "Ptr",hTempDC, "Ptr",hTargetBM )

  If ( hTargetBM <> hBM )
    hBrush := DllCall( "CreateSolidBrush", UInt,hBM & 0xFFFFFF, "Ptr" )
  , VarSetCapacity( RECT, 16, 0 )
  , NumPut( BitmapW, RECT, 8, "UInt" ),  NumPut( BitmapH, RECT,12, "UInt" )
  , DllCall( "FillRect", "Ptr",hTempDC, "Ptr",&RECT, "Ptr",hBrush )
  , DllCall( "DeleteObject", "Ptr",hBrush )
  
  DllCall( "BitBlt", "Ptr",hSourceDC, "Int",ColumnW * 2, "Int",0, "Int",BitBltW, "Int",BitBltH
                   , "Ptr",hTempDC,   "Int",MarginL, "Int",MarginT, "UInt",SRCCOPY )
  DllCall( "BitBlt", "Ptr",hSourceDC, "Int",0, "Int",0, "Int",BitBltW, "Int",BitBltH
                   , "Ptr",hTempDC,   "Int",MarginL, "Int",MarginT, "UInt",SRCCOPY )

; Validate Pen color / Size                                                                    
  PenColor   := ( PenColor + 0 <> "" ? PenColor & 0xffffff : 0x808080 ) ; Range: 000000 - ffffff
  PenSize    := ( PenSize  + 0 <> "" ? PenSize & 0xf : 1 )              ; Range: 0 - 15                
  hSourcePen := DllCall( "CreatePen", "Int",PS_SOLID, "Int",PenSize, "UInt",PenColor, "Ptr" )
  DllCall( "SelectObject", "Ptr",hSourceDC, "Ptr",hSourcePen )
  DllCall( "MoveToEx", "Ptr",hSourceDC, "Int",MX1, "Int",MY1, "Ptr",0 )

  hTargetDC := DllCall( "GetDC", "Ptr",hCtrl, "Ptr" ) 
  DllCall( "BitBlt", "Ptr",hTargetDC, "Int",0, "Int",0, "Int",BitmapW, "Int",BitmapH
                   , "Ptr",hTempDC,   "Int",0, "Int",0, "UInt",SRCCOPY ) 

  DllCall( "RestoreDC", "Ptr",hTempDC, "Int",-1 )
  DllCall( "DeleteDC",  "Ptr",hTempDC )    

  DllCall( "SendMessage", "Ptr",hCtrl, "UInt",WM_SETREDRAW, "Ptr",False, "Ptr",0 ) 
  hOldBM := DllCall( "SendMessage", "Ptr",hCtrl, "UInt",STM_SETIMAGE, "Ptr",0, "Ptr",hTargetBM )    
  DllCall( "SendMessage", "Ptr",hCtrl, "UInt",WM_SETREDRAW, "Ptr",True,  "Ptr",0 )
  DllCall( "DeleteObject", "Ptr",hOldBM )

; Create / Update Graph structure
  DataSz := ( SV = 1 ? Columns * 8 : 0 )
  pGraph := DllCall( "GlobalAlloc", "UInt",GPTR, "Ptr",cbSize + DataSz, "UPtr" )
  NumPut( DataSz, pGraph + cbSize - 8   )     
  VarL := "cbSize / hCtrl / hTargetDC / hSourceDC / hSourceBM / hSourcePen / ColumnW / Columns / "
        . "MarginL / MarginT / MarginR / MarginB / MX1 / MX2 / BitBltW / BitBltH" 
  Loop, Parse, VarL, /, %A_Space%
    NumPut( %A_LoopField%, pGraph + 0, ( A_Index - 1 ) * 8 )

Return pGraph          
}

; -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -

XGraph_Info( pGraph, FormatFloat := "" ) {
Static STM_GETIMAGE := 0x173
  IfEqual, pGraph, 0, Return "",    ErrorLevel := -1 
  T := "`t",  TT := "`t:`t",  LF := "`n", SP := "                "

  pData := pGraph + NumGet( pGraph + 0 ), DataSz := Numget( pData-8 )
  If ( FormatFloat <> "" and DataSz )
    GoTo, XGraph_Info_Data  
 
  VarL := "cbSize / hCtrl / hTargetDC / hSourceDC / hSourceBM / hSourcePen / ColumnW / Columns / "
        . "MarginL / MarginT / MarginR / MarginB / MX1 / MX2 / BitBltW / BitBltH" 
  Loop, Parse, VarL, /, %A_Space%
    Offset := ( A_Index - 1 ) * 8,         %A_LoopField% := NumGet( pGraph + 0, OffSet )
  , RAW    .= SubStr( Offset SP,1,3 ) T SubStr( A_LoopField SP,1,16 ) T %A_LoopField% LF
  
  hTargetBM := DllCall( "SendMessage", "Ptr",hCtrl, "UInt",STM_GETIMAGE, "Ptr",0, "Ptr",0 )
  VarSetCapacity( BITMAP,32,0 )
  DllCall( "GetObject", "Ptr",hTargetBM, "Int",( A_PtrSize = 8 ? 32 : 24 ), "Ptr",&BITMAP )
  TBMW := NumGet( BITMAP,  4, "UInt" ),            TBMH := NumGet( BITMAP, 8, "UInt" )
  TBMB := NumGet( BITMAP, 12, "UInt" ) * TBMH,     TBMZ := Round( TBMB/1024,2 )
  TBPP := NumGet( BITMAP, 18, "UShort" )
  Adj := ( Adj := TBMW - MarginL - BitBltW - MarginR ) ? " (-" Adj ")" : ""

  DllCall( "GetObject", "Ptr",hSourceBM, "Int",( A_PtrSize = 8 ? 32 : 24 ), "Ptr",&BITMAP )
  SBMW := NumGet( BITMAP,  4, "UInt" ),            SBMH := NumGet( BITMAP, 8, "UInt" )
  SBMB := NumGet( BITMAP, 12, "UInt" ) * SBMH,     SBMZ := Round( SBMB/1024,2 )
  SBPP := NumGet( BITMAP, 18, "UShort" )
   
Return "GRAPH Properties" LF LF
 . "Screen BG Bitmap   " TT TBMW ( Adj ) "x" TBMH " " TBPP "bpp ( " TBMZ " KB )" LF
 . "Margins ( L,T,R,B )" TT MarginL "," MarginT "," MarginR "," MarginB LF 
 . "Client Area        " TT MarginL "," MarginT "," MarginL+BitBltW-1 "," MarginT+BitBltH-1 LF LF
 . "Memory Bitmap      " TT SBMW         "x" SBMH " " SBPP "bpp ( " SBMZ " KB )" LF 
 . "Graph Width        " TT BitBltW " px ( " Columns " cols x " ColumnW " px )" LF
 . "Graph Height (MY2) " TT BitBltH " px ( y0 to y" BitBltH - 1 " )" LF  
 . "Graph Array        " TT ( DataSz=0 ? "NA" : Columns " cols x 8 bytes = " DataSz " bytes" ) LF LF 
 . "Pen start position " TT MX1 "," BitBltH - 1 LF
 . "LineTo position    " TT MX2 "," "MY2" LF
 . "MoveTo position    " TT MX1 "," "MY2" LF LF
 . "STRUCTURE ( Offset / Variable / Raw value )" LF LF RAW

XGraph_Info_Data:

  AFF := A_FormatFloat 
  SetFormat, FloatFast, %FormatFloat%
  Loop % DataSz // 8  
    Values .= SubStr( A_Index "   ", 1, 4  ) T NumGet( pData - 8, A_Index * 8, "Double" ) LF
  SetFormat, FloatFast, %AFF%
  StringTrimRight, Values, Values, 1                                                                          

Return Values      
}

; -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -

XGraph_Plot( pGraph, MY2 := "", SetVal := "", Draw := 1 ) {
Static SRCCOPY := 0x00CC0020

  IfEqual, pGraph, 0, Return "",    ErrorLevel := -1 
  pData     := pGraph + NumGet( pGraph + 0 ),     DataSz     := Numget( pData - 8 )

, hSourceDC := NumGet( pGraph + 24 ),             BitBltW    := NumGet( pGraph + 112 )     
, hTargetDC := NumGet( pGraph + 16 ),             BitBltH    := NumGet( pGraph + 120 )
, ColumnW   := NumGet( pGraph + 48 )           

, MarginL   := NumGet( pGraph + 64 ),             MX1 := NumGet( pGraph + 096 )
, MarginT   := NumGet( pGraph + 72 ),             MX2 := NumGet( pGraph + 104 ) 

  If not ( MY2 = "" )                                 
     DllCall( "BitBlt", "Ptr",hSourceDC, "Int",0, "Int",0, "Int",BitBltW + ColumnW, "Int",BitBltH
                    , "Ptr",hSourceDC, "Int",ColumnW, "Int",0, "UInt",SRCCOPY )
  ,  DllCall( "LineTo",   "Ptr",hSourceDC, "Int",MX2, "Int",MY2 )
  ,  DllCall( "MoveToEx", "Ptr",hSourceDC, "Int",MX1, "Int",MY2, "Ptr",0 )
                    
  If ( Draw = 1 ) 
     DllCall( "BitBlt", "Ptr",hTargetDC, "Int",MarginL, "Int",MarginT, "Int",BitBltW, "Int",BitBltH
                      , "Ptr",hSourceDC, "Int",0, "Int",0, "UInt",SRCCOPY )

  If not ( MY2 = "" or SetVal = "" or DataSz = 0 ) 
     DllCall( "RtlMoveMemory", "Ptr",pData, "Ptr",pData + 8, "Ptr",DataSz - 8 )
  ,  NumPut( SetVal, pData + DataSz - 8, 0, "Double" )

Return 1
} 

; -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -

XGraph_SetVal( pGraph, Double := 0, Column := "" ) {

  IfEqual, pGraph, 0, Return "",    ErrorLevel := -1 
  pData := pGraph + NumGet( pGraph + 0 ), DataSz := Numget( pData - 8 )
  IfEqual, DataSz, 0, Return 0

  If ( Column = "" )
       DllCall( "RtlMoveMemory", "Ptr",pData, "Ptr",pData + 8, "Ptr",DataSz - 8 )
     , pNumPut := pData + DataSz 
  else Columns := NumGet( pGraph + 56 ) 
     , pNumPut := pData + ( Column < 0 or Column > Columns ? Columns * 8 : Column * 8 )

Return NumPut( Double, pNumPut - 8, 0, "Double" ) - 8       
}

; -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -

XGraph_GetVal( pGraph, Column := "" ) {
Static RECT
  If not VarSetCapacity( RECT )
         VarSetCapacity( RECT, 16, 0 )

  IfEqual, pGraph, 0, Return "",    ErrorLevel := -1
  pData   := pGraph + NumGet( pGraph + 0 ),   DataSz  := Numget( pData - 8 )
  Columns := NumGet( pGraph + 56 )
  If not ( Column = "" or DataSz = 0 or Column < 1 or Column > Columns )
    Return NumGet( pData - 8, Column * 8, "Double" ),    ErrorLevel := Column

  hCtrl   := NumGet( pGraph + 8   ),          ColumnW := NumGet( pGraph + 48 )                      
, BitBltW := NumGet( pGraph + 112 ),          MarginL := NumGet( pGraph + 64 )
, BitBltH := NumGet( pGraph + 120 ),          MarginT := NumGet( pGraph + 72 )

, Numput( MarginL, RECT, 0, "Int" ),          Numput( MarginT, RECT, 4, "Int" )
, DllCall( "ClientToScreen", "Ptr",hCtrl, "Ptr",&RECT )
, DllCall( "GetCursorPos", "Ptr",&RECT + 8 )

, MX := NumGet( RECT, 8, "Int" ) - NumGet( RECT, 0, "Int" ) 
, MY := NumGet( RECT,12, "Int" ) - NumGet( RECT, 4, "Int" )

, Column := ( MX >= 0 and MY >= 0 and MX < BitBltW and MY < BitBltH ) ? MX // ColumnW + 1 : 0
Return ( DataSz and Column ) ? NumGet( pData - 8, Column * 8, "Double" ) : "",    ErrorLevel := Column  
}

; -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -

XGraph_GetMean( pGraph, TailCols := "" ) {

  IfEqual, pGraph, 0, Return "",    ErrorLevel := -1 
  pData := pGraph + NumGet( pGraph + 0 ), DataSz := Numget( pData - 8 )
  IfEqual, DataSz, 0, Return 0,     ErrorLevel := 0

  Columns := NumGet( pGraph + 56 )
  pDataEnd := pGraph + NumGet( pGraph + 0 ) + ( Columns * 8 )
  TailCols := ( TailCols = "" or TailCols < 1 or Tailcols > Columns ) ? Columns : TailCols

  Loop %TailCols%
    Value += NumGet( pDataEnd - ( A_Index * 8 ), 0, "Double"  )

Return Value / TailCols,            ErrorLevel := TailCols
}

; -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -

XGraph_Detach( pGraph ) {
  IfEqual, pGraph, 0, Return 0
 
  VarL := "cbSize / hCtrl / hTargetDC / hSourceDC / hSourceBM / hSourcePen"
  Loop, Parse, VarL, /, %A_Space%
    %A_LoopField% := NumGet( pGraph + 0, ( A_Index - 1 ) * 8 )

  DllCall( "ReleaseDC",    "Ptr",hCtrl, "Ptr",hTargetDC )
  DllCall( "RestoreDC",    "Ptr",hSourceDC, "Int",-1  )
  DllCall( "DeleteDC",     "Ptr",hSourceDC  )
  DllCall( "DeleteObject", "Ptr",hSourceBM  )               
  DllCall( "DeleteObject", "Ptr",hSourcePen )

Return DllCall( "GlobalFree", "Ptr",pGraph, "Ptr"  )   
}

; -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -

XGraph_MakeGrid(  CellW, CellH, Cols, Rows, GLClr, BGClr, ByRef BMPW := "", ByRef BMPH := "" ) {
Static LR_Flag1 := 0x2008 ; LR_CREATEDIBSECTION := 0x2000 | LR_COPYDELETEORG := 8
    ,  LR_Flag2 := 0x200C ; LR_CREATEDIBSECTION := 0x2000 | LR_COPYDELETEORG := 8 | LR_COPYRETURNORG := 4 
    ,  DC_PEN := 19

  BMPW := CellW * Cols + 1,  BMPH := CellH * Rows + 1
  hTempDC := DllCall( "CreateCompatibleDC", "Ptr",0, "Ptr" )
  DllCall( "SaveDC", "Ptr",hTempDC )
  
  If ( DllCall( "GetObjectType", "Ptr",BGClr ) = 0x7 ) 
    hTBM := DllCall( "CopyImage", "Ptr",BGClr, "Int",0, "Int",BMPW, "Int",BMPH, "UInt",LR_Flag2, "UPtr" )
  , DllCall( "SelectObject", "Ptr",hTempDC, "Ptr",hTBM )

  Else 
    hTBM := DllCall( "CreateBitmap", "Int",2, "Int",2, "UInt",1, "UInt",24, "Ptr",0, "Ptr" )
  , hTBM := DllCall( "CopyImage", "Ptr",hTBM,  "Int",0, "Int",BMPW, "Int",BMPH, "UInt",LR_Flag1, "UPtr" )
  , DllCall( "SelectObject", "Ptr",hTempDC, "Ptr",hTBM )
  , hBrush := DllCall( "CreateSolidBrush", "UInt",BGClr & 0xFFFFFF, "Ptr" )
  , VarSetCapacity( RECT, 16 )
  , NumPut( BMPW, RECT, 8, "UInt" ),  NumPut( BMPH, RECT, 12, "UInt" )
  , DllCall( "FillRect", "Ptr",hTempDC, "Ptr",&RECT, "Ptr",hBrush )
  , DllCall( "DeleteObject", "Ptr",hBrush )

  hPenDC := DllCall( "GetStockObject", "Int",DC_PEN, "Ptr" ) 
  DllCall( "SelectObject",  "Ptr",hTempDC, "Ptr",hPenDC )
  DllCall( "SetDCPenColor", "Ptr",hTempDC, "UInt",GLClr & 0xFFFFFF )

  Loop, % Rows + 1 + ( X := Y := 0 )  
    DllCall( "MoveToEx", "Ptr",hTempDC, "Int",X,    "Int",Y, "Ptr",0  )
  , DllCall( "LineTo",   "Ptr",hTempDC, "Int",BMPW, "Int",Y ),  Y := Y + CellH
  
  Loop, % Cols + 1 + ( X := Y := 0 )
    DllCall( "MoveToEx", "Ptr",hTempDC, "Int",X, "Int",Y, "Ptr",0 )
  , DllCall( "LineTo",   "Ptr",hTempDC, "Int",X, "Int",BMPH ),  X := X + CellW

  DllCall( "RestoreDC", "Ptr",hTempDC, "Int",-1 )
  DllCall( "DeleteDC",  "Ptr",hTempDC )    

Return hTBM
}

; -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
The functions and parameters:

Image
  • XGraph() Create and attach graph. Returns a pointer to Graph data:
  • hCtrl : Hwnd of Static control.
    • The control's dimension ( W x H ) should be present and exactly match the size of the background bitmap.
    • It is preferable to use a Text control instead of Picture control.
    • Do not use any styles/exstyles or associate a variable with this control. To be specific: The text control should not have a non-client area.
  • hBM : This parameter can be either hBitmap ( BPP 16|24 ) or COLORREF ( eg. 0x0000FF = Red ) that will be used as background.
    Note: The background bitmap will be applied to the control with STM_SETIMAGE. This means: The graph line may disappear when the timer is not running or the script is paused etc., But whenever window redraws, it draws the background bitmap and there is a guaranteed placeholder.
    • If hBitmap, the dimension ( W x H ) should exactly match the size of the control.
    • The bitmap can be a Grid returned by XGraph_MakeGrid(), or a vertical linear gradient returned by CreateDIB(). A horizontal linear gradient will produce undesirable result whilst plotting.
    • If this parameter is a COLORREF ( eg. 0x0000FF = Red ), XGraph creates a 16BPP bitmap and fills it with COLORREF passed.
    • Default value is 0x000000 and a black bitmap matching control's dimension is automatically created.
  • ColumnW : Column width for each graph line, in pixels.
    • Total columns is derived from this parameter. eg. For a background bitmap width of 600px with no left/right margins and ColumnW of 3, the Total columns will be 600//3 = 200 Columns.
    • Default value is 2 and valid range is from 1 to 255.
  • LTRB : Margin for Left,Top,Right,Bottom.
    • XGraph derives a virtual client area ( or graph area ) using the margins specified. ( and is the reason why text control should not have styles like WS_BORDER or SS_SUNKEN )
    • Image transfer will occur from Memory bitmap to screen, only for the derived graph area. A background bitmap can be many times large than the graph area and LTRB allows you to specify the client rectangle where it actually needs to be drawn.
    • Default value is 0,2,0,2.
  • PenColor : The line color of graph passed as COLORREF.
    • Default value is 0x808080 and valid range is from 0 to 0xFFFFFF. Note: 24bit color is enforced.
  • PenSize : Thickness of graph line.
    • If 0 is passed, graph line will be short by 1px per column and will result in broken lines. This is a feature.
    • Default value is 1 and valid range is from 0 to 15.
    • Note: GDI lines are not anti-aliased. Line thickness and background color plays an important role in graph's appearance. Pen size of 1 or 2 will be ideal in most situations.
  • SV : Pass True to enable "Set Value" feature. Allocates space for internal array.
    • When SV is true, XGraph allocates memory space of 8 bytes ( data type = double ) for each column of graph.
    • Enabling internal array allows you to store/retrieve values with XGraph_Plot(), XGraph_SetVal(), XGraph_GetVal() and XGraph_GetMean().
    • Default value is False.
Image
  • XGraph_Plot() Plots graph line on FIFO basis. ( FIFO = First In, First Out ):
    For a graph with 30 columns, when 31st value is passed, the first value will move out of the graph.
    When called with single parameter, XGraph_Plot( pGraph ) will update screen without any actual plotting.
  • pGraph : Pointer to Graph data.
  • MY2 : The Y axis coordinate.
    • Pass a null value if you want to refresh/redraw the graph ( Draw should be True ).
    • Default value is NULL
  • SetVal : A Column value to store.
    • Updates internal array on FIFO basis.
    • Value will be ignored if MY2 is NULL.
    • Value will be ignored if internal array was not enabled when graph was created with XGraph().
    • Default value is NULL
  • Draw : Transfers the graph from memory to screen.
    • Default value is True.
    • For historical graphs, you can pass False until all columns have been plotted and then call XGraph_Plot( pGraph ) to update the screen.
Image
  • XGraph_Detach() Detaches graph from control and releases/frees the resources is use:
  • pGraph : Pointer to Graph data.
    • Passing invalid pointer to XGraph_Plot() etc, will result in appcrash. When successful, XGraph_Detach() returns 0, so it is advised to store the return value from this function to pGraph itself.
    • Correct usage: pGraph := XGraph_Detach( pGraph ). Functions that require pGraph as parameter will safely fail when pGraph equals zero
Image
  • XGraph_GetVal() Returns the associated value for a graph column:
    Note: Internal array should have been enabled when creating with XGraph().
  • pGraph : Pointer to Graph data.
  • Column : Valid column number in graph.
    • When invalid column number is passed, the value for the last column will be returned.
    • Default parameter is NULL
    • If this parameter is NULL, and the mouse pointer is over any of the columns, then value for the column under mouse will be returned and ErrorLevel will contain the column number under mouse
    • Suggested usage: Assign a subroutine [ GoSub Label ) to text control and from the subroutine call XGraph_GetVal() and display the return value in Status bar. Well, one would be tempted to use ToolTip, but it will trigger WM_PAINT() which will erase the graph line. The workaround is to call XGraph_Plot( pGraph ) every time WM_PAINT() is triggered.
Image
  • XGraph_SetVal() Manually sets a value for any column, Returns pointer to written data :
    Note: Internal array should have been enabled when creating with XGraph().
  • pGraph : Pointer to Graph data.
  • Double : The value.
  • Column : Valid column number in graph. Invalid number will set the value for last column.
Image
  • XGraph_GetMean() Returns arithmetic mean for specified no. of columns:
    Note: Internal array should have been enabled when creating with XGraph().
    ErrorLevel will contain the number of columns used for mean calculation.
  • pGraph : Pointer to Graph data.
  • TailCols : Number of columns ( at the tail of internal array ).
Image
  • XGraph_MakeGrid() Creates a bitmap and draws a grid on it, Returns hBitmap :
  • CellW : Cell width should be same as Column width parameter of XGraph()
  • CellH : Cell height.
  • Cols : Columns required.
  • Rows : Rows required.
  • GLClr : Color of grid line. Note: 24bit color is enforced.
  • BGClr : Background color. You can pass a hBitmap, which will be re-sized to fit the grid. You may create and pass a vertical linear gradient with CreateDIB()
  • BMPW : ByRef. Width of Bitmap.
  • BMPH : ByRef. Height of Bitmap.
Image
  • XGraph_Info() Returns either graph properties or Internal array data
  • pGraph : Pointer to Graph data.
  • FormatFloat:
    • If this parameter is NULL, the function returns graph properties.
    • If this parameter is non-NULL, it must be a valid float format like "0.2" which return all values from internal array
Image
:: end of documentation ::

Sample code posted in following topic should demonstrate most of the functionality:
CPULoad() : CPU usage percentage ( Demos for XGraph )
Screenshots from above topic:

Image

Image

Image

:)
My Scripts and Functions: V1  V2
User avatar
joedf
Posts: 8940
Joined: 29 Sep 2013, 17:08
Location: Canada
Contact:

Re: XGraph v1.1.1.0 : Real time data plotting.

05 May 2014, 21:15

WOW! THIS IS WAY COOL! I HAVE TO TRY THIS! :D
Image Image Image Image Image
Windows 10 x64 Professional, Intel i5-8500, NVIDIA GTX 1060 6GB, 2x16GB Kingston FURY Beast - DDR4 3200 MHz | [About Me] | [About the AHK Foundation] | [Courses on AutoHotkey]
[ASPDM - StdLib Distribution] | [Qonsole - Quake-like console emulator] | [LibCon - Autohotkey Console Library]
strobo
Posts: 125
Joined: 30 Sep 2013, 15:24

Re: XGraph v1.1.1.0 : Real time data plotting.

07 May 2014, 16:20

Killer -- in the meaning of "looks promising"**2.
Guest10
Posts: 578
Joined: 01 Oct 2013, 02:50

Re: XGraph v1.1.1.0 : Real time data plotting.

07 May 2014, 22:05

i guess this script could be also used to generate charts, too? i mean static charts like in Excel (with labels and all)? any examples of such charts?
User avatar
Learning one
Posts: 173
Joined: 04 Oct 2013, 13:59
Location: Croatia
Contact:

Re: XGraph v1.1.1.0 : Real time data plotting.

08 May 2014, 00:56

Guest10, look here; BarChart
Nice library SKAN! :)
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

Re: XGraph v1.1.1.0 : Real time data plotting.

08 May 2014, 05:10

Learning one wrote:Nice library SKAN! :)
Thanks. :)
Guest10 wrote:static charts like in Excel
GDI is very limited. Excel kind of charts requires GDI Plus. Learning one's Lib looks great :).

XGraph was specifically written to plot real time data at high speeds with bare minimum resources.

Here is an example:
When you move your mouse cursor fast enough, it can use 100% of CPU for 1ms which will not be caught by a CPU load monitor running with 1000ms timer as 100% usage for 1ms translates to 0.001% usage for 1000ms. Windows Task Manager's fastest speed is like 250ms. Any faster, the chart would peak as Task manager itself uses lot of CPU time.
You can call XGraph_Plot() several thousands of times without registering 1 second of CPU time... But of course, what you plot does matter. GetSystemTimes() does not use much CPU whereas 'Random' command does.

If not anything else, XGraph() can be a good performance testing tool.
I actually wrote it to monitor the performance of my Mobile dial-up connection ( EDGE ) which is as erratic as Random plotting.
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

XGraph_GetMean()

08 May 2014, 15:36

Update: Added new function XGraph_GetMean(). This function can return the average value for X number of columns from the end of internal array.

Here follows a demo that shows how to combine XGraph_SetVal() and XGraph_GetMean() to smoothen graph line.

Image

Code: Select all

ListLines, Off
#NoEnv
#SingleInstance, Force
#Include XGraph.ahk

Gui, Add, Text,, Raw Random Values
Gui, Add, Text,  y+3 w300 h105 hwndhGraph1           
Gui, Add, Text,, Smoothened Random Values ( mean of last 3 values )
Gui, Add, Text,  y+3 w300 h105 hwndhGraph2
Gui, Add, Text,, Smoothened Random Values ( mean of last 10 values )
Gui, Add, Text,  y+3 w300 h105 hwndhGraph3

pGraph1 := XGraph( hGraph1, 0, 3, "", 0xAAAA00, 1, False )                    
pGraph2 := XGraph( hGraph2, 0, 3, "", 0x00AAAA, 1, True  )
pGraph3 := XGraph( hGraph3, 0, 3, "", 0x00AA00, 1, True  )                    

Gui, Show,, XGraph : Plotting Random values
SetTimer, RandomPlot

Return ; // end of auto-execute section //

RandomPlot:
  Random, MY2, 0, 100

  XGraph_Plot( pGraph1, MY2 )                  ; Plot random value as is

  XGraph_SetVal( pGraph2, MY2 )                ; Update internal array with raw value
  SmoothMY2 := XGraph_GetMean( pGraph2, 3  )   ; Retrieve mean value for last 3 columns  
  XGraph_Plot( pGraph2, SmoothMY2 )            ; Plot smoothened value  

  XGraph_SetVal( pGraph3, MY2 )                ; Update internal array with raw value
  SmoothMY2 := XGraph_GetMean( pGraph3, 10 )   ; Retrieve mean value for last 10 columns  
  XGraph_Plot( pGraph3, SmoothMY2 )            ; Plot smoothened value  

Return
User avatar
tank
Posts: 3122
Joined: 28 Sep 2013, 22:15
Location: CarrolltonTX
Contact:

Re: XGraph v1.1.1.0 : Real time data plotting.

09 Jun 2014, 11:52

I wonder about data points?
dots on the line for each data point?
We are troubled on every side‚ yet not distressed; we are perplexed‚
but not in despair; Persecuted‚ but not forsaken; cast down‚ but not destroyed;
Telegram is the best way to reach me
https://t.me/ttnnkkrr
If you have forum suggestions please submit a
Check Out WebWriter
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

Re: XGraph v1.1.1.0 : Real time data plotting.

09 Jun 2014, 13:41

Hi tank, :)
you wrote:dots on the line for each data point
GDI is fast and efficient for a moving graph..
But since there is no anti-aliasing in GDI, I guess dots would not look good on the graph.
User avatar
evilC
Posts: 4822
Joined: 27 Feb 2014, 12:30

Re: XGraph v1.1.1.0 : Real time data plotting.

11 Jun 2014, 11:16

Hi,
Could this maybe be repurposed for a regular chart?

I would like to create something like the windows joystick test dialog using AHK.

ie, replicate the functionality of the moving "+" in the X/Y chart.
This dialog does not update when it does not have focus, whereas AHK does.

I would like to make a tool for YouTubers that generates graphics to represent state of keyboard / mouse / joystick, for tutorial videos etc.

Image
colt
Posts: 291
Joined: 04 Aug 2014, 23:12
Location: Portland Oregon

Re: XGraph v1.1.1.0 : Real time data plotting.

05 Aug 2014, 18:38

Thank you so much for posting this! I will be using this library extensively in my future projects.

Are there any plans to support resizing of the graph after it has been created? Currently resizing the text control resizes the background but does not scale the actual graph region.

-Colt

update- a project using xgraph to plot csv data from a file http://www.autohotkey.com/board/topic/1 ... =%2Bxgraph
Last edited by colt on 15 Jul 2015, 00:18, edited 1 time in total.
architech1906

Re: XGraph v1.1.1.0 : Real time data plotting.

26 Oct 2014, 23:06

Can this script allow multiple lines of real time data on the same graph. If so, how? I only see an implementation where one data group per plot. I'm still looking through your code but not sure how it would come together to generate multiple plots on a single graph.
Thanks for any assistance you can provide.
User avatar
Scoox
Posts: 125
Joined: 11 May 2014, 09:12
Location: China

Re: XGraph v1.1.1.0 : Real time data plotting.

13 Nov 2014, 00:34

Looks awesome, thanks for sharing!
ThomasB

Re: XGraph v1.1.1.0 : Real time data plotting.

01 Dec 2014, 03:45

like "architech1906" I tried to use it with multiple graphs using the same axis, but for me it seems at the moment it is not possible.

Any idea?
User avatar
moefr01
Posts: 115
Joined: 25 Nov 2015, 09:01
Location: Germany

Re: XGraph v1.1.1.0 : Real time data plotting.

17 Jul 2016, 04:53

Really great lib, SKAN... thank you for sharing! :clap:

any idea how to implement an filled area underneath the dataplot, with different (fading) colors and transparency for the negative values?
(see attached)

It would incredibly increase the readability from a far distance if you've to monitor different machines at the same time by showing each plot.

cheers
moefr01
Attachments
win10-graph-performance1.jpg
win10-graph-performance1.jpg (18.65 KiB) Viewed 32256 times
win10-graph-ressources.jpg
win10-graph-ressources.jpg (27.71 KiB) Viewed 32256 times
User avatar
SYnCR
Posts: 9
Joined: 25 Apr 2018, 02:32
Contact:

Re: XGraph v1.1.1.0 : Real time data plotting.

11 May 2018, 04:57

nice Job what you did there!

i got a question:
can you maybe add to the lib a way to Change the Graph-Color during the Graph is ploting?

i wan to use it for a Ping-Gui

if the ping is lower than 20ms the Graph should be in Green
if the ping is between 21-50 the Graph should be in Yellow
if the ping is between 51-80 the Graph should be in Orange
if the ping is higer than 80-error the Graph sould be in Red

maybe you can hit me up with a way to get this!

Thx already!

sorry for my bad english..

Have a good day!
SYnCR
pneumatic
Posts: 338
Joined: 05 Dec 2016, 01:51

Re: XGraph v1.1.1.0 : Real time data plotting.

06 Oct 2018, 22:03

I am finding at high DPI settings, the pen becomes quite badly aliased, which seems to be due to Windows' crappy raster upscaling. Increasing the pen thickness to 2 helps a bit, but it's still a bit nasty to look at, and I would like a nice anti-aliased smooth pen.

It seems it's possible to create a custom pen pattern with an antialised style, eg. adding some darker pixels around the center of the pen in a circular pattern.

According to MSDN, it seems instead of creating a regular pen like so in Xgraph:

Code: Select all

hSourcePen := DllCall( "CreatePen", "Int",PS_SOLID, "Int",PenSize, "UInt",PenColor, "Ptr" )
We could instead use ExtCreatePen. According to this, we first need to create a brush containing the pattern (which comes from a bitmap, eg. a .bmp file on disk) and pass the brush's handle to the ExtCreatePen function. This should create the pen with the custom brush pattern.

However I'm totally bamboozled by the ExtCreatePen function, as it requires all these data structures which I don't know how to create or even reference. For example I don't even know how to even get the hex code for basic parameters like eg. PS_SOLID := 0 - how did SKAN figure out PS_SOLID = 0? Are there some tools which can discover this? Also how do you discover what byte offsets to use in structures and arrays?

Thanks
Last edited by pneumatic on 07 Oct 2018, 20:55, edited 1 time in total.
expert_vision
Posts: 21
Joined: 13 Jan 2014, 10:47

Re: XGraph v1.1.1.0 : Real time data plotting.

07 Oct 2018, 04:14

pneumatic wrote:For example I don't even know how to even get the hex code for basic parameters like eg. PS_SOLID := 0 - how did SKAN figure out PS_SOLID = 0?
Uppercase names, like PS_SOLID, are constants in C++. If you look at the requirements section of this page, it tells you in which header the constants are defined. In this case, wingdi.h (include Windows.h).

To get the windows header install Visual Studio Community with "Desktop development with C++" checked.
Then to find where the constant is defined, create a new Visual C++ - Windows Console Application, then in ConsoleApplication1.cpp, in the include section type "#include <wingdi.h>" or "#include <windows.h>", then in main section type PS_SOLID on a new line. After that, right click PS_TOOLS and click "Go To Definition". And you're done :).
In this case it takes you to:
File: c:\Program Files (x86)\Windows Kits\10\Include\10.0.17134.0\um\wingdi.h
1967: #define PS_SOLID 0
pneumatic
Posts: 338
Joined: 05 Dec 2016, 01:51

Re: XGraph v1.1.1.0 : Real time data plotting.

07 Oct 2018, 20:54

Thanks!

In the meantime I found it helps reduce visibility of aliasing if I change the pen colour to be closer to the graph's background colour. eg. instead of doing a black pen on a white background, I made it a grey pen eg. RGB (152,152,152).

Another possibility might be to do the antialiasing manually in the Plot() function, eg. for each point that you plot, also plot a darker/lighter version of that point above and below.
pneumatic
Posts: 338
Joined: 05 Dec 2016, 01:51

Re: XGraph v1.1.1.0 : Real time data plotting.

08 Oct 2018, 03:27

It seems GDI+ supports antialiasing, but GDI doesn't (XGraph uses regular GDI). But here are some articles which show how it's possible to implement antialiasing manually in GDI.

Easy method - https://www.codeproject.com/Articles/21 ... indows-GDI
Hard method - https://www.codeproject.com/Articles/13 ... -Algorithm ;it seems we would use SetPixel instead of DrawPixel though

I'm attracted to the simplicity of the Easy method, but the hard method looks like it might produce a better result. Not really in the mood for attempting to port it though, maybe someday :lol:

edit: just a tip, the GetDCPenColor and SetDCPenColor functions are not compatible with a custom pen such as the one created in XGraph. To change the pen colour you need to make a whole new pen and then use SelectObject to select that pen into the device context (hSourceDC in XGraph). This one had me :headwall: for a couple of hours :lol:

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: No registered users and 120 guests