custom markers from images?

I’d like to use, in one case, small loaded images (pngs) as markers on an interactive matplotlib plot (using the OO approach). I’d potentially like to be able to point-pick these markers, too, as well as have them update appropriately if the plot is resized.

The only example I’ve been to find of this is here:
http://stackoverflow.com/questions/2318288/how-to-use-custom-marker-with-plot

But that is from 2 years ago. Is this way of doing it–which the author describes as a “kludge”–still the state of things, or is there a better approach now? (And right now this way isn’t working for me…the images are down the bottom of the figure).

Thank you,
Che

Yeah, there are better ways to do that, somewhat. The problem with the proposed solution is that it relies on non-public APIs, which are can be subject to change without deprecation. Instead, I would have created the figimage object with a particular transform object that would have placed it at the appropriate data points. Perhaps someone else on this list knows of the correct way to do that?

Ben Root

···

On Wed, Feb 29, 2012 at 5:47 PM, C M <cmpython@…287…> wrote:

I’d like to use, in one case, small loaded images (pngs) as markers on an interactive matplotlib plot (using the OO approach). I’d potentially like to be able to point-pick these markers, too, as well as have them update appropriately if the plot is resized.

The only example I’ve been to find of this is here:
http://stackoverflow.com/questions/2318288/how-to-use-custom-marker-with-plot

But that is from 2 years ago. Is this way of doing it–which the author describes as a “kludge”–still the state of things, or is there a better approach now? (And right now this way isn’t working for me…the images are down the bottom of the figure).

Thank you,
Che

Yeah, there are better ways to do that, somewhat. The problem with the proposed solution is that it relies on non-public APIs, which are can be subject to change without deprecation. Instead, I would have created the figimage object with a particular transform object that would have placed it at the appropriate data points.

Maybe your or someone from this list can help me understand more about this. So, if I take the code that I have adapted to my purposes, there are questions I have about it:

    # constants
    dpi = 72; imageSize = (32,32)

    # read in our png file
    im = image.imread('redX_10.png')

So far, so good–just setting the dpi and getting the image.

    fig = self.figure
    ax = self.subplot

    ax.get_frame().set_alpha(0)

Does the current version of Matplotlib require the frame be set to fully transparent? I need a white canvas, so I think I’d rather not do that.

    # translate point positions to pixel positions

    # figimage needs pixels not points
    line = self.line_collections_list[0][0]

“line” here is my line of datapoints from elsewhere in my app.

    line._transform_path()
    path, affine = line._transformed_path.get_transformed_points_and_affine()

    path = affine.transform_path(path)

I have no understanding of the purpose of the previous three lines. Can someone give me a quick explanation?

    for pixelPoint in path.vertices:
        # place image at point, centering it

        fig.figimage(im,pixelPoint[0]+80,pixelPoint[1]+180,origin="upper")

This is just a way to put the image somewhere on my canvas to see it, so these offsets are just for this exercise.

I should state that if I do it this way, the images appear on the canvas but are NOT repositioned in data coordinates (and they should be)–which is probably just Ben’s point, right?

Thanks,
Che

···

Yeah, there are better ways to do that, somewhat. The problem with the proposed solution is that it relies on non-public APIs, which are can be subject to change without deprecation. Instead, I would have created the figimage object with a particular transform object that would have placed it at the appropriate data points.

Maybe your or someone from this list can help me understand more about this. So, if I take the code that I have adapted to my purposes, there are questions I have about it:

    # constants
    dpi = 72; imageSize = (32,32)




    # read in our png file
    im = image.imread('redX_10.png')

So far, so good–just setting the dpi and getting the image.

    fig = self.figure
    ax = self.subplot




    ax.get_frame().set_alpha(0)

Does the current version of Matplotlib require the frame be set to fully transparent? I need a white canvas, so I think I’d rather not do that.

I think this is technically because of the use of figimage. Any axes that are created would get plotted above the figimage. I suppose one could manually set the zorder to a high enough number to make sure it stays on top.

translate point positions to pixel positions

    # figimage needs pixels not points
    line = self.line_collections_list[0][0]

“line” here is my line of datapoints from elsewhere in my app.

    line._transform_path()
    path, affine = line._transformed_path.get_transformed_points_and_affine()




    path = affine.transform_path(path)

I have no understanding of the purpose of the previous three lines. Can someone give me a quick explanation?

The transforms framework translates coordinates from one system to another. There are multiple coordinate systems within a mpl figure. data, axes and figure are the three main “reference frames”. I think the first line is effectively useless (but due to caching has no impact on performance). The second line would translate the coordinates stored in “line” into figure-relative coordinates, and also provide a special object for doing affine transformations. The point of that step, IIUC, is to do a special handling of curves (either the line data itself has curves, or the coordinate tranformation has curves). Consider the case of drawing a straight line from a Lat/Lon coordinate on a map to another Lat/Lon coordinate (so, there are only two points in “line”). Now, that line may not be straight depending upon the map projection used, so the final line may need many more points to represent it correctly in a transformed projection. Again, I am not an expert here, so it is quite likely that I mixed something up.

