Getting coordinates of legend markers

Question:

It’s my first time asking a question here. So please tell me if anything is amiss.

So I’m trying to create a dataset of synthetically generated charts to train a neural net to find bounding boxes for different elements of a chart – legend box, chart title, axes labels, etc. That’s the part I’ve managed to do.

Next what I need is to create a mapping from different legend entries to their corresponding datapoints. I need to create annotations for bounding boxes around the different handles and text like this:

Please see an example here

I’ve tried looking around the docs, but there can’t find any related functionality. Looking into properties of legend using matplotlib.artist.getp() also got me nothing on this.

fig, ax = plt.subplots(figsize=(12, 4))
x_vals = np.linspace(0, 5, 5)
y_vals = np.random.uniform(size=(5,))

ax.plot(x_vals, y_vals, label='line1')
ax.plot(x_vals, y_vals + np.random.randn(), label='line2')
leg = ax.legend()
ax.set_label('Label via method')

matplotlib.artist.getp(leg)

Output:
    agg_filter = None
    alpha = None
    animated = False
    bbox_to_anchor = TransformedBbox(     Bbox(x0=0.125, y0=0.125, x1=0...
    children = [<matplotlib.offsetbox.VPacker object at 0x7f3582d...
    clip_box = None
    clip_on = True
    clip_path = None
    contains = None
    default_handler_map = {<class 'matplotlib.container.StemContainer'>: <ma...
    figure = Figure(864x288)
    frame = FancyBboxPatch(640.55,203.64;60.625x33)
    frame_on = True
    gid = None
    label = 
    legend_handler_map = {<class 'matplotlib.container.StemContainer'>: <ma...
    lines = [<matplotlib.lines.Line2D object at 0x7f35834f4400...
    patches = <a list of 0 Patch objects>
    path_effects = []
    picker = None
    rasterized = None
    sketch_params = None
    snap = None
    texts = <a list of 2 Text objects>
    title = Text(0,0,'None')
    transform = IdentityTransform()
    transformed_clip_path_and_affine = (None, None)
    url = None
    visible = True
    window_extent = Bbox(x0=640.5500000000001, y0=203.64, x1=701.17500...
    zorder = 5

Any help would be appreciated. Please tell me if any clarification is needed. Thanks

Asked By: metalmachine13

||

Answers:

I spent a solid 30min poking around trying to figure something out.. I’m sure there’s an easier way but here’s something I whipped up in the hopes it helps you

import matplotlib.pyplot as plt; plt.ion()
from matplotlib.patches import Rectangle as rect

fig, ax = plt.subplots()
ax.plot([0,1],[4,6],label='test')
leg = ax.legend(edgecolor='w', loc='upper left')
leg.get_frame().set_alpha(0)
line = leg.get_lines()[0]
plt.draw()
plt.pause(0.001)

#all of this is based on pixel coordinates in the figure
(lx0, ly0, lx1, ly1) = (leg.get_window_extent().x0,
                       leg.get_window_extent().y0,
                       leg.get_window_extent().x1,
                       leg.get_window_extent().y1)
(mx0, my0, mx1, my1) = (line.get_window_extent(fig).x0,
                       line.get_window_extent(fig).y0,
                       line.get_window_extent(fig).x1,
                       line.get_window_extent(fig).y1)
(ax0, ay0, ax1, ay1) = (ax.get_window_extent().x0,
                       ax.get_window_extent().y0,
                       ax.get_window_extent().x1,
                       ax.get_window_extent().y1)
#convert pixel coords to graphical coords
x0, x1 = ax.get_xlim()
y0, y1 = ax.get_ylim()
ratex = (x1-x0) / (ax1-ax0)
ratey = (y1-y0) / (ay1-ay0)
newx0 = (mx0 - ax0) * ratex + x0
newx1 = (mx1 - ax0) * ratex + x0
newy0 = (my0 - ay0) * ratey + y0 - 0.05
newy1 = (my1 - ay0) * ratey + y0 + 0.05
#box around legend marker
ax.add_patch(rect((newx0, newy0), newy1-newy0, newx1-newx0, edgecolor='k', alpha=0.5, facecolor='w'))
#convert pixel coords to graphical coords
tx0 = mx1
tx1 = lx1
ty0 = ly0
ty1 = ly1
newx0 = (tx0 - ax0) * ratex + x0
newx1 = (tx1 - ax0) * ratex + x0
newy0 = (ty0 - ay0) * ratey + y0
newy1 = (ty1 - ay0) * ratey + y0
#box around legend txt
ax.add_patch(rect((newx0, newy0), newy1-newy0, newx1-newx0, edgecolor='k', alpha=0.5, facecolor='w'))

this produces the following plot:
plot

I’m not 100% sure why the boxes are off but you could modify this to make it work somehow…you could also use this to get coordinates for the legend entries, and draw a vector from those coordinates to coordinates on the corresponding data lines

Answered By: Derek Eden
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.