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.
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