for pixelPoint in path.vertices:
# place image at point, centering it

        fig.figimage(im,pixelPoint[0]+80,pixelPoint[1]+180,origin="upper")

This is just a way to put the image somewhere on my canvas to see it, so these offsets are just for this exercise.

I should state that if I do it this way, the images appear on the canvas but are NOT repositioned in data coordinates (and they should be)–which is probably just Ben’s point, right?

Right. It should be technically feasible to just simply tell figimage to use a different transformation object, but this might have implications elsewhere. I am very hazy in this part of mpl.

Cheers!
Ben Root

···

On Thu, Mar 1, 2012 at 1:11 PM, C M <cmpython@…287…> wrote:

Right. It should be technically feasible to just simply tell figimage to use a different transformation object, but this might have implications elsewhere. I am very hazy in this part of mpl.

Hmm, I’ve simplified the figimage to just this line:

    fig.figimage(im,100,100,origin="upper", transform=None)

And it puts the image 100 up and 100 px out from the lower right corner. I then tried setting the transform from None to all the various possible transforms listed on this page:

http://matplotlib.sourceforge.net/users/transforms_tutorial.html

as well as their inverted() forms. None of them allowed the image to be updated with data coordinates when the plot was resized.

It really seems that figimage is a property of the figure only and not the canvas, so whatever the axes do is irrelevant to its placement.

But I really don’t know for sure. So far, this isn’t going to work this way.

Thanks,
Che

I’ve for now taken a different approach that means I won’t need custom markers from images.

But I’m just curious: is there any wish/plans in Matplotlib to add support for this? I think it could do a lot to expand what’s possible in terms of the look and feel of plots (even without things drifing into USA Today territory!).

Just my $0.02

Che

It would be a nice idea. I’m not sure it’s something that would
work terribly well in vector backends as the images may not scale
well. I should mention that there is already support to use
arbitrary Unicode characters or math expressions as markers already,
which does work well in vector backends.

Mike
···

http://www.accelacomm.com/jaw/sfnl/114/51521223/Matplotlib-users@lists.sourceforge.nethttps://lists.sourceforge.net/lists/listinfo/matplotlib-users

One way to use images as a marker would be to use offsetbox module.
Here is an example adopted from

http://matplotlib.sourceforge.net/examples/pylab_examples/demo_annotation_box.html

Regards,

-JJ

import matplotlib.pyplot as plt
from matplotlib.offsetbox import OffsetImage, AnnotationBbox
from matplotlib.cbook import get_sample_data

import numpy as np

if 1:
    fig = plt.gcf()
    fig.clf()
    ax = plt.subplot(111)

    xy = [0.3, 0.55]

    arr = np.arange(100).reshape((10,10))
    im = OffsetImage(arr, zoom=2)

    ab = AnnotationBbox(im, xy,
                        xycoords='data',
                        pad=0.3,
                        )

    ax.add_artist(ab)

    # another image

    from matplotlib._png import read_png
    fn = get_sample_data("lena.png", asfileobj=False)
    arr_lena = read_png(fn)

    imagebox = OffsetImage(arr_lena, zoom=0.1)

    xy = (0.7, 0.4)
    ab = AnnotationBbox(imagebox, xy,
                        xycoords='data',
                        pad=0.5,
                        )

    ax.add_artist(ab)

    ax.set_xlim(0, 1)
    ax.set_ylim(0, 1)

    plt.draw()
    plt.show()

···

On Thu, Mar 8, 2012 at 4:25 AM, Michael Droettboom <mdroe@...86...> wrote:

It would be a nice idea. I'm not sure it's something that would work
terribly well in vector backends as the images may not scale well. I should
mention that there is already support to use arbitrary Unicode characters or
math expressions as markers already, which does work well in vector
backends.

Mike

On 03/07/2012 01:59 PM, C M wrote:

I've for now taken a different approach that means I won't need custom
markers from images.

But I'm just curious: is there any wish/plans in Matplotlib to add support
for this? I think it could do a lot to expand what's possible in terms of
the look and feel of plots (even without things drifing into USA Today
territory!).

Just my $0.02

Che

------------------------------------------------------------------------------
Virtualization & Cloud Management Using Capacity Planning
Cloud computing makes use of virtualization - but cloud computing
also focuses on allowing computing to be delivered as a service.
http://www.accelacomm.com/jaw/sfnl/114/51521223/

_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
matplotlib-users List Signup and Options

------------------------------------------------------------------------------
Virtualization & Cloud Management Using Capacity Planning
Cloud computing makes use of virtualization - but cloud computing
also focuses on allowing computing to be delivered as a service.
http://www.accelacomm.com/jaw/sfnl/114/51521223/
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
matplotlib-users List Signup and Options