How can I export legend markers from matplotlib one at a time?
Asked Answered
E

1

2

I have a matplotlib legend that looks like this:

enter image description here

What's an easy way to export the markers as separate .pdf files? In other words, I want to end up with three separate .pdfs, one with a blue X, one with a gold +, etc.

Ultimately what I want to do is to use these markers in an inline legend in a Latex figure caption, but I figure I'll ask about that part on the Latex SE site.

Exceed answered 25/3, 2017 at 20:27 Comment(0)
R
1

An idea to export the legend handles to a file would be to save the created figure as pdf but crop it to the part of interest.

This can be done by specifying a bounding box bbox to the bbox_inches argument within the call to savefig

plt.savefig("file.pdf", dpi="figure", bbox_inches=bbox )

Now we just need to find out the bounding box to use. This can be done by finding the DrawingArea for each of the legend handles and transform its bounding box to coordinates in inches. This is done in a function export_legend_handles in the code below.

Unfortunately, while writing that code, I found that the marker may acutally exceed the DrawingArea. Since I haven't found an automatic way to find the real size of the handle outside the DrawingArea, one may need to extend/shrink the bounding box manually by some pixels. For this purpose, the below function has a parameter d which allows to set those pixel offsets and for this test case I have already put some decent values in.

import matplotlib.pyplot as plt
import numpy as np; np.random.seed(422)

x = np.arange(12)
a = np.random.rand(len(x), 3)

markers=["x", "+", "o"]
fig, ax = plt.subplots()
for i in range(a.shape[1]):
    ax.plot(x, a[:,i], linestyle="", marker=markers[i], label=markers[i]*6)

leg = ax.legend(framealpha=1)

def export_legend_handles(fig, leg, filename=None, ext=[".pdf", ".png"], d = [0,0,0,3]):
    """ d = [left, bottom, right, top] pixel to add in the respective dimension """
    import matplotlib.transforms as mtransforms
    boxes = []
    fig.canvas.draw()
    trans = fig.dpi_scale_trans.inverted()
    for vpack in leg._legend_handle_box.get_children():
        for hpack in vpack.get_children():
            drawbox = hpack.get_children()[0]
            w, h, xd, yd = drawbox.get_extent(fig.canvas.get_renderer())
            ox, oy = drawbox.get_offset()  
            pixbox = mtransforms.Bbox.from_bounds(ox-d[0],oy-d[1],w+d[0]+d[2],h+d[1]+d[3])
            inchbox = pixbox.transformed(trans) 
            boxes.append(inchbox)

    filename = filename if filename else __file__[:-3]
    for i, box in enumerate(boxes):
        for ex in ext:
            plt.savefig(filename+str(i)+ex, dpi="figure", bbox_inches=box)

export_legend_handles(fig, leg, d = [-5,0,-5,3])
plt.show()

This produces a plot like the following

enter image description here

and saves the legend handles as pdf and png images, which then look as follows

enter image description here

Rhyner answered 26/3, 2017 at 11:33 Comment(2)
Unfortunately, this did not work for me with a more complex figure, because the markers ended up being at very different vertical positions. This can be reproduced by adding linestyles=["-", "-", "-"] and by replacing marker=markers[i] with linestyle=linestyles[i]. Placing the three pdfs that are produced side by side you will notice that the three lines are at different heights. The difference is subtle here, but it is huge in another plot of mine.Chiropteran
@Chiropteran this answer would give you enough background to understand how to export markers. If it doesn't work for you you can ask a new question about it.Rhyner

© 2022 - 2024 — McMap. All rights reserved.