cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Browse apps to extend the software in the new JMP Marketplace
Choose Language Hide Translation Bar
EDM
EDM
Level II

Looking for a way to control and move a shape across a graph

I'm looking for a way to control and move a 'drawn' shape or series of shapes across plot (graph builder) using JSL script, for data visualisation purposes. Think of it as an animation using a series of frames and then scrolling through them to give the impression of movement.

 

By 'drawn' shape, I mean something like:

Rect ()

 

I was thinking of taking the following approach, but I'm not sure exactly how to execute this or if there's a better approach:

-  Script / draw the shape(s) required and associate them with a variable (which could be a row value) - we'll call this a frame

- Construct multiples frames, with the shape(s) required in different positions, with each frame assigned to a distinct variable

E.g.

Frame 1 - Shape is in position (X+0,Y) and associated with variable (v = 1)

Frame 2 - Shape is in position (X+1,Y) and associated with variable (v = 2)

Frame 3 - Shape is in position (X+2,Y) and associated with variable (v = 3)

- Use local data filter to scroll which variable is selected and therefore the position of the drawn shape(s)

 

I'd hope that this, as described in my example, would give the impression of the shape moving in direction X+.

As aforementioned I am unsure that this would work, the graph builder report would need to be updated / refreshed somehow to remove the old drawing (overwritten) in place of the new one when the variable selected is being changed.

 

I'm eager to see if something like this is possible and how this could be coded.

 

 

 

 

1 ACCEPTED SOLUTION

Accepted Solutions
Craige_Hales
Super User

Re: Looking for a way to control and move a shape across a graph

x1 = y1 = x2 = y2 = 0;
keepRunning=1;
New Window( "Example", gb = Graph Box( Frame Size( 800, 800 ), Oval( x1, y1, x2, y2 ) ), <<onclose(keepRunning=0;1) );
Wait( 0.1 );
radius = 5;
x = 50;
y = 90;
velocity = 0;
accel = .2;
prevtime = Tick Seconds();
While( keepRunning,
	curtime = Tick Seconds();
	dt = curtime - prevtime;
	prevtime = curtime;
	velocity -= accel;
	dy = velocity * dt;
	y = Max( 1, y + dy );
	//Show( y );
	ysize = Min( radius, y );
	xsize = radius ^ 2 / ysize;
	x1 = x - xsize;
	x2 = x + xsize;
	y1 = y + ysize;
	y2 = y - ysize;
	gb[framebox( 1 )] << inval << reshow;
	Wait( 0 );
	// the bounce is hard to model. the velocity decreases rapidly, then reverses rapidly.
	// the following isn't quite right...
	If( y < radius,
		velocity += 5 / y; // reverse harder as the ball squishes more.
	);
	velocity *= .99;
);

Looks like some rusty physics.

Craige

View solution in original post

5 REPLIES 5
jthi
Super User

Re: Looking for a way to control and move a shape across a graph

Could you provide better example about what you try to visualize? JMP does for example have Mousetrap() which can draw things based on the cursor location in the framebox

Names Default To Here(1); 

dt = open("$SAMPLE_DATA/Big Class.jmp");

gb = dt << Graph Builder(
	Variables(X(:weight), Y(:height), Overlay(:sex)),
	Elements(Points(X, Y, Legend(9)), Line Of Fit(X, Y, Legend(11)))
);

exx = 70;
exy = 70;

Report(gb)[FrameBox(1)] << Add Graphics Script(
	Mousetrap(
		exx = x;
		exy = y;
	);
	Rect({exx - 10, exy - 10}, {exx, exy});	
);

 

-Jarmo
EDM
EDM
Level II

Re: Looking for a way to control and move a shape across a graph

This is really neat.

I think I can find a use for this, I'm eager to a have a play around to see how it works.

I'm now keen on taking a more passive approach to my initial problem, I didn't realise you can control a shapes velocity, acceleration over time like in Craige's example.

Craige_Hales
Super User

Re: Looking for a way to control and move a shape across a graph

