HTML5 Matplotlib Backend

(Michael Droettboom)

The display at the bottom that says “Cursor
at: X, Y” is in pixels, not in

data units. ?It would be great if this could
display data units, though

being general enough to support custom scales
(eg. log) and projections (eg.

polar) may be tricky without making a round-trip
to the server.

(Simon Ratcliffe)

As you mentioned, the trick is in giving the client
some view on how

pixels should map to data values without fetching
these for each mouse

movement. For simple cartesian plots this is probably
pretty

straightforward. It is something we need to get
working for our

internal use so it should get solved at some stage.

I have accomplished this in one of my applications as
follows:

Axes =figure.get_axes()

#The transform used in this axis is Composite Generic
Transform, so get the two affine transformation matricies

MatrixA = axes[0].transData.inverted()._a.get_matrix()

MatrixB = axes[0].transData.inverted()._b.get_matrix()

I use an Ajax or WebSockets call to get MatrixA and MatrixB
to the client (javascript) side, and then do the affine transform in the
mousemove callback:

function ev_mousemove(ev){

if(affineMatrixPopulated){

//First convert the browser coordinates to the form MPL uses

var x, y, x2, y2;

x = ev.clientX - canvas.offsetLeft;

y = canvas.height - (ev.clientY - canvas.offsetTop);

//Now it’s just a couple matrix multiplications:

// I flattened the Matrix when transferring from the server
process, so affineMatrixA[2] is MatrixA[0,2]

// affineMatrixA[4] is MatrixA[1,1] etc…

x2 = affineMatrixA[0] * x + affineMatrixA[1] * y + affineMatrixA[2];

y2 = affineMatrixA[3] * x + affineMatrixA[4] * y + affineMatrixA[5];

x2 = affineMatrixB[0] * x2 + affineMatrixB[1] * y2 + affineMatrixB[2];

y2 = affineMatrixB[3] * x2 + affineMatrixB[4] * y2 + affineMatrixB[5];

document.getElementById(‘cursor_info’).innerText = "Cursor at: " + x2

  • “,” + y2;

}

}

The simple affine transformation can be accomplished by
leaving off the MatrixB part. Non affine will probably be similar to the above
followed by a log or exponential operation.

Ryan Wagner** ** |Senior Technical Support Engineer |

Rogue
Wave Software, Inc.

5500
Flatiron Parkway, Suite 200, Boulder, CO 80301

ryan.wagner@…869…

www.roguewave.com

(Michael Droettboom)

The display at the bottom that says "Cursor at: X, Y" is in pixels, not
in

data units. ?It would be great if this could display data units, though

being general enough to support custom scales (eg. log) and projections
(eg.

polar) may be tricky without making a round-trip to the server.

(Simon Ratcliffe)

As you mentioned, the trick is in giving the client some view on how

pixels should map to data values without fetching these for each mouse

movement. For simple cartesian plots this is probably pretty

straightforward. It is something we need to get working for our

internal use so it should get solved at some stage.

I have accomplished this in one of my applications as follows:

Axes =figure.get_axes()

#The transform used in this axis is Composite Generic Transform, so get the
two affine transformation matricies

MatrixA = axes[0].transData.inverted()._a.get_matrix()

MatrixB = axes[0].transData.inverted()._b.get_matrix()

[...]

The simple affine transformation can be accomplished by leaving off the
MatrixB part. Non affine will probably be similar to the above followed by a
log or exponential operation.

The other option, which would be somewhat less accurate but would
avoid reimplementing every projection in javascript, would be to build
a mesh (e.g., a grid) over the client's viewport region, sample the
value of the projection at each point on the grid, send that to the
client, and then let the client do linear interpolation to estimate
points in between grid points.

-- Nathaniel

···

On Fri, Jul 16, 2010 at 10:21 AM, Ryan Wagner <Ryan.Wagner@...869...> wrote: