Disable Graph Updates with InteractionI have a data table with columns ox, oy, dx, and dy. For demonstration purposes, you can assume all columns are random with formula: Random Normal(0, 10). The real problem is a network with a list of coordinates.
I would like to draw lines between (ox, oy) and (dx, dy) and I can do this with either Graph Builder or Graph Box (example below). However, with every interaction, JMP redraws the lines which makes my visualization very slow (I have >10 000 rows in the data table). I tested this by adding a small random part to the origin and destination coordinates in the graph script and as soon as there's any interaction (e.g., using the Grabber tool and dragging the canvas, adjusting axes, resizing the graph, resizing the window), the lines do change. Is there a way to stop JMP updating the graph and rerunning the scripts?
I couldn't find a way in Graph Builder (I'd prefer to use this platform) or Graph Box. I found the
<< Graph Updating( Per Mouse Up );
message but it only has two options; there's no "don't update" option as far as I can tell. Also, I think that message doesn't work with Graph Box anyway.
Here's a minimal Graph Box example that can draw lines but the lines get updated with every interaction:
New Window( "Example",
Graph Box(
Frame Size( 300, 300 ),
Pen Color( "Blue" );
o_x = :ox << Get Values();
o_y = :oy << Get Values();
d_x = :dx << Get Values();
d_y = :dy << Get Values();
For( i=1, i<=N Items(o_x), i++,
origin = Eval List({o_x[i]*Random Normal( 1, 0.1 ), o_y[i]*Random Normal( 1, 0.1 )});
destination = Eval List({d_x[i]*Random Normal( 1, 0.1 ), d_y[i]*Random Normal( 1, 0.1 )});
Line(origin, destination);
);
);
);Reminder, I only added the Random Normal in that Graph Box script just to see if the lines are being recalculated. The real problem has fixed coordinates.
Bonus question: is there a way to add lines after the graph box has been constructed? I couldn't find it in the examples. I theorized that maybe they won't be updated with every mouse interaction but couldn't test it.
GraphicsScriptingRe: Disable Graph Updates with InteractionI think that the problem is that the frame box will automatically update whenever there is a change, so it is best to make all the changes before rendering. Also, you can vectorize the operations for speed, too, instead of explicitly iterating with the For() function. Graphic segments offer some advantages, too, but they are poorly documented at present.
See this approach:
Names Default to Here( 1 );
// origin
o_x = :ox << Get As Matrix;
o_y = :oy << Get As Matrix;
// destination
d_x = :dx << Get As Matrix;
d_y = :dy << Get As Matrix;
n = N Items( o_x );
// vectorize for line segments
seg = (o_x :*</img> J( n, 1, Random Normal( 1, 0.1 ))) || (o_y f:* J( n, 1, Random Normal( 1, 0.1 ))) ||
(d_x :*</img> J( n, 1, Random Normal( 1, 0.1 ))) || (d_y f:* J( n, 1, Random Normal( 1, 0.1 )));
// plot segments
New Window( "Example",
gb = Graph Box(
Frame Size( 300, 300 ),
Pen Color( "Blue" );
Line Seg( seg );
)
);
// later, update seg, then send gb << Reshow message to graph box
(I do not have your data table so I could not test it, but it should still illustrate the approach.)
Re: Disable Graph Updates with InteractionIMHO JMP really really _VERY_ badly needs to update this functionality. I've run into this issue multiple times and there is, quite simply, no valid work-around. JMP should only re-run the graphics script when something changes (such as the size of the graph), not simply when scrolling / changing the size of the window.
That being said, I've found that the fastest method for doing something like this is as shown below. I create an SVG path (in my experience this is hands-down the fastest way to render complex paths in JMP) and have a sentinel to determine whether or not to reconstruct the path. I've included a button to force the reconstruction of the path simply as an example.
Hope this helps, but even better would be the JMP devs providing a system that behaves as all other display manager systems (including multi-threaded, signal/slots, callbacks, etc...).
I've also toyed around with using this method to grab an image of the desired render, check the size of the graphics box, and if the size hasn't changed, use the saved image as the thing to show. This is what JMP should be doing and never ever should have been setup to aggressively execute the graphics script at every possible opportunity. However, I've not had much luck with this method as JMP doesn't provide the necessary tools to make this work properly
self = New Namespace();
self:table = Current Data Table();
self:redraw = 1;
self:path = "";
self:build path = Function( {},
{Default Local},
self:path = "";
For Each Row( self:table,
self:path ||= Eval Insert( "\[M^:ox * Random Normal( 1, 0.1 )^,^oy * Random Normal( 1, 0.1)^ L^dx * Random Normal( 1, 0.1 )^,^:dy * Random Normal( 1, 0.1 )^]\" )
);
);
Eval( Eval Expr(
New Window( "Example",
<<ON close=""></ON>