Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Mathematical Function Grapher


  • Please log in to reply
40 replies to this topic
jonny
  • Members
  • 2951 posts
  • Last active: Feb 24 2008 04:22 AM
  • Joined: 13 Nov 2004
A picture is worth a thousand words:

Posted Image
Two straight lines, sine, and arctan.


This set of functions can be used to make a pseudo-control that graphs simple equations of the form 'y = f(x)' (it's not actually a control, but just a bitmap drawn onto the GUI). Nearly everything is configurable, including the colors of all graphical elements, the viewable range of the graph, and the resolution of the grid.

;;;;;;;;;;;;;;; 
; 
; Function Grapher by jonny 
; 
; 
;;;Functions;;; 
; 
;GraphCreate(id,x,y,w,h,pre="") 
;   Initializes the graph, sets its options, 
;   and draws it at the specified location. 
;   Returns 1 if it's successful, 0 if there's 
;   a logical error (e.g. bad option), and blank 
;   if there's a problem allocating memory. 
; 
;  id: 
;   The window ID (ahk_id) of the window to 
;   draw the graph on. 
; 
;  x: 
;   The x-coordinate to draw the graph at. 
; 
;  y: 
;   The y-coordinate to draw the graph at. 
; 
;  w: 
;   The width of the graph. 
; 
;  h: 
;   The height of the graph. 
; 
;  pre: 
;   The prefix for the global option variables, 
;   explained further below. 
;   For example, if pre = "GraphOpts_", then it 
;   will read GraphOpts_xScl for the xScl option 
; 
; 
;Graph(equation,color=defGraphColor) 
;   Computes and draws the given equation on 
;   the graph. The equation must be in terms 
;   of the variable 'x', and it can contain any 
;   standard AHK operators and math functions. 
;   Returns 1 if it's successful, and 0 if 
;   the graph doesn't exist or if there's a 
;   problem with the computation. 
; 
;  equation: 
;   The equation to use. This must be in the form 
;   of a string, NOT a bare expression; however, 
;   it will eventually be parsed, so it must be 
;   valid as an expression. 
; 
;  color: 
;   The color to draw the equation in. This must 
;   be in RGB form (0xRRGGBB), not an HTML color. 
;   If this parameter is unspecified or not a valid 
;   RGB color, the defGraphColor option will be used. 
; 
; 
;GraphClear() 
;   Clears all equations off the graph. 
; 
; 
;GraphDraw() 
;   Redraws the graph. Shouldn't be necessary to 
;   use, since GraphCreate binds this to WM_PAINT. 
; 
; 
;GraphDestroy() 
;   Frees all memory associated with the graph. 
;   You MUST call this before exiting the script, 
;   or there will be a memory leak. 
;   Note that this will not remove the graph's image 
;   from the display. The window must be redrawn 
;   to visually clear it. 
; 
; 
; 
;;;Options;;; 
; 
; To use these, set any of them as global variables 
; with a consistent prefix (required). Then pass 
; the prefix to GraphCreate as a string, via the 
; 'pre' parameter. Any options left unset will get 
; their default values. 
; 
; 
;paperColor (0xFFFFFF - white) 
;   The color of the graph's background, or the 
;   "graph paper." Must be a full RGB color. 
; 
;axisColor (0x000000 - black) 
;   The color of the x and y axes, if visible. 
;   Must be a full RGB color. 
; 
;gridColor (0xDFDFDF - light grey) 
;   The color of the grid beneath the graph. 
;   Must be a full RGB color. 
; 
;defGraphColor (0x0000FF - blue) 
;   The default color for Graph(), if the 'color' 
;   parameter isn't valid or specified. 
; 
;lineWidth (3) 
;   The width of the lines generated by Graph(). 
;   Must be greater than or equal to zero. 
; 
;xScl (1) 
;   The scale of the x-plane of the grid, in 
;   logical units. For instance, a value of 10 
;   would draw a vertical line wherever x is 
;   a multiple of 10, and a value of 0.5 would 
;   draw two vertical lines for every integral 
;   x-value. Must be greater than zero. 
; 
;yScl (1) 
;   The scale of the y-plane of the grid, in 
;   logical units. Same as above, except for 
;   the horizontal lines with y. Must be greater 
;   than zero. 
; 
;xMin (-10) 
;   The smallest x-value displayed on the graph, 
;   or the left edge of its viewable area. Must 
;   be less than xMax. 
; 
;yMin (-10) 
;   The smallest y-value displayed on the graph, 
;   or the bottom edge of its viewable area. Must 
;   be less than yMax. 
; 
;xMax (10) 
;   The largest x-value displayed on the graph, 
;   or the right edge of its viewable area. Must 
;   be greater than xMin. 
; 
;yMax (10) 
;   The largest y-value displayed on the graph, 
;   or the top edge of its viewable area. Must be 
;   greater than yMin. 
; 
; 
; 
;;;Remarks;;; 
; 
; Use this at your own risk. I've tested it a lot, 
; but there's still a chance it'll cause a serious 
; memory leak. 
; 
; Avoid naming any global variables with the prefix 
; '__graph_' while the graph is created, since these 
; functions use it to communicate. 
; 
; Graph() uses two temporary files which it creates 
; in A_Temp, so don't be alarmed if you notice that 
; your script is suddenly opening weird files. (It 
; deletes them when it's finished, so they'll only 
; consume space for a few milliseconds.) 
; 


GraphCreate(WindowID,xCoord,yCoord,Width,Height,OptPre="") 
{ 
   global 
   local paperColor,axisColor,gridColor,xScl,yScl,xMin,yMin 
         ,xMax,yMax,Pen,Brush 
    
   if __graph_Exists 
      return 0 

;options 
   ;background color (white) 
   paperColor := %OptPre%paperColor ? %OptPre%paperColor : 0xFFFFFF 

   ;color for axes (black) 
   axisColor := %OptPre%axisColor ? %OptPre%axisColor : 0x000000 

   ;grid color (grey) 
   gridColor := %OptPre%gridColor ? %OptPre%gridColor : 0xDFDFDF 

   ;default color for new equations (blue) 
   __graph_color := %OptPre%defGraphColor ? %OptPre%defGraphColor : 0x0000FF 

   ;width of equations' graphs 
   __graph_lineWidth := %OptPre%lineWidth ? %OptPre%lineWidth : 3 

   ;scale of grid for the x plane 
   xScl := %OptPre%xScl ? %OptPre%xScl : 1 

   ;scale of grid for the y plane 
   yScl := %OptPre%yScl ? %OptPre%yScl : 1 

   ;lowest x-value shown on graph 
   xMin := %OptPre%xMin ? %OptPre%xMin : -10 

   ;lowest y-value shown on graph 
   yMin := %OptPre%yMin ? %OptPre%yMin : -10 

   ;highest x-value shown on graph 
   xMax := %OptPre%xMax ? %OptPre%xMax : 10 

   ;highest y-value shown on graph 
   yMax := %OptPre%yMax ? %OptPre%yMax : 10 

   ;sanity checks 
   if (paperColor > 0xFFFFFF || paperColor < 0 
    || axisColor  > 0xFFFFFF || axisColor  < 0 
    || gridColor  > 0xFFFFFF || gridColor  < 0 
    || __graph_color > 0xFFFFFF || __graph_color < 0 
    || __graph_lineWidth < 0 
    || xScl <= 0 || yScl <= 0 
    || xMin >= xMax || yMin >= yMax) 
   { 
      __graph_color = 
      __graph_lineWidth = 
      return 0 
   } 

   __graph_X := xCoord 
   __graph_Y := yCoord 
   __graph_W := Width 
   __graph_H := Height 

   ;compute how many units on the graph each pixel 
   ;corresponds to 
   __graph_xUnit   := Width  / (xMax - xMin) 
   __graph_yUnit   := Height / (yMax - yMin) 

   ;how far, in graph units, the left 
   ;edge is from the origin 
   __graph_leftDist := xMin * __graph_xUnit 
   ;how far the top edge is from the 
   ;origin, this time in terms of y 
   __graph_topDist  := yMax * __graph_yUnit 
    
   ;Device Context for the window to be drawn to 
   __graph_WindowDC := DllCall("GetDC", UInt,WindowID) 
   if not __graph_WindowDC 
      return 
    
   ;first memory DC, containing the "graph paper," 
   ;the background of the graph 
   __graph_PaperDC := DllCall("CreateCompatibleDC", UInt,WindowDC) 
   if not __graph_PaperDC 
      return 
   ;create a bitmap on the DC 
   __graph_PaperDC_BM := DllCall("CreateCompatibleBitmap" 
      , UInt,__graph_WindowDC, UInt,Width, UInt,Height) 
   DllCall("SelectObject", UInt,__graph_PaperDC 
      , UInt,__graph_PaperDC_BM) 

   ;second Memory DC, containing the finished product 
   ;of the paper with the graphed equations on it 
   __graph_MemoryDC := DllCall("CreateCompatibleDC", UInt,WindowDC) 
   if not __graph_MemoryDC 
      return 
   ;create a bitmap on the DC 
   __graph_MemoryDC_BM := DllCall("CreateCompatibleBitmap" 
      , UInt,__graph_WindowDC, UInt,Width, UInt,Height) 
   DllCall("SelectObject", UInt,__graph_MemoryDC 
      , UInt,__graph_MemoryDC_BM) 

;set up the graph paper 
   ;first the background and border 
   Pen := DllCall("CreatePen", UInt,0, UInt,0, UInt,paperColor) 
   DllCall("SelectObject", UInt,__graph_PaperDC, UInt,Pen) 
   Brush := DllCall("CreateSolidBrush", UInt,paperColor) 
   DllCall("SelectObject", UInt,__graph_PaperDC, UInt,Brush) 
   DllCall("Rectangle", UInt,__graph_PaperDC, UInt,0, UInt,0 
      , UInt,Width, UInt,Height) 
   DllCall("DeleteObject", UInt,Pen) 
   DllCall("DeleteObject", UInt,Brush) 

   ;now the grid 
   Pen := DllCall("CreatePen", UInt,0, UInt,0, UInt,gridColor) 
   DllCall("SelectObject", UInt,__graph_PaperDC, UInt,Pen) 
   ;vertical lines (x-plane) 
   Loop 
   { 
      if (A_Index >= ( (xMax - xMin) / xScl )) 
         break 
      DllCall("MoveToEx", UInt,__graph_PaperDC 
         , UInt,Round(A_Index*__graph_xUnit*xScl), UInt,0, UInt,0) 
      DllCall("LineTo", UInt,__graph_PaperDC 
         , UInt,Round(A_Index*__graph_xUnit*xScl), UInt,Height) 
   } 
   ;horizontal lines (y-plane) 
   Loop 
   { 
      if (A_Index >= ( (yMax - yMin) / yScl )) 
         break 
      DllCall("MoveToEx", UInt,__graph_PaperDC 
         , UInt,0, UInt,Round(A_Index*__graph_yUnit*yScl), UInt,0) 
      DllCall("LineTo", UInt,__graph_PaperDC 
         , UInt,Width, UInt,Round(A_Index*__graph_yUnit*yScl)) 
   } 
   DllCall("DeleteObject", UInt,Pen)    

   ;axes 
   Pen := DllCall("CreatePen", UInt,0, UInt,0, UInt,axisColor) 
   DllCall("SelectObject", UInt,__graph_PaperDC, UInt,Pen) 
   if (xMin < 0 and xMax > 0) 
   { 
      DllCall("MoveToEx", UInt,__graph_PaperDC 
         , UInt,Round((-xMin)*__graph_xUnit), UInt,0, UInt,0) 
      DllCall("LineTo", UInt,__graph_PaperDC 
         , UInt,Round((-xMin)*__graph_xUnit), UInt,Height) 
   } 
   if (yMin < 0 and yMax > 0) 
   { 
      DllCall("MoveToEx", UInt,__graph_PaperDC 
         , UInt,0, UInt,Round(yMax*__graph_yUnit), UInt,0) 
      DllCall("LineTo", UInt,__graph_PaperDC 
         , UInt,Width, UInt,Round(yMax*__graph_yUnit)) 
   } 
   DllCall("DeleteObject", UInt,Pen) 
    

   __graph_Exists := true 
   GraphClear() 
   ;WM_PAINT: 0x0F 
   OnMessage(0x0F,"GraphDraw") 
   return 1 
} 

Graph(Equation,Color = -1) 
{ 
   global 
   local EquDC,EquDC_BM,Pen,FirstVal,GraphSpec,R,G,B 

   if (!__graph_Exists or !A_AhkPath) 
      return 0 

   if (Color < 0 or Color > 0xFFFFFF) 
      Color := __graph_color 

   ;CreatePen expects a BGR-formatted COLORREF 
   R := Color & 0x0000FF 
   G := Color & 0x00FF00 
   B := Color & 0xFF0000 
   R <<= 16 
   B >>= 16 
   Color := R | G | B 


   ;px/py: Positional coordinates used to 
   ;       place the graph 
   ; 
   ;x/y: Actual coordinates that the function 
   ;       is computed in 
   ; 
   ;Equation must be in terms of 'x' 
   FileAppend, 
   ( LTrim 
      #NoTrayIcon 
      Loop %__graph_W% 
      { 
         px := A_Index 
         x := (px + %__graph_leftDist%) / %__graph_xUnit% 
          
         y := (%Equation%) * %__graph_yUnit% 
         py := Round(%__graph_topDist% - y) 

         GraphSpec .= py . ";" 
      } 
      FileDelete gspec 
      FileAppend,`%GraphSpec`%,gspec 
   ),%A_Temp%\tempGraph.ahk 

   RunWait,"%A_AhkPath%" "%A_Temp%\tempGraph.ahk",%A_Temp% 
   FileRead,GraphSpec,%A_Temp%\gspec 
   FileDelete %A_Temp%\tempGraph.ahk 
   FileDelete %A_Temp%\gspec 

   Pen := DllCall("CreatePen", UInt,0, UInt,__graph_lineWidth, UInt,Color) 
   DllCall("SelectObject", UInt,__graph_MemoryDC, UInt,Pen) 

   StringTrimRight,GraphSpec,GraphSpec,1 
   FirstVal := InStr(GraphSpec,";") 
   DllCall("MoveToEx", UInt,__graph_MemoryDC, UInt,1, UInt,SubStr(GraphSpec,1,FirstVal-1), UInt,0) 
   StringTrimLeft,GraphSpec,GraphSpec,FirstVal 
   Loop,Parse,GraphSpec,; 
      DllCall("LineTo", UInt,__graph_MemoryDC, UInt,A_Index + 1, UInt,A_LoopField) 

   DllCall("DeleteObject", UInt,Pen) 

   GraphDraw() 
   return 1 
} 

GraphClear() 
{ 
   global 
   if not __graph_Exists 
      return 
   DllCall("BitBlt", UInt,__graph_MemoryDC, UInt,0, UInt,0 
      , UInt,__graph_W, UInt,__graph_H, UInt,__graph_PaperDC 
      , UInt,0, UInt,0, UInt,0x00CC0020) 
   GraphDraw() 
} 

GraphDraw() 
{ 
   global 
   if not __graph_Exists 
      return 
   DllCall("BitBlt", UInt,__graph_WindowDC, UInt,__graph_X 
      , UInt,__graph_Y, UInt,__graph_W, UInt,__graph_H 
      , UInt,__graph_MemoryDC, UInt,0, UInt,0, UInt,0x00CC0020) 
} 

GraphDestroy() 
{ 
   global 

   ;WM_PAINT: 0x0F 
   OnMessage(0x0F,"") 
    
   DllCall("DeleteObject", UInt,__graph_PaperDC) 
   DllCall("DeleteObject", UInt,__graph_PaperDC_BM) 
   DllCall("DeleteObject", UInt,__graph_MemoryDC) 
   DllCall("DeleteObject", UInt,__graph_MemoryDC_BM) 
   DllCall("ReleaseDC", UInt,0, UInt,__graph_WindowDC) 

   __graph_PaperDC = 
   __graph_PaperDC_BM = 
   __graph_MemoryDC = 
   __graph_MemoryDC_BM = 
   __graph_WindowDC = 
   __graph_X = 
   __graph_Y = 
   __graph_W = 
   __graph_H = 
   __graph_color = 
   __graph_lineWidth = 
   __graph_xUnit = 
   __graph_yUnit = 
   __graph_leftDist = 
   __graph_topDist = 
   __graph_Exists = 
}

There are a few quirks with it. The way you set options is kind of awkward, I might replace that with a function sometime... also, it uses several global variables. They have an obscure prefix, but this is still fundamentally bad style. They could probably be replaced with another function.

In any case, this is just the first version and there could be any number of things wrong with it, so don't rely heavily on its stability.

The GUI you see in the screenshot is not a direct product of these functions. You have to do everything else but the graph, including any kind of border you want around it (I used one-pixel wide Progress controls, though it didn't work out very well). Here's a script almost identical to the one I used to make the screenshot, except that you can specify the functions at runtime, rather than hardcoding Graph() calls:

#include grapher.ahk

DetectHiddenWindows On
OnExit GuiClose

Gui Add,Progress,w402 h1 x10 y10
Gui Add,Progress,w1 h402 x10 y10
Gui Add,Progress,w402 h1 x10 y411
Gui Add,Progress,w1 h402 x411 y10
Process Exist
WinGet ScriptID,ID,ahk_pid %ErrorLevel%
Gui Show,w422 h422,Function Grapher

GraphOpt_defGraphColor := 0xFF0000  ;red
GraphCreate(ScriptID,11,11,400,400,"GraphOpt_")
return

GuiContextMenu:
InputBox,Equation,Function Grapher,Enter an equation in terms of x:
Graph(Equation)
return

GuiEscape:
GraphClear()
return

GuiClose:
GraphDestroy()
ExitApp

Right-click on it to enter a new equation to graph, and press Escape to clear it. And of course, you need grapher.ahk in the same directory (change the #include if you use a different name).

Comments, critiques, and modifications welcome.

PhiLho
  • Moderators
  • 6850 posts
  • Last active: Jan 02 2012 10:09 PM
  • Joined: 27 Dec 2005
Wow...
It even manage correctly refreshing of the canvas... And is OK with stuff like sin(x) / cos(x)!
I will take a closer look later.

Hey, isn't that you writing that AutoHotkey should be used almost exclusively for small automation programs? :-D
Posted Image vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
jonny, this is beautiful.

I never thought that I will say something like this, but life is fulll of surprises :)
Posted Image

jonny
  • Members
  • 2951 posts
  • Last active: Feb 24 2008 04:22 AM
  • Joined: 13 Nov 2004

Hey, isn't that you writing that AutoHotkey should be used almost exclusively for small automation programs?


I recall saying that AutoHotkey should be designed exclusively with small programs in mind, but I never condemned the production of large-scale projects with AutoHotkey. It's pretty fun to do stuff like this. 8)

My argument is that, while stuff like this can be done, and will probably be easier to do as AutoHotkey develops more, new features should not be made solely for advanced, lower-level projects like this one. For instance, these functions could be vastly improved with namespaces and/or structs, and it would be even better as a tightly integrated class. But that kind of stuff wouldn't benefit the three-liner text processing and window manipulation scripts that form the majority of AHK usage.

jonny, this is beautiful.

I never thoutht i will say something like this, but life is fool of surprises :)


Thank you.

ahklerner
  • Members
  • 1386 posts
  • Last active: Oct 08 2014 10:29 AM
  • Joined: 26 Jun 2006
Sweet

jonny
  • Members
  • 2951 posts
  • Last active: Feb 24 2008 04:22 AM
  • Joined: 13 Nov 2004
Here is a new version of the script that doesn't require a temporary file to do the computation. It uses Laszlo's "Monster" expression script. However, since it parses the expression each time, it calculates much slower than the temporary script with its values hardcoded into it.

;;;;;;;;;;;;;;; 
; 
; Function Grapher by jonny 
;  (with code by Laszlo)
; 
; 
;;;Functions;;; 
; 
;GraphCreate(id,x,y,w,h,pre="") 
;   Initializes the graph, sets its options, 
;   and draws it at the specified location. 
;   Returns 1 if it's successful, 0 if there's 
;   a logical error (e.g. bad option), and blank 
;   if there's a problem allocating memory. 
; 
;  id: 
;   The window ID (ahk_id) of the window to 
;   draw the graph on. 
; 
;  x: 
;   The x-coordinate to draw the graph at. 
; 
;  y: 
;   The y-coordinate to draw the graph at. 
; 
;  w: 
;   The width of the graph. 
; 
;  h: 
;   The height of the graph. 
; 
;  pre: 
;   The prefix for the global option variables, 
;   explained further below. 
;   For example, if pre = "GraphOpts_", then it 
;   will read GraphOpts_xScl for the xScl option 
; 
; 
;Graph(equation,color=defGraphColor) 
;   Computes and draws the given equation on 
;   the graph. The equation must be in terms 
;   of the variable 'x', and it can contain any 
;   standard AHK operators and math functions. 
;   Returns 1 if it's successful, and 0 if 
;   the graph doesn't exist or if there's a 
;   problem with the computation. 
; 
;  equation: 
;   The equation to use. This must be in the form 
;   of a string, NOT a bare expression; however, 
;   it will eventually be parsed, so it must be 
;   valid as an expression. 
; 
;  color: 
;   The color to draw the equation in. This must 
;   be in RGB form (0xRRGGBB), not an HTML color. 
;   If this parameter is unspecified or not a valid 
;   RGB color, the defGraphColor option will be used. 
; 
; 
;GraphClear() 
;   Clears all equations off the graph. 
; 
; 
;GraphDraw() 
;   Redraws the graph. Shouldn't be necessary to 
;   use, since GraphCreate binds this to WM_PAINT. 
; 
; 
;GraphDestroy() 
;   Frees all memory associated with the graph. 
;   You MUST call this before exiting the script, 
;   or there will be a memory leak. 
;   Note that this will not remove the graph's image 
;   from the display. The window must be redrawn 
;   to visually clear it. 
; 
; 
; 
;;;Options;;; 
; 
; To use these, set any of them as global variables 
; with a consistent prefix (required). Then pass 
; the prefix to GraphCreate as a string, via the 
; 'pre' parameter. Any options left unset will get 
; their default values. 
; 
; 
;paperColor (0xFFFFFF - white) 
;   The color of the graph's background, or the 
;   "graph paper." Must be a full RGB color. 
; 
;axisColor (0x000000 - black) 
;   The color of the x and y axes, if visible. 
;   Must be a full RGB color. 
; 
;gridColor (0xDFDFDF - light grey) 
;   The color of the grid beneath the graph. 
;   Must be a full RGB color. 
; 
;defGraphColor (0x0000FF - blue) 
;   The default color for Graph(), if the 'color' 
;   parameter isn't valid or specified. 
; 
;lineWidth (3) 
;   The width of the lines generated by Graph(). 
;   Must be greater than or equal to zero. 
; 
;xScl (1) 
;   The scale of the x-plane of the grid, in 
;   logical units. For instance, a value of 10 
;   would draw a vertical line wherever x is 
;   a multiple of 10, and a value of 0.5 would 
;   draw two vertical lines for every integral 
;   x-value. Must be greater than zero. 
; 
;yScl (1) 
;   The scale of the y-plane of the grid, in 
;   logical units. Same as above, except for 
;   the horizontal lines with y. Must be greater 
;   than zero. 
; 
;xMin (-10) 
;   The smallest x-value displayed on the graph, 
;   or the left edge of its viewable area. Must 
;   be less than xMax. 
; 
;yMin (-10) 
;   The smallest y-value displayed on the graph, 
;   or the bottom edge of its viewable area. Must 
;   be less than yMax. 
; 
;xMax (10) 
;   The largest x-value displayed on the graph, 
;   or the right edge of its viewable area. Must 
;   be greater than xMin. 
; 
;yMax (10) 
;   The largest y-value displayed on the graph, 
;   or the top edge of its viewable area. Must be 
;   greater than yMin. 
; 
; 
; 
;;;Remarks;;; 
; 
; Use this at your own risk. I've tested it a lot, 
; but there's still a chance it'll cause a serious 
; memory leak. 
; 
; Avoid naming any global variables with the prefix 
; '__graph_' while the graph is created, since these 
; functions use it to communicate. 
; 
; Graph() uses two temporary files which it creates 
; in A_Temp, so don't be alarmed if you notice that 
; your script is suddenly opening weird files. (It 
; deletes them when it's finished, so they'll only 
; consume space for a few milliseconds.) 
; 


GraphCreate(WindowID,xCoord,yCoord,Width,Height,OptPre="") 
{ 
   global 
   local paperColor,axisColor,gridColor,xScl,yScl,xMin,yMin 
         ,xMax,yMax,Pen,Brush 
    
   if __graph_Exists 
      return 0 

;options 
   ;background color (white) 
   paperColor := %OptPre%paperColor ? %OptPre%paperColor : 0xFFFFFF 

   ;color for axes (black) 
   axisColor := %OptPre%axisColor ? %OptPre%axisColor : 0x000000 

   ;grid color (grey) 
   gridColor := %OptPre%gridColor ? %OptPre%gridColor : 0xDFDFDF 

   ;default color for new equations (blue) 
   __graph_color := %OptPre%defGraphColor ? %OptPre%defGraphColor : 0x0000FF 

   ;width of equations' graphs 
   __graph_lineWidth := %OptPre%lineWidth ? %OptPre%lineWidth : 3 

   ;scale of grid for the x plane 
   xScl := %OptPre%xScl ? %OptPre%xScl : 1 

   ;scale of grid for the y plane 
   yScl := %OptPre%yScl ? %OptPre%yScl : 1 

   ;lowest x-value shown on graph 
   xMin := %OptPre%xMin ? %OptPre%xMin : -10 

   ;lowest y-value shown on graph 
   yMin := %OptPre%yMin ? %OptPre%yMin : -10 

   ;highest x-value shown on graph 
   xMax := %OptPre%xMax ? %OptPre%xMax : 10 

   ;highest y-value shown on graph 
   yMax := %OptPre%yMax ? %OptPre%yMax : 10 

   ;sanity checks 
   if (paperColor > 0xFFFFFF || paperColor < 0 
    || axisColor  > 0xFFFFFF || axisColor  < 0 
    || gridColor  > 0xFFFFFF || gridColor  < 0 
    || __graph_color > 0xFFFFFF || __graph_color < 0 
    || __graph_lineWidth < 0 
    || xScl <= 0 || yScl <= 0 
    || xMin >= xMax || yMin >= yMax) 
   { 
      __graph_color = 
      __graph_lineWidth = 
      return 0 
   } 

   __graph_X := xCoord 
   __graph_Y := yCoord 
   __graph_W := Width 
   __graph_H := Height 

   ;compute how many units on the graph each pixel 
   ;corresponds to 
   __graph_xUnit   := Width  / (xMax - xMin) 
   __graph_yUnit   := Height / (yMax - yMin) 

   ;how far, in graph units, the left 
   ;edge is from the origin 
   __graph_leftDist := xMin * __graph_xUnit 
   ;how far the top edge is from the 
   ;origin, this time in terms of y 
   __graph_topDist  := yMax * __graph_yUnit 
    
   ;Device Context for the window to be drawn to 
   __graph_WindowDC := DllCall("GetDC", UInt,WindowID) 
   if not __graph_WindowDC 
      return 
    
   ;first memory DC, containing the "graph paper," 
   ;the background of the graph 
   __graph_PaperDC := DllCall("CreateCompatibleDC", UInt,WindowDC) 
   if not __graph_PaperDC 
      return 
   ;create a bitmap on the DC 
   __graph_PaperDC_BM := DllCall("CreateCompatibleBitmap" 
      , UInt,__graph_WindowDC, UInt,Width, UInt,Height) 
   DllCall("SelectObject", UInt,__graph_PaperDC 
      , UInt,__graph_PaperDC_BM) 

   ;second Memory DC, containing the finished product 
   ;of the paper with the graphed equations on it 
   __graph_MemoryDC := DllCall("CreateCompatibleDC", UInt,WindowDC) 
   if not __graph_MemoryDC 
      return 
   ;create a bitmap on the DC 
   __graph_MemoryDC_BM := DllCall("CreateCompatibleBitmap" 
      , UInt,__graph_WindowDC, UInt,Width, UInt,Height) 
   DllCall("SelectObject", UInt,__graph_MemoryDC 
      , UInt,__graph_MemoryDC_BM) 

;set up the graph paper 
   ;first the background and border 
   Pen := DllCall("CreatePen", UInt,0, UInt,0, UInt,paperColor) 
   DllCall("SelectObject", UInt,__graph_PaperDC, UInt,Pen) 
   Brush := DllCall("CreateSolidBrush", UInt,paperColor) 
   DllCall("SelectObject", UInt,__graph_PaperDC, UInt,Brush) 
   DllCall("Rectangle", UInt,__graph_PaperDC, UInt,0, UInt,0 
      , UInt,Width, UInt,Height) 
   DllCall("DeleteObject", UInt,Pen) 
   DllCall("DeleteObject", UInt,Brush) 

   ;now the grid 
   Pen := DllCall("CreatePen", UInt,0, UInt,0, UInt,gridColor) 
   DllCall("SelectObject", UInt,__graph_PaperDC, UInt,Pen) 
   ;vertical lines (x-plane) 
   Loop 
   { 
      if (A_Index >= ( (xMax - xMin) / xScl )) 
         break 
      DllCall("MoveToEx", UInt,__graph_PaperDC 
         , UInt,Round(A_Index*__graph_xUnit*xScl), UInt,0, UInt,0) 
      DllCall("LineTo", UInt,__graph_PaperDC 
         , UInt,Round(A_Index*__graph_xUnit*xScl), UInt,Height) 
   } 
   ;horizontal lines (y-plane) 
   Loop 
   { 
      if (A_Index >= ( (yMax - yMin) / yScl )) 
         break 
      DllCall("MoveToEx", UInt,__graph_PaperDC 
         , UInt,0, UInt,Round(A_Index*__graph_yUnit*yScl), UInt,0) 
      DllCall("LineTo", UInt,__graph_PaperDC 
         , UInt,Width, UInt,Round(A_Index*__graph_yUnit*yScl)) 
   } 
   DllCall("DeleteObject", UInt,Pen)    

   ;axes 
   Pen := DllCall("CreatePen", UInt,0, UInt,0, UInt,axisColor) 
   DllCall("SelectObject", UInt,__graph_PaperDC, UInt,Pen) 
   if (xMin < 0 and xMax > 0) 
   { 
      DllCall("MoveToEx", UInt,__graph_PaperDC 
         , UInt,Round((-xMin)*__graph_xUnit), UInt,0, UInt,0) 
      DllCall("LineTo", UInt,__graph_PaperDC 
         , UInt,Round((-xMin)*__graph_xUnit), UInt,Height) 
   } 
   if (yMin < 0 and yMax > 0) 
   { 
      DllCall("MoveToEx", UInt,__graph_PaperDC 
         , UInt,0, UInt,Round(yMax*__graph_yUnit), UInt,0) 
      DllCall("LineTo", UInt,__graph_PaperDC 
         , UInt,Width, UInt,Round(yMax*__graph_yUnit)) 
   } 
   DllCall("DeleteObject", UInt,Pen) 
    

   __graph_Exists := true 
   GraphClear() 
   ;WM_PAINT: 0x0F 
   OnMessage(0x0F,"GraphDraw") 
   return 1 
} 

Graph(Equation,Color = -1) 
{ 
   global 
   local Pen,FirstVal,GraphSpec,R,G,B 

   if (!__graph_Exists or !A_AhkPath) 
      return 0 

   if (Color < 0 or Color > 0xFFFFFF) 
      Color := __graph_color 

   ;CreatePen expects a BGR-formatted COLORREF 
   R := Color & 0x0000FF 
   G := Color & 0x00FF00 
   B := Color & 0xFF0000 
   R <<= 16 
   B >>= 16 
   Color := R | G | B 


   ;px/py: Positional coordinates used to 
   ;       place the graph 
   ; 
   ;x/y: Actual coordinates that the function 
   ;       is computed in 
   ; 
   ;Equation must be in terms of 'x' 
   Loop %__graph_W% 
   { 
      px := A_Index 
      x := (px + __graph_leftDist) / __graph_xUnit
     
      y := Eval("x:=" . x . "; " . Equation) * __graph_yUnit 
      py := Round(__graph_topDist - y) 

      GraphSpec .= py . ";" 
   } 

   Pen := DllCall("CreatePen", UInt,0, UInt,__graph_lineWidth, UInt,Color) 
   DllCall("SelectObject", UInt,__graph_MemoryDC, UInt,Pen) 

   StringTrimRight,GraphSpec,GraphSpec,1 
   FirstVal := InStr(GraphSpec,";") 
   DllCall("MoveToEx", UInt,__graph_MemoryDC, UInt,1, UInt,SubStr(GraphSpec,1,FirstVal-1), UInt,0) 
   StringTrimLeft,GraphSpec,GraphSpec,FirstVal 
   Loop,Parse,GraphSpec,; 
      DllCall("LineTo", UInt,__graph_MemoryDC, UInt,A_Index + 1, UInt,A_LoopField) 

   DllCall("DeleteObject", UInt,Pen) 

   GraphDraw() 
   return 1 
} 

GraphClear() 
{ 
   global 
   if not __graph_Exists 
      return 
   DllCall("BitBlt", UInt,__graph_MemoryDC, UInt,0, UInt,0 
      , UInt,__graph_W, UInt,__graph_H, UInt,__graph_PaperDC 
      , UInt,0, UInt,0, UInt,0x00CC0020) 
   GraphDraw() 
} 

GraphDraw() 
{ 
   global 
   if not __graph_Exists 
      return 
   DllCall("BitBlt", UInt,__graph_WindowDC, UInt,__graph_X 
      , UInt,__graph_Y, UInt,__graph_W, UInt,__graph_H 
      , UInt,__graph_MemoryDC, UInt,0, UInt,0, UInt,0x00CC0020) 
} 

GraphDestroy() 
{ 
   global 

   ;WM_PAINT: 0x0F 
   OnMessage(0x0F,"") 
    
   DllCall("DeleteObject", UInt,__graph_PaperDC) 
   DllCall("DeleteObject", UInt,__graph_PaperDC_BM) 
   DllCall("DeleteObject", UInt,__graph_MemoryDC) 
   DllCall("DeleteObject", UInt,__graph_MemoryDC_BM) 
   DllCall("ReleaseDC", UInt,0, UInt,__graph_WindowDC) 

   __graph_PaperDC = 
   __graph_PaperDC_BM = 
   __graph_MemoryDC = 
   __graph_MemoryDC_BM = 
   __graph_WindowDC = 
   __graph_X = 
   __graph_Y = 
   __graph_W = 
   __graph_H = 
   __graph_color = 
   __graph_lineWidth = 
   __graph_xUnit = 
   __graph_yUnit = 
   __graph_leftDist = 
   __graph_topDist = 
   __graph_Exists = 
}



;; Taken from Laszlo's "Monster" expression evaluation script (version 20070301):
;; http://www.autohotkey.com/forum/viewtopic.php?t=17058

Eval(x) {                              ; PRE/POST PROCESSING (Global Dynamic vars, Array y: y1, y2, y3) 
   Local FORM, i, z 
   SetFormat Integer, D                ; decimal intermediate results! 
   RegExMatch(x, "\$(b|h|x|\d*)", y) 
   FORM := y1                          ; HeX, Bin, .{digits} output format 
   SetFormat FLOAT, % y1 >= 0 ? "0." . y1 : 0.6 ; Default = 6 decimal 
   StringReplace x, x, %y%             ; remove ${num} 
   x := RegExReplace(x,"\s*")          ; remove whitespace 
   If RegExMatch(x, "(.*);(.*)", u) { 
      z := u2                          ; workaround local-global mixup with arrays 
      Eval(u1) 
      Return Eval(z) 
   } 

   StringGetPos i, x, :=               ; execute leftmost ":=" operator 
   If (i >= 0) { 
      z := "x" . SubStr(x,1,i)         ; user vars start with x to avoid name conflicts 
      Return %z% := Eval(SubStr(x,3+i)) 
   } 

   StringReplace x, x,`%, \, All       ; % -> \ for MOD 
   StringReplace x, x, **, @, All      ; ** -> @ for easier process 
   Loop { 
      If !RegExMatch(x, "i)(.*)(0x[a-f\d]*)(.*)", y) 
         Break 
      x := y1 . y2+0 . y3              ; convert hex numbers to decimal 
   } 
   Loop { 
      If !RegExMatch(x, "(.*)'([01]*)(.*)", y) 
         Break 
      x := y1 . FromBin(y2) . y3       ; convert binary numbers to decimal: sign = first bit 
   } 

   x := RegExReplace(x,"([a-z_A-Z]\w*)([^\w\(\]]|$)","%x$1%$2") ; var -> %var%; func(.., [op] remains 
   Transform x, Deref, %x%             ; dereference all %var% 

   StringReplace x, x, -, #, All       ; # = subtraction, different from sign 
   x := RegExReplace(x, "(^|\(|\])\+", "$1") ; (+x -> (x, ]+x -> ]x 

   Loop {                              ; find innermost (..) 
      If !RegExMatch(x, "(.*)\(([^\(\)]*)\)(.*)", y) 
         Break 
      x := y1 . Eval@(y2) . y3         ; replace "(x)" with value of x 
   } 
   If FORM is Digit                    ; return result: no more (..) 
      Return Eval@(x) 
   If FORM = b                         ; binary 
      Return ToBin(Eval@(x)) 
   x := Eval@(x)                       ; Hex 
   SetFormat Integer, Hex 
   Return x+0 
} 

Eval@(x) {                             ; EVALUATE PRE-PROCESSED EXPRESSIONS 
   IfEqual x,, Return 0                ; empty = 0 
   StringGetPos i, x, ||, R            ; execute rightmost || operator 
   IfGreaterOrEqual i,0, Return Eval@(SubStr(x,1,i)) || Eval@(SubStr(x,3+i)) 
   StringGetPos i, x, &&, R            ; execute rightmost && operator 
   IfGreaterOrEqual i,0, Return Eval@(SubStr(x,1,i)) && Eval@(SubStr(x,3+i)) 
                                       ; execute rightmost =, <> operator 
   RegExMatch(x, "(.*)([^\<\>])(\<\>|=)(.*)", y) 
   IfEqual y3,=,  Return Eval@(y1 . y2) =  Eval@(y4) 
   IfEqual y3,<>, Return Eval@(y1 . y2) <> Eval@(y4) 
                                       ; execute rightmost  <,>,<=,>= operator 
   RegExMatch(x, "(.*)([^\<\>])(\<=?|\>=?)([^\<\>])(.*)", y) 
   IfEqual y3,<,  Return Eval@(y1 . y2) <  Eval@(y4 . y5) 
   IfEqual y3,>,  Return Eval@(y1 . y2) >  Eval@(y4 . y5) 
   IfEqual y3,<=, Return Eval@(y1 . y2) <= Eval@(y4 . y5) 
   IfEqual y3,>=, Return Eval@(y1 . y2) >= Eval@(y4 . y5) 
                                       ; execute rightmost user operator (low precedence) 
   RegExMatch(x, "i)(.*)(\[gcd\]|\[min\]|\[max\]|\[choose\])(.*)", y) 
   IfEqual y2,[Gcd],   Return GCD(   Eval@(y1),Eval@(y3)) 
   IfEqual y2,[Min],   Return Min(   Eval@(y1),Eval@(y3)) 
   IfEqual y2,[Max],   Return Max(   Eval@(y1),Eval@(y3)) 
   IfEqual y2,[choose],Return Choose(Eval@(y1),Eval@(y3)) 

   StringGetPos i, x, |, R             ; execute rightmost | operator 
   IfGreaterOrEqual i,0, Return Eval@(SubStr(x,1,i)) | Eval@(SubStr(x,2+i)) 
   StringGetPos i, x, ^, R             ; execute rightmost ^ operator 
   IfGreaterOrEqual i,0, Return Eval@(SubStr(x,1,i)) ^ Eval@(SubStr(x,2+i)) 
   StringGetPos i, x, &, R             ; execute rightmost & operator 
   IfGreaterOrEqual i,0, Return Eval@(SubStr(x,1,i)) & Eval@(SubStr(x,2+i)) 
                                        ; execute rightmost <<, >> operator 
   RegExMatch(x, "(.*)(\<\<|\>\>)(.*)", y) 
   IfEqual y2,<<, Return Eval@(y1) << Eval@(y3) 
   IfEqual y2,>>, Return Eval@(y1) >> Eval@(y3) 
                                       ; execute rightmost +- (not unary) operator 
   RegExMatch(x, "(.*[^\(\@\*\/\\\~\+\#])(\+|\#)(.*)", y) ; lower precedence ops are already handled 
   IfEqual y2,+,  Return Eval@(y1) + Eval@(y3) 
   IfEqual y2,#,  Return Eval@(y1) - Eval@(y3) 
                                       ; execute rightmost */% operator 
   RegExMatch(x, "(.*)(\*|\/|\\)(.*)", y) 
   IfEqual y2,*,  Return Eval@(y1) * Eval@(y3) 
   IfEqual y2,/,  Return Eval@(y1) / Eval@(y3) 
   IfEqual y2,\,  Return Mod(Eval@(y1),Eval@(y3)) 
                                       ; execute rightmost power 
   StringGetPos i, x, @, R 
   IfGreaterOrEqual i,0, Return Eval@(SubStr(x,1,i)) ** Eval@(SubStr(x,2+i)) 
                                       ; execute rightmost function 
   If !RegExMatch(x,"i)(.*)(\+|\#|\~|Abs|Ceil|Exp|Floor|Log|Ln|Round|Sqrt|Sin|Cos|Tan|ASin|ACos|ATan|Sgn|Fib|fac)([-\d\.]*)", y) 
      Return x                         ; no more function 
   IfEqual y2,+,Return Eval@(y1 .  y3) ; unary + and... 
   IfEqual y2,#,Return Eval@(y1 . -y3) ; unary - and... 
   IfEqual y2,~,Return Eval@(y1 . ~y3) ; unary ~ behaves like a function 
   GoTo %y2%                           ; functions checked last: y3 is number 
Abs: 
   Return Eval@(y1 . Abs(y3)) 
Ceil: 
   Return Eval@(y1 . Ceil(y3)) 
Exp: 
   Return Eval@(y1 . Exp(y3)) 
Floor: 
   Return Eval@(y1 . Floor(y3)) 
Log: 
   Return Eval@(y1 . Log(y3)) 
Ln: 
   Return Eval@(y1 . Ln(y3)) 
Round: 
   Return Eval@(y1 . Round(y3)) 
Sqrt: 
   Return Eval@(y1 . Sqrt(y3)) 
Sin: 
   Return Eval@(y1 . Sin(y3)) 
Cos: 
   Return Eval@(y1 . Cos(y3)) 
Tan: 
   Return Eval@(y1 . Tan(y3)) 
ASin: 
   Return Eval@(y1 . ASin(y3)) 
ACos: 
   Return Eval@(y1 . ACos(y3)) 
ATan: 
   Return Eval@(y1 . ATan(y3)) 
Sgn: 
   Return Eval@(y1 . Sgn(y3)) 
Fib: 
   Return Eval@(y1 . Fib(y3)) 
Fac: 
   Return Eval@(y1 . Fac(y3)) 
} 

ToBin(n) {      ; Binary representation of n. 1st bit is SIGN: -8 -> 1000, -1 -> 11, 0 -> 0, 8 -> 01000 
   m := -(n<0) 
   Loop  { 
      b := n&1 . b 
      If (m = n >>= 1) 
         Return b = "0" ? b : -m . b 
   } 
} 
FromBin(bits) { ; Number converted from the binary "bits" string, 1st bit is SIGN 
   n = 0 
   Loop Parse, bits 
      n += n + A_LoopField 
   Return n - (SubStr(bits,1,1)<<StrLen(bits)) 
} 

MIN(a,b) {      ; The less of a, b 
   Return a<b ? a : b 
} 
MAX(a,b) {      ; The greater of a, b 
   Return a>b ? a : b 
} 
GCD(a,b) {      ; Euclidean GCD 
   Return b=0 ? Abs(a) : GCD(b, mod(a,b)) 
} 
Choose(n,k) {   ; Binomial coefficient 
   p := 1, i := 0, k := k < n-k ? k : n-k 
   Loop %k% 
      p *= (n-i)/(k-i), i+=1 
   Return Round(p) 
} 

Sgn(x) {        ; Sign of x 
   Return (x>0)-(x<0) 
} 
Fib(n) {        ; n-th Fibonacci number (iterative to avoid globals) 
   a := 0, b := 1 
   Loop % n-1 
      c := b, b += a, a := c 
   Return b 
} 
fac(n) {        ; n! 
   Return n<2 ? 1 : n*fac(n-1) 
}


Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
Beautiful (as majkinetor said)!

If you want to speed up expression evaluations, you can remove all the unneeded Monster options, but on my PC (2GHz Centrino) it is fast enough with Monster 0.4.

The ability to paste the graph in a Word document would be really useful. Would it be hard adding a "Copy to ClipBoard" feature to the script? Or a "Save As…" button, where we can choose the file formats supported by GDI?

jonny
  • Members
  • 2951 posts
  • Last active: Feb 24 2008 04:22 AM
  • Joined: 13 Nov 2004
Thanks for the pointers on speeding it up. I'll see if I can trim it down to only those things I'd need to do ordinary functions.

As for saving to images, I'll look into that too for the full GUI that I'm planning. The script I've already posted that used the functions was only intended as a proof-of-concept, not an end product, but I'm planning a much more full-featured application that includes being able to reset the options on the fly and the ability to manage multiple functions.

Elevator_Hazard
  • Members
  • 297 posts
  • Last active: Feb 07 2011 12:10 AM
  • Joined: 28 Oct 2006
I think that's a cosine graph, and the amplitude is too high.
Changed siggy at request of ahklerner :D

polyethene
  • Members
  • 5519 posts
  • Last active: May 17 2015 06:39 AM
  • Joined: 26 Oct 2012

I think that's a cosine graph

edit: nope ur right. The scale is quite odd though.

Great work jonny... now get started on a 3d molecule viewer showing bonds and polarity :lol:

autohotkey.com/net Site Manager

 

Contact me by email (polyethene at autohotkey.net) or message tidbit


jonny
  • Members
  • 2951 posts
  • Last active: Feb 24 2008 04:22 AM
  • Joined: 13 Nov 2004

I think that's a cosine graph, and the amplitude is too high.


Good eye. It's actually negative sine, and it's multiplied by constants on both the x and y axes. That, and especially the arctan, I just went crazy with to make them look nicer.

Elevator_Hazard
  • Members
  • 297 posts
  • Last active: Feb 07 2011 12:10 AM
  • Joined: 28 Oct 2006
I really don't know what that means at all, a friend told me to post it. I haven't even begun learning this in school... But I will soon if my crappy math teacher learns to control the people in the class... (ew 8th grade)
Changed siggy at request of ahklerner :D

Icarus
  • Members
  • 851 posts
  • Last active: Jan 02 2012 11:17 AM
  • Joined: 24 Nov 2005
This is nice.

How complicated is it to make it so instead of getting a function as an input, it gets an array of x/y values?

i am looking for a way to create line charts, based on predefined input.

;D

tonne
  • Members
  • 1654 posts
  • Last active: May 06 2014 06:22 PM
  • Joined: 06 Jun 2006
Add this to grapher.ahk (note the coordinates are not scaled):
GraphLine(xname, yname, size, Color = -1)
{
   global
   local EquDC,EquDC_BM,Pen,FirstVal,GraphSpec,R,G,B,Xxx,Yyy

   if (!__graph_Exists or !A_AhkPath)
      return 0

   if (Color < 0 or Color > 0xFFFFFF)
      Color := __graph_color

   ;CreatePen expects a BGR-formatted COLORREF
   R := Color & 0x0000FF
   G := Color & 0x00FF00
   B := Color & 0xFF0000
   R <<= 16
   B >>= 16
   Color := R | G | B

   Pen := DllCall("CreatePen", UInt,0, UInt,__graph_lineWidth, UInt,Color)
   DllCall("SelectObject", UInt,__graph_MemoryDC, UInt,Pen)
   
   loop %size%
   {
     xentry := %xname%%a_index%
     yentry := %yname%%a_index%
     Xxx := xentry
     Yyy := yentry
     if a_index = 1
       DllCall("MoveToEx", UInt,__graph_MemoryDC, UInt, Xxx, UInt, Yyy, UInt, 0)
     else
       DllCall("LineTo", UInt,__graph_MemoryDC, UInt, Xxx, UInt, Yyy)
   }
   
   DllCall("DeleteObject", UInt,Pen)

   GraphDraw()
   return 1
}

The original example with a call to the new function:
#include grapher.ahk

DetectHiddenWindows On
OnExit GuiClose

Gui Add,Progress,w402 h1 x10 y10
Gui Add,Progress,w1 h402 x10 y10
Gui Add,Progress,w402 h1 x10 y411
Gui Add,Progress,w1 h402 x411 y10
Process Exist
WinGet ScriptID,ID,ahk_pid %ErrorLevel%
Gui Show,w422 h422,Function Grapher

GraphOpt_defGraphColor := 0xFF0000  ;red
GraphCreate(ScriptID,11,11,400,400,"GraphOpt_")

[color=red]x1 := 1
x2 := 100
x3 := 200
x4 := 300
x5 := 400

y1 := 1
y2 := 100
y3 := 400
y4 := 200
y5 := 300
GraphLine("x","y",5)[/color]

return

GuiContextMenu:
InputBox,Equation,Function Grapher,Enter an equation in terms of x:
Graph(Equation)

return

GuiEscape:
GraphClear()
return

GuiClose:
GraphDestroy()
ExitApp


Icarus
  • Members
  • 851 posts
  • Last active: Jan 02 2012 11:17 AM
  • Joined: 24 Nov 2005
tonne,

you are the king of all kings.
i was sitting here frustrated to the point where i started reading the gnuplot documentation.... these are two hours i am never getting back... horrible experience.

thanks for the super quick reply, much appreciated, going to play with it.