How to build an interactive plotter with a polygon

Start to build our stack

1) Create a table named "MyTable" and fill it with some numerical data (only positive values for our lesson.)

2) Create a button named "Draw".

3) Create a rectangle named "destRect", and put it where you want your graph to be drawn.

4) Create a polygon and keep its original name "Polygon". You can draw a few points, but don't worry about the size and the position of it.

This Polygon will be our graph result afterwards and will be automatically redrawn by our Card Script.

If you have questions at this point, you might want to read this lesson first: "How to make a simple line graph".

Look in our Project Browser

We can see our 4 cards objects with their respectives names, and we have only 2 scripts. One script in our "Draw" button, and our main script in the card. We will explore them now.

Script our "Draw" button

We are calling our card handlerDrawGraph, passing 3 parameters, well, self-explained.

Sleeves up ! our plotter script

(1) We split our original list of lines of points into 2 lists; one for the X, the second for the Y axis, respectively listTableX and listTableY.

(2) We are calculating the rectangle including all our original points.

(3) We have the rectangle where all the final points will fit into.

(4) We set the ratios for our X and Y values.

(5) For each item (actually a point) in our list we transform the original point to a new value. Points in a polygon are integers, that's why we use the round() function. The last line of the repeat will build our new list of points in a format understandable by our polygon (each point is on a separate line)

(6) We update our polygon with our calculated points.... That's it!

If you have questions at this point about the details of calculation, you might want to read this lesson first: "How to make a simple line graph".

You can copy and paste the entire script here:

on Drawgraph tableName, destRectName, graphicId
   -- get the values from our table
   -- split them into 2 lists: X and Y values
   repeat for each line thisLine in the text of field tableName
      put word 1 of thisLine & comma after listTableX
      put word 2 of thisLine & comma after listTableY
   end repeat
   delete last char of lisTableX -- get rid of last comma
   delete last char of lisTableY -- get rid of last comma
   
   -- these next 4 values give us the rectangle aread of our original values
   put min(listTableX) into minTableX
   put 0 into minTableY
   put max(listTableX) into maxTableX
   put max(listTableY) into maxTableY
   
   -- the rect of the destination area
   put the rect of control destRectName into destRect
   
   --ratios
   put (item 3 of destRect - item 1 of destRect) / (maxTableX - minTableX) into deltaX
   put (item 4 of destRect - item 2 of destRect) / (maxTableY - minTableY) into deltaY
   
   --shifts
   put item 1 of destRect into shiftX
   put item 4 of destRect into shiftY
   
   --  Now we have to do a transformation to every point to fit in our destRect
   
   --build a new list to display our polygon
   put empty into listP
   put empty into listP2
   put the number of items in listTableX into Nitems
   repeat with i=1 to Nitems
      put round(deltaX * (item i of listTableX - minTableX) + shiftX) into x
      put round(-deltaY * (item i of listTableY - minTableY) + shiftY) into Y
      -- ste our list of points
      put x & comma & y & cr after listP
   end repeat   
   -- update our polygon
   set the points of graphic id graphicId to listP
end Drawgraph

Make the plotter real...

Hmmm, it works, but I don't like these black lines.

Ok, we can change this behavior easily. See next section...

Make the plotter real. Second version

Above, we see the last lines of our card script, with 2 little changes from the previous script.

(1) We add a cr (return) character after each point. Doing so, the polygon sees all our points as split, and it will not draw the lines any more. Easy, no?

(2) We have to suppress the last cr of our list ( if not, we will have an extra point with value 0,0 )

And then....

Our new plotter.

Now we would like to add some extra information as a line for the X axis, another one for the Y axis, and maybe 4 fields in each corner of our plotter (the blue rectangle) filled with the 4 values we calculated at the beginning of our script.

But in this case we are not really using the best of LiveCode.

Why not do a minimalist interaction with our plotter?

For instance, bringing the cursor close to a red point, will highlight the original corresponding value, which means the corresponding line in our Table.

For this , we add 2 handlers in our card script...

Add handlers for user interaction

The script displayed above completes our script. See the section "Sleeves up !.." for the first part.

(1) We had a list variable listP2. It will contains our list of points. Almost the same as listP, except for the extra cr after each point.

(2) We fill our list for each iteration of the repeat loop.

