cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Choose Language Hide Translation Bar
xxvvcczz
Level III

Is there a way to make the rowstate handler less laggy?

Is it possible to make the rowstate handler only fire on mouse up or after a selection event is completed? 

 

The realtime event causes drag select from my graph to lag and makes the user experience unpleasant.

 

I've gone so far  as to completely rewrite a selection event in the mousetrap thing but I'm having trouble applying it to histograms and I don't even love how it's performing either.

 

It would meet my needs if I could use the selection box the "Arrow(A)" tool at the same time as the mousetrap function so I could simply pick up my selected rows at the end of the moustrap event instead of firing off a million events while dragging the mouse along.

 

Stuff I don't like:
The longer you mouse down move the mouse around while selecting, more and more useless graphics scripts pile into the graph.

I'd like to just have one and only one. I added a loop at the end to kill them all out of the graph which is why they appear to "fade away".
I could just leave them there but they add visual noise to the graph and I don't know what happens when you get too many of them.

 

Edit: when you get too many of them they start to lag. It might be faster to destroy the graph and rebuild it than for looping to remove the left over graphics scripts. Edit 2: It's way faster to destroy the graph and recreate it but then the zoom gets reset, so I'll have to capture more about the state of the graph so I can rebuild it to hide the refresh from the user.

I got the Shift/control click stuff to work it just feels too hacky for production. Especially the control click it has this long lag time after you mouseup and the selection box chases the mouse even when you've already released the button, I think jmp is handling a bunch of stale drag events in the meantime before it stops moving.

 

Or just discard this whole adventure and find a way to have a row state handler that fires on mouse up (that would be ideal).

 

Examples I borrowed code from:
http://www.pega-analytics.co.uk/blog/segmented-regression/

https://community.jmp.com/t5/Discussions/Quick-way-to-compare-two-lists-and-identify-the-uncommon/td...

 

 

Names Default To Here(1);

dt = open("$sample_data\Iris.jmp");
MY_GRAPH_BUILDER = Graph Builder(
	Size( 531, 456 ),
	Show Control Panel( 0 ),
	Variables( X( :Sepal length ), Y( :Sepal width ) ),
	Elements( Points( X, Y, Legend( 3 ) ) ),
		SendToReport(	
		Dispatch({},"Graph Builder",
			FrameBox,
			{Add Graphics Script(MouseTrap( MouseDown(x,y), MouseUp(x,y)))}
			),
			),
);





//MOUSE STUFF
get_box_dims = Function({firstX,lastX,firstY,lastY},
show("get_box_dims");
//show(firstX,lastX,firstY,lastY,modifier_key);

	If (lastX>firstX,
	max_x = lastX; min_x =firstX,
	max_x = firstX;min_x =lastX,
	);

	If (lastY>firstY,
	max_y = lastY; min_y =firstY,
	max_y = firstY;min_y =lastY,
	);


show(min_x,min_y,max_x,max_y);
evallist({min_x,max_x,min_y,max_y});
);

do_normal_select = Function({select_range},
show("normal_select");


dt << Select Where( 

	AsColumn(:Sepal length) >= select_range[1] 
	& AsColumn(:Sepal length) <= select_range[2]
	& AsColumn(:Sepal width) >= select_range[3] 
	& AsColumn(:Sepal width) <= select_range[4]
	
	);
);

do_shift_select = Function({select_range},
	show("shift_select");


	new_rows_to_add = as list(dt << Get Rows Where( 

		AsColumn(:Sepal length) >= select_range[1] 
		& AsColumn(:Sepal length) <= select_range[2]
		& AsColumn(:Sepal width) >= select_range[3] 
		& AsColumn(:Sepal width) <= select_range[4]
		
		)
			
	);

	if (length(new_rows_to_add) > 0,
	curr_rows = as list(dt << Get Selected Rows);
	rows_to_select = curr_rows || new_rows_to_add;
	dt << Select Rows( rows_to_select);
	);
		show(new_rows_to_add,length(new_rows_to_add));
);


