legend text vertical alignment

Hi,

I have a problem with legends where the vertical spacing is sometimes
a bit funny (lines don't seem to be evenly spaced).

I am now preparing some figures for publication and this is the last
niggle I'd really like to resolve.

Is there anything I could do to fix this?

A small example is attached (I cropped it to just the legend to reduce
file size).

I am setting the label on the bars I am plotting and then just calling
ax.legend()

At the risk of putting two queries in one email the only other problem
I have regularly is that small figures resize themselves when the
mouse rolls over them. I am using TkAgg backend on OS X but I think it
happens on other platforms as well. On mouse over the window jiggles
and resizes slightly. When I am saving figures I have to be careful to
call savefig from the command line without touching the window with
the mouse to ensure they save as the correct size. Just wondered if it
was a known issue...

Apart from these minor things though matplotlib has been performing great!

Thanks,

Robin

bad_legend.pdf (30.5 KB)

Hi,

I was wondering if anyone was able to help with this problem of
incorrect legend alignment.

I am not sure if the original mail did not get through, perhaps
because of the attachent, so this time I have put the example here:
http://acrids.robince.net/robince/bad_legend.pdf

Publication is now imminent and I have a horible feeling I am going to
have to do all the plots again in Matlab unless we can resolve this
problem - it currently looks very unprofessional.

I would appreciate any pointers on where to look to try to resolve this.

Thanks

Robin

···

On Thu, Jul 10, 2008 at 11:58 PM, Robin <robince@...287...> wrote:

Hi,

I have a problem with legends where the vertical spacing is sometimes
a bit funny (lines don't seem to be evenly spaced).

I am now preparing some figures for publication and this is the last
niggle I'd really like to resolve.

Is there anything I could do to fix this?

A small example is attached (I cropped it to just the legend to reduce
file size).

I am setting the label on the bars I am plotting and then just calling
ax.legend()

At the risk of putting two queries in one email the only other problem
I have regularly is that small figures resize themselves when the
mouse rolls over them. I am using TkAgg backend on OS X but I think it
happens on other platforms as well. On mouse over the window jiggles
and resizes slightly. When I am saving figures I have to be careful to
call savefig from the command line without touching the window with
the mouse to ensure they save as the correct size. Just wondered if it
was a known issue...

Apart from these minor things though matplotlib has been performing great!

Thanks,

Robin

Hi Robin,

Could you post a *simple* script that reproduces the problem? And in the
meantime, to get a figure that looks better for your publication, can you
save your figure as an svg, import it into inkscape, tweak the bad placement,
and then save a pdf?

Darren

···

On Monday 18 August 2008 08:47:16 am Robin wrote:

Hi,

I was wondering if anyone was able to help with this problem of
incorrect legend alignment.

I am not sure if the original mail did not get through, perhaps
because of the attachent, so this time I have put the example here:
http://acrids.robince.net/robince/bad_legend.pdf

Publication is now imminent and I have a horible feeling I am going to
have to do all the plots again in Matlab unless we can resolve this
problem - it currently looks very unprofessional.

I would appreciate any pointers on where to look to try to resolve this.

Thanks

Robin

On Thu, Jul 10, 2008 at 11:58 PM, Robin <robince@...287...> wrote:
> Hi,
>
> I have a problem with legends where the vertical spacing is sometimes
> a bit funny (lines don't seem to be evenly spaced).
>
> I am now preparing some figures for publication and this is the last
> niggle I'd really like to resolve.
>
> Is there anything I could do to fix this?
>
> A small example is attached (I cropped it to just the legend to reduce
> file size).
>
> I am setting the label on the bars I am plotting and then just calling
> ax.legend()
>
> At the risk of putting two queries in one email the only other problem
> I have regularly is that small figures resize themselves when the
> mouse rolls over them. I am using TkAgg backend on OS X but I think it
> happens on other platforms as well. On mouse over the window jiggles
> and resizes slightly. When I am saving figures I have to be careful to
> call savefig from the command line without touching the window with
> the mouse to ensure they save as the correct size. Just wondered if it
> was a known issue...
>
> Apart from these minor things though matplotlib has been performing
> great!
>
> Thanks,
>
> Robin

-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's
challenge Build the coolest Linux based applications with Moblin SDK & win
great prizes Grand prize is a trip for two to an Open Source event anywhere
in the world http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users

Hi,

Could you post a *simple* script that reproduces the problem? And in the
meantime, to get a figure that looks better for your publication, can you
save your figure as an svg, import it into inkscape, tweak the bad placement,
and then save a pdf?

Thanks for the inkscape suggestion - I usually just use eps and pdf
which I find harder to edit.

Below is the function I use to create the plot. Actually I thought it
happened with all legends, but I think I have just been focussing on
these plots for too long, because when I check now it only seems to
happen when I plot with this function.
plot_stacked(arange(1,6),arange(1,6)) should reproduce the problem.
Perhaps it is something to do with setting the labels to '' to delete
the duplicate copies I don't want?

Thanks,

Robin

def plot_stacked(*vals, **kwargs):
    fig = figure()
    sub = fig.add_subplot(111)
    ticks = kwargs.setdefault('ticks',[])
    labels = kwargs.setdefault('labels',False)

    numstacks = len(vals)
    vallength = set([len(val) for val in vals])
    if len(vallength) > 1:
        raise ValueError,'All input values should have the same length'
    vallength = vallength.pop()

    ind = 0.25 + arange(numstacks)
    width = 0.5
    bottom = zeros(numstacks)
    colorvals = arange(vallength) * (1.0/(vallength-1))
    orderlabels = ['First Order','Second Order','Third Order','Fourth Order']
    if not labels:
        labels = orderlabels[:vallength-1] + ['Higher Order']

    for i in range(vallength):
        ivals = [val[i] for val in vals]
        sub.bar(ind, ivals, width,
                bottom=bottom, color=str(colorvals[i]),label=labels[i])
        bottom += ivals
    sub.set_xlim(0,numstacks+1.5)
    sub.set_xticks(ind+width/2)
    sub.set_xticklabels(ticks)

    # remove duplicate labels
    tmplabels = []
    for rect in sub.patches:
        if rect.get_label() in tmplabels:
            rect.set_label('')
        else:
            tmplabels.append(rect.get_label())
    sub.legend()
    fig.show()

···

On Mon, Aug 18, 2008 at 2:25 PM, Darren Dale <dsdale24@...287...> wrote:

Darren

On Monday 18 August 2008 08:47:16 am Robin wrote:

Hi,

I was wondering if anyone was able to help with this problem of
incorrect legend alignment.

I am not sure if the original mail did not get through, perhaps
because of the attachent, so this time I have put the example here:
http://acrids.robince.net/robince/bad_legend.pdf

Publication is now imminent and I have a horible feeling I am going to
have to do all the plots again in Matlab unless we can resolve this
problem - it currently looks very unprofessional.

I would appreciate any pointers on where to look to try to resolve this.

Thanks

Robin

On Thu, Jul 10, 2008 at 11:58 PM, Robin <robince@...287...> wrote:
> Hi,
>
> I have a problem with legends where the vertical spacing is sometimes
> a bit funny (lines don't seem to be evenly spaced).
>
> I am now preparing some figures for publication and this is the last
> niggle I'd really like to resolve.
>
> Is there anything I could do to fix this?
>
> A small example is attached (I cropped it to just the legend to reduce
> file size).
>
> I am setting the label on the bars I am plotting and then just calling
> ax.legend()
>
> At the risk of putting two queries in one email the only other problem
> I have regularly is that small figures resize themselves when the
> mouse rolls over them. I am using TkAgg backend on OS X but I think it
> happens on other platforms as well. On mouse over the window jiggles
> and resizes slightly. When I am saving figures I have to be careful to
> call savefig from the command line without touching the window with
> the mouse to ensure they save as the correct size. Just wondered if it
> was a known issue...
>
> Apart from these minor things though matplotlib has been performing
> great!
>
> Thanks,
>
> Robin

-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's
challenge Build the coolest Linux based applications with Moblin SDK & win
great prizes Grand prize is a trip for two to an Open Source event anywhere
in the world http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users

-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users

No, because you can comment out that part of the code and still get a problem
with the "Higher Order" label.

The problem is that the text placement for the "Higher Order" text label is
being calculated with reference to the descent of "g" rather than its
baseline (see http://en.wikipedia.org/wiki/Typeface#Font_metrics). I'm
looking into it, I think it can be improved.

···

On Monday 18 August 2008 09:48:58 am you wrote:

Hi,

On Mon, Aug 18, 2008 at 2:25 PM, Darren Dale <dsdale24@...287...> wrote:
> Could you post a *simple* script that reproduces the problem? And in the
> meantime, to get a figure that looks better for your publication, can you
> save your figure as an svg, import it into inkscape, tweak the bad
> placement, and then save a pdf?

Thanks for the inkscape suggestion - I usually just use eps and pdf
which I find harder to edit.

Below is the function I use to create the plot. Actually I thought it
happened with all legends, but I think I have just been focussing on
these plots for too long, because when I check now it only seems to
happen when I plot with this function.
plot_stacked(arange(1,6),arange(1,6)) should reproduce the problem.
Perhaps it is something to do with setting the labels to '' to delete
the duplicate copies I don't want?

It turns out that the information needed to do a better job of placing either
the text or the Rectangle is calculated by the renderer, long after the text
and Rectangle positions have been chosen based on an approximation of the
text height (among other parameters). This is not my area of expertise, I'm
just trying to fill in while the others are busy at the Scipy conference.

There must be good reasons for organizing Legend the way it is, but maybe it
tries to do too much too early and then never makes any refinements. Here is
a patch that I submit only for the sake of discussion, it is an ugly
workaround to the problem of not using the text's baseline as the common
point of reference.

You can perhaps temporarily modify your legend.py to make a better figure,
although maybe this patch doesnt even do what you want it to. For now, I
think it would be better to go with inkscape to make improvements, if you
can.

Index: lib/matplotlib/legend.py

···

On Monday 18 August 2008 10:45:39 am Darren Dale wrote:

On Monday 18 August 2008 09:48:58 am you wrote:
> Hi,
>
> On Mon, Aug 18, 2008 at 2:25 PM, Darren Dale <dsdale24@...287...> wrote:
> > Could you post a *simple* script that reproduces the problem? And in
> > the meantime, to get a figure that looks better for your publication,
> > can you save your figure as an svg, import it into inkscape, tweak the
> > bad placement, and then save a pdf?
>
> Thanks for the inkscape suggestion - I usually just use eps and pdf
> which I find harder to edit.
>
> Below is the function I use to create the plot. Actually I thought it
> happened with all legends, but I think I have just been focussing on
> these plots for too long, because when I check now it only seems to
> happen when I plot with this function.
> plot_stacked(arange(1,6),arange(1,6)) should reproduce the problem.
> Perhaps it is something to do with setting the labels to '' to delete
> the duplicate copies I don't want?

No, because you can comment out that part of the code and still get a
problem with the "Higher Order" label.

The problem is that the text placement for the "Higher Order" text label is
being calculated with reference to the descent of "g" rather than its
baseline (see http://en.wikipedia.org/wiki/Typeface#Font_metrics). I'm
looking into it, I think it can be improved.

===================================================================
--- lib/matplotlib/legend.py (revision 6035)
+++ lib/matplotlib/legend.py (working copy)
@@ -203,16 +203,31 @@

         if not len(self.legendHandles) and not len(self.texts): return
- for h in self.legendHandles:
- if h is not None:
- h.draw(renderer)
- if hasattr(h, '_legmarker'):
- h._legmarker.draw(renderer)
- if 0: bbox_artist(h, renderer)

- for t in self.texts:
- if 0: bbox_artist(t, renderer)
- t.draw(renderer)
+ for l, t in safezip(self.legendHandles, self.texts):
+ if t is not None:
+ if 0: bbox_artist(t, renderer)
+ t.draw(renderer)
+ s = t.get_text()
+ f = t.get_font_properties()
+ ismath = t.is_math_text(s)
+ w, h, d = renderer.get_text_width_height_descent(s, f,
ismath)
+ if l is not None:
+ if isinstance(l, Rectangle):
+ try:
+ old_h = l.get_height()
+ new_h = old_h * (h-d) / h
+ old_y = l.get_y()
+ new_y = old_y + (old_h - new_h)
+ l.set_height(new_h)
+ l.set_y(new_y)
+ except NameError:
+ pass
+ l.draw(renderer)
+ if hasattr(l, '_legmarker'):
+ l._legmarker.draw(renderer)
+ if 0: bbox_artist(l, renderer)
+
         renderer.close_group('legend')
         #draw_bbox(self.save, renderer, 'g')
         #draw_bbox(self.ibox, renderer, 'r', self.get_transform())

I'm out of town, so it's hard for me to look deeply into this now, but 0.91 and later supports "baseline" vertical alignment, but the legend layout code doesn't use it by default. It may be as simple as setting valign to "baseline" in the legend text -- or there may be a subtle interaction with something else. But maybe that's a hint about where to start.

Cheers,
Mike

My last response was sent before reading this. I think you've found the reason why it's not as easy as it seems...

I think your suggestion (to manually adjust) is good for now. I'll see if I can find time to look at this when I get back.

Cheers,
Mike

Thanks for your help.

I have been getting on OK with manual adjustment.

I thought I would point out a similar problem though which I suspect
is the same thing.

If I am using latex tick labels for a bar graph, the tick labels with
superscripts have a lower baseline than tick labels without
superscripts which again looks a little funny.

Cheers

Robin