(3) We need to declare listP2 as local, so to be shared between handlers. ( Please, put this line on top of the script )

(4) We calculate all the distances from our cursor position and each point. It returns the index of the closest point or 0 if the distance is more than minDistance.

(5) For each move of our cursor, we pass here, call TheClosestPoint() function and highlight the corresponding line. Highlighting a field with empty or 0 will reset the previous highlighted line.

 

local listP2 -- put it on top of this script
on Drawgraph tableName, destRectName, graphicId
   -- get the values from our table
   -- split them into 2 lists: X and Y values
   repeat for each line thisLine in the text of field tableName
      put word 1 of thisLine & comma after listTableX
      put word 2 of thisLine & comma after listTableY
   end repeat
   delete last char of listTableX -- get rid of last comma
   delete last char of listTableY -- get rid of last comma
   
   -- these next 4 values give us the rectangle aread of our original values
   put min(listTableX) into minTableX
   put 0 into minTableY
   put max(listTableX) into maxTableX
   put max(listTableY) into maxTableY
   
   -- the rect of the destination area
   put the rect of control destRectName into destRect
   
   --ratios
   put (item 3 of destRect - item 1 of destRect) / (maxTableX - minTableX) into deltaX
   put (item 4 of destRect - item 2 of destRect) / (maxTableY - minTableY) into deltaY
   
   --shifts
   put item 1 of destRect into shiftX
   put item 4 of destRect into shiftY
   
   --  Now we have to do a transformation to every point to fit in our destRect
   
   --build a new list to display our polygon
   put empty into listP
   put empty into listP2
   put the number of items in listTableX into Nitems
   repeat with i=1 to Nitems
      put round(deltaX * (item i of listTableX - minTableX) + shiftX) into x
      put round(-deltaY * (item i of listTableY - minTableY) + shiftY) into Y
      -- set our list of points
      put x & comma & y & cr &cr after listP
      put x & comma & y & cr after listP2
   end repeat      
   delete last char of listP 
   -- update our polygon
   set the points of graphic id graphicId to listP
end Drawgraph

function TheClosestPoint x, y
   put the number of lines of listP2 into Npoints
   put 1600 into minDistance -- 40 pixels threshold
   put 0 into closestPoint
   repeat with i=1 to Npoints
      put item 1 of line i of listP2 into x1
      put item 2 of line i of listP2 into y1
      get (x1 - x)^2 + (y1 - y)^2
      if it < minDistance then
         put it into minDistance
         put i into closestPoint
      end if
   end repeat
   return closestPoint
end TheClosestPoint

on mouseMove
   if the mouseLoc is within the rect of graphic "destRect" then
      get TheClosestPoint(the mouseH, the mouseV)
      set the hilitedLine of field "MyTable" to it
   else
      set the hilitedline of field "MyTable" to empty
   end if
end mouseMove

Final screen

Our cursor is positioned around the fifth point, and the fifth line is highlighted.

How do we make our spots square and red

Select our Polygon, open the Property Inspector.

(1) Choose the Basic tab.

(2) Select the Draw shape at vertices option.

(3) Choose the size of the line.

(4) Draw your marker with this list of points. In our example, we have drawn a square of 2 pixels

For setting the red color, in (1) Select "Colors" and choose the color of the Marker Border Fill.

2 Comments

John Tripp

why does the programme not compile?
repeat for each line thisLine in the text of field tableName
put word 1 of thisLine & comma after listTableX
put word 2 of thisLine & comma after listTableY
end repeat
the program says chink: can't create a variable with that name (explicitVariables?() near listTableX, char 38 for line
put word 1 of thisLine & comma after listTableX
it appears to be an exact copy of the code in the help page but this error is poping up more and more often and I cannot find any reference to what it means or how to adjust - why d you have code in the help file that does not work?

Hanson Schmidt-Cornelius

Hi John,

the reason you are getting this is because you probably have variable checking switched on and you are not declaring the variables.

Variable checking is a good thing, as it encourages good development practices. You can switch it off by clicking the script editor and then selecting: "Edit -> Variable Checking."

If you want to keep this feature on (recommended), then add: "local listTableX, listTableY" before you use these variables.

Kind Regards,

Hanson

Add your comment

E-Mail me when someone replies to this comment