do_ctrl_select = Function({select_range},
	show("ctrl_select");
	
	new_rows_to_subtract = associativearray(as list(dt << Get Rows Where( 

		AsColumn(:Sepal length) >= select_range[1] 
		& AsColumn(:Sepal length) <= select_range[2]
		& AsColumn(:Sepal width) >= select_range[3] 
		& AsColumn(:Sepal width) <= select_range[4]
		
		)
			
	));
	
	if (length(new_rows_to_subtract) > 0,
	curr_rows = associativearray(as list(dt << Get Selected Rows));
	show("current_rows_selected",length(curr_rows));
	show("number_rows_to_subtract",length(new_rows_to_subtract));
	intersection=curr_rows;intersection<<Intersect(new_rows_to_subtract);
	uncommon1 = curr_rows; 
	uncommon1<<remove(intersection);
	uncommon1 = uncommon1<<getkeys;

	show(uncommon1);
	show("uncommon array length",length(uncommon1));
	
	uncommon2 = new_rows_to_subtract; 
	uncommon2<<remove(intersection);
	uncommon2 = uncommon2<<getkeys;
	
	new_rows_to_add = as list(uncommon1 || uncommon2);
	
	
	dt << Clear Select;
	dt << Select Rows(new_rows_to_add);
	);

);




lstX = {};
lstY = {};

xpr_select_box = Expr(
	Line Style( "solid" );
	Fill Color( "BlueGreen" );
	Transparency( 0.03 );
	Rect(firstX, firstY, lastX, lastY, 1);
);

 
MouseDown = Function({px,py},


Insert Into(lstX,pX);
Insert Into(lstY,pY);
firstX = lstX[1];
lastX = lstX[NItems(lstX)];	
firstY = lstY[1];
lastY = lstY[NItems(lstY)];	


//show what's being selected
(report(MY_GRAPH_BUILDER)[FrameBox(1)]) << Add Graphics Script(
	Line Style( "solid" );
	Fill Color( "BlueGreen" );
	Transparency( 0.03 );
	Rect(firstX, firstY, lastX, lastY, 1);
);


);

MouseUp = Function({px,py},
		box_dims = get_box_dims(firstX,lastX,firstY,lastY);
		show("mouseUP range",box_dims);
		
		If( Is Shift Key(),
			modifier_key = "shift";do_shift_select(box_dims);,
			Is Control Key(),
			modifier_key = "control";do_ctrl_select(box_dims);,
		//no modifier key
		modifier_key = "none";dt << Clear Select;do_normal_select(box_dims);
		);
		


// I have no idea how this Xpath works but its pretty sweet
	script_list = ((report(MY_GRAPH_BUILDER)[FrameBox(1)]) << XPath("//TopSeg")) << get script;
	for(i=0,i<=length(script_list),i++,
	(report(MY_GRAPH_BUILDER)[FrameBox(1)]) << Remove Graphics Script( 2 );	
	);
	

		lstX = {};
		lstY = {};
		modifier_key = "none";	
);

 

11 REPLIES 11
xxvvcczz
Level III

Re: Is there a way to make the rowstate handler less laggy?

This made a big improvement. Thanks!

Craige_Hales
Super User

Re: Is there a way to make the rowstate handler less laggy?

For the multiple scripts, you could do it all in a single script and use a missing value in firstX to turn it off. Here's a q&d hack to only add one copy of a second script, or freshen the graph if not adding, and still use your logic to remove it when done.

 

MouseDown = Function( {px, py}, 
    Insert Into( lstX, pX );
    Insert Into( lstY, pY );
    firstX = lstX[1];
    lastX = lstX[N Items( lstX )];
    firstY = lstY[1];
    lastY = lstY[N Items( lstY )];	

// quick and dirty hack to only add the script once
    If( N Items( ((Report( MY_GRAPH_BUILDER )[FrameBox( 1 )]) << XPath( "//TopSeg" )) << get script ) < 2,
        (Report( MY_GRAPH_BUILDER )[FrameBox( 1 )]) << Add Graphics Script(
            Line Style( "solid" );
            Fill Color( "BlueGreen" );
            Transparency( 0.3 );
            Rect( firstX, firstY, lastX, lastY, 1 );
        );
    , // ELSE make sure to redraw using new values (might work without this)
        (Report( MY_GRAPH_BUILDER )[FrameBox( 1 )]) << inval << updatewindow;
    );
);
Craige