x1 = y1 = x2 = y2 = 0;
keepRunning=1;
New Window( "Example", gb = Graph Box( Frame Size( 800, 800 ), Oval( x1, y1, x2, y2 ) ), <<onclose(keepRunning=0;1) );
Wait( 0.1 );
radius = 5;
x = 50;
y = 90;
velocity = 0;
accel = .2;
prevtime = Tick Seconds();
While( keepRunning,
	curtime = Tick Seconds();
	dt = curtime - prevtime;
	prevtime = curtime;
	velocity -= accel;
	dy = velocity * dt;
	y = Max( 1, y + dy );
	//Show( y );
	ysize = Min( radius, y );
	xsize = radius ^ 2 / ysize;
	x1 = x - xsize;
	x2 = x + xsize;
	y1 = y + ysize;
	y2 = y - ysize;
	gb[framebox( 1 )] << inval << reshow;
	Wait( 0 );
	// the bounce is hard to model. the velocity decreases rapidly, then reverses rapidly.
	// the following isn't quite right...
	If( y < radius,
		velocity += 5 / y; // reverse harder as the ball squishes more.
	);
	velocity *= .99;
);

Looks like some rusty physics.

Craige
EDM
EDM
Level II

Re: Looking for a way to control and move a shape across a graph

This looks really good, I think this is what I'm after - I really like how this can be time driven.

 

Would it be possible to get this to work for a more complex drawing, such as:

 

Fill Color( RGB Color( 255, 0, 0 ) );
Rect (50, 90, 60, 80, 1);
Fill Color( RGB Color( 204, 0, 0 ) );
Rect (51, 89, 59, 81, 1);
Fill Color( RGB Color( 255, 0, 0 ) );
Polygon ( {59, 89}, {60, 90}, {50, 90}, {51, 89});
Fill Color( RGB Color( 153, 0, 0 ) );
Polygon ( {60, 80}, {59, 81}, {51, 81}, {50, 80});

 

Rather than bouncing, when the bottom of the shape hits the X-axis, I want to be able to get it to stop and stay in place.

Also, after a given time has elapsed I'd like other shapes drawing to enter the screen and follow the same path, with each one settling on the X-axis.

 

I've had a play around with the script you sent, but not sure quite how to modify it in the right way - really clever!!!

Craige_Hales
Super User

Re: Looking for a way to control and move a shape across a graph

Yes, you can do that.  It sounds like your object has a rigid shape and you want it to stop instantly when some condition is met. Not gradually slow down or distort. And it sounds like you will have multiple objects that may be released over time. I'd use a data table with one row per object, with column names similar to these:

Xpos  Ypos  Xvel  Yvel  XdeltaVel  TdeltaVel  IsActive  IsDrawing  Color  Size  Shape

Then I'd write two functions: UpdateRow( row number, deltaTime ) and DrawRow( row number ). UpdateRow might look something like this (untested, approximately right...):

UpdateRow = function({rowNumber, deltaTime}
   if( dtQ:isActive[rowNumber],
      dtQ:Xpos[rowNumber] += dtQ:Xvel[rowNumber] * deltaTime;
      dtQ:Ypos[rowNumber] += dtQ:Yvel[rowNumber] * deltaTime;
      // you might want the velocity to change as well, possibly using the deltaVelocity,
      // make sure the Xs and Ys stay together
      // do a test to see if still active
      if( dtQ:y[rowNumber] <= 0, // whatever condition makes it stop
          dtQ:isActive[rowNumber] = 0;
          dtQ:isDrawing[rowNumber] -= 1; // count down until vanishes
      )
}

When you add a row to the table (dtQ, above, I tend to use dt for a table not delta time!) make sure to set the row's value for isActive to 1, and if you want the non-active objects to eventually expire, set the isDrawing to 100 or 1000 to control how many cycles go by before it stops drawing.

The DrawRow function looks something like this:

DrawRow = function({RowNumber},
   if( dtQ:isDrawing[RowNumber],
      // your code goes here. Add the dtQ:Xpos[RowNumber] to your X coords
      // and same for Ypos/Y.
      // .... use the color/size/shape values from the row if you find them useful
   )
);

Now the graphics script becomes a pair of loops over dtQ, the first to apply the updates, and the second to do the drawing. You don't have to keep them separated, but you might find it helpful later if you decide to handle collisions.

In this example, the data table in dtQ could also be displayed with graph builder by plotting the xpos, ypos, color, size, shape values. GraphBuilder will update automatically and you don't need the DrawRow function. I've never used it but I think there might be a custom shape drawing mechanism for the points.

If you are trying to make a video (rather than an interactive, real-time display), settle on 30 or 60 FPS and let the delta time be constant from frame to frame. Above, I picked numbers that made it work on my machine. But if I picked 1/30 and made a set of numbered images, they would make a very smooth video.

 

 

 

Craige