Feature request: automatic scaling of subplots, margins, etc

Hi,

almost every time I create a somewhat more complex figure I have to
fight with the not too smart positioning of the plots and the size of
margins around the axes. From many postings here I have learned that
this is the absolute intention, i.e. it is broken by design unless the
programmer takes care about this.

I have to admin that I do not really get this idea. I am aware that
the defaults will not change anytime soon and so I'd like to ask for
an "idiot-proof" mode: this could be enabled by an rcParam and take
care of proper dimensions, scale axis labels, titles, margins etc so
that they don't cover.

Here's an example for a matplotlib script which is a simple as it can
get and demonstrates the broken layout which a user gets by default.

import scipy
import pylab

x = scipy.linspace(-50,50, 100)
y1 = scipy.rand(100)
y2 = scipy.sin(x)
y3 = y1 + y2

fig = pylab.figure()
ax1 = fig.add_subplot(311)
ax2 = fig.add_subplot(312)
ax3 = fig.add_subplot(313)

ax1.plot(x, y1)
ax2.plot(x, y2)
ax3.plot(x, y3)

ax1.set_title('some title')
ax2.set_title('some title')
ax3.set_title('some title')

pylab.show()

Of course, one can adjust the figsize but the results are still far
from being adorable. The spacing around the sublplots increases for no
apparent reason while the spacing between the subplot remains the same
so that everything looks cramped...

Thank you many times in advance,
best regards,

Daniel

Since I just posted an almost-identical question, it's no surprise
that I agree this would be a useful feature.
Reason #1) I create hundreds of quick throwaway figures every day,
often in an automated way, and don't have time to fine-tune them.
Reason #2) a newbie to matplotlib might be turned off by one "ugly"
figure, when in fact matplotlib is capable of producing beautiful
figures.

The previous suggestion I received was to create a convenience wrapper
for the subplot function with some idiot-proof defaults. Can you
propose a set of rcParams that satisfies this criterion? This one
fixes the specific issue you raise:
matplotlib.rcParams['figure.subplot.hspace'] = .5

Although it will rear its ugly head again once the number of subplots
reaches 5 or 6. Personally I rarely use more than 4x4, and if I did I
would certainly increase the figsize.

I find that setting all text sizes to be as small as possible also
helps. My most commonly encountered issue is overlapping x-tick
labels, because most of my plots have "samples" on the x-axis and
therefore hundreds of thousands of points.

The real solution of course is to calculate exactly where every piece
of text actually is, detect overlaps, and adjust. That is certainly
beyond my ability or inclination to implement. In the mean time, it
would be nice to have a simple "idiot-proof" flag that blindly fixes
some common problems.

···

On Fri, May 6, 2011 at 1:20 AM, Daniel Mader <danielstefanmader@...982...> wrote:

Hi,

almost every time I create a somewhat more complex figure I have to
fight with the not too smart positioning of the plots and the size of
margins around the axes. From many postings here I have learned that
this is the absolute intention, i.e. it is broken by design unless the
programmer takes care about this.

I have to admin that I do not really get this idea. I am aware that
the defaults will not change anytime soon and so I'd like to ask for
an "idiot-proof" mode: this could be enabled by an rcParam and take
care of proper dimensions, scale axis labels, titles, margins etc so
that they don't cover.

Here's an example for a matplotlib script which is a simple as it can
get and demonstrates the broken layout which a user gets by default.

import scipy
import pylab

x = scipy.linspace(-50,50, 100)
y1 = scipy.rand(100)
y2 = scipy.sin(x)
y3 = y1 + y2

fig = pylab.figure()
ax1 = fig.add_subplot(311)
ax2 = fig.add_subplot(312)
ax3 = fig.add_subplot(313)

ax1.plot(x, y1)
ax2.plot(x, y2)
ax3.plot(x, y3)

ax1.set_title('some title')
ax2.set_title('some title')
ax3.set_title('some title')

pylab.show()

Of course, one can adjust the figsize but the results are still far
from being adorable. The spacing around the sublplots increases for no
apparent reason while the spacing between the subplot remains the same
so that everything looks cramped...

Thank you many times in advance,
best regards,

Daniel

------------------------------------------------------------------------------
WhatsUp Gold - Download Free Network Management Software
The most intuitive, comprehensive, and cost-effective network
management toolset available today. Delivers lowest initial
acquisition cost and overall TCO of any competing solution.
http://p.sf.net/sfu/whatsupgold-sd
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users

I wrote a helper script awhile back to adjust spacing “automatically”.

Code can be found here:

http://www.mail-archive.com/matplotlib-users@…1753…forge.net/msg18107.html

You can simply copy the code into a module (e.g. layout.py) that lives in your python path, and then call “layout.tight_layout()” right before your call to “plt.show()” (or “plt.savefig()”).

It’s pretty inefficient though because it has to draw the figure 3 different times (once to calculate the size of subplots and again to calculate the size of the figure, and then the final draw). There are some other issues, which prevent inclusion in matplotlib (see discussion in link below), but it works well for my purposes.

Best,
-Tony

Original post, with some discussion, can be found here:

http://www.mail-archive.com/matplotlib-devel@…1753…forge.net/msg06896.html

Note the code from the original post didn’t work on some backends, so it’s probably best to use the code from the first link.

···

On Fri, May 6, 2011 at 5:55 AM, Chris Rodgers <chris.rodgers@…1016…> wrote:

The real solution of course is to calculate exactly where every piece

of text actually is, detect overlaps, and adjust. That is certainly

beyond my ability or inclination to implement. In the mean time, it

would be nice to have a simple “idiot-proof” flag that blindly fixes

some common problems.

Very nice, will try this asap!

Many thanks!

2011/5/6 Tony Yu <tsyu80@...287...>:

···

On Fri, May 6, 2011 at 5:55 AM, Chris Rodgers <chris.rodgers@...1016...> > wrote:

The real solution of course is to calculate exactly where every piece
of text actually is, detect overlaps, and adjust. That is certainly
beyond my ability or inclination to implement. In the mean time, it
would be nice to have a simple "idiot-proof" flag that blindly fixes
some common problems.

I wrote a helper script awhile back to adjust spacing "automatically".

Code can be found here:
http://www.mail-archive.com/matplotlib-users@lists.sourceforge.net/msg18107.html

You can simply copy the code into a module (e.g. layout.py) that lives in
your python path, and then call "layout.tight_layout()" *right before* your
call to "plt.show()" (or "plt.savefig()").

It's pretty inefficient though because it has to draw the figure 3 different
times (once to calculate the size of subplots and again to calculate the
size of the figure, and then the final draw). There are some other issues,
which prevent inclusion in matplotlib (see discussion in link below), but it
works well for my purposes.

Best,
-Tony

Original post, with some discussion, can be found here:
http://www.mail-archive.com/matplotlib-devel@lists.sourceforge.net/msg06896.html

Note the code from the original post didn't work on some backends, so it's
probably best to use the code from the first link.

I think there are pros and cons, and I don't think the current design
is simply broken.
For example, it will be very distracting if the axes area changes
while you're doing some interactive stuff (e.g., panning). Anyhow I
admit that the default layout may not be optimal for figures with
multiple subplots, and there is a room for improvement.

There are a few approach you can take.

* If you're only interested in saved outputs, you may use savefig
with bbox_inches="tight". Note that this changes the size of figure.

* Use Tony's script to adjust the subplot params automatically.

* use axes_grid1 toolkit which enables you to change the axes
position on the fly. Check
http://www.mail-archive.com/matplotlib-users@lists.sourceforge.net/msg18743.html.
For current git master branch, check
examples/axes_grid/make_room_for_ylabel_using_axesgrid.py

Regards,

-JJ

···

On Fri, May 6, 2011 at 5:20 PM, Daniel Mader <danielstefanmader@...982...> wrote:

From many postings here I have learned that
this is the absolute intention, i.e. it is broken by design unless the
programmer takes care about this.

Hi Jae-Loon,

thanks for your comments! Of course I do agree that a figure layout
should not change in interactive mode. However, I don't see why this
should happen upon a panning action. A different case is when the
label or title font sizes are changed, but I was assuming this is
adjusted prior to the creation of the figure.

For the time being I am very happy with Tony's solution. It works nice
most of the time, only very complex figures take forever now to be
drawn.

The current behavior *looks* broken to any user who does not
understand the internals. And it's too likely that even simple figures
look horrible. I'd definitely vote for a more end-user friendly
solution (with end users I have scientific users in mind who generally
appreciate the beauty of the generated plots but who don't integrated
the library into some other application).

Best regards,
Daniel

2011/5/11 Jae-Joon Lee <lee.j.joon@...287...>:

···

On Fri, May 6, 2011 at 5:20 PM, Daniel Mader > <danielstefanmader@...982...> wrote:

From many postings here I have learned that
this is the absolute intention, i.e. it is broken by design unless the
programmer takes care about this.

I think there are pros and cons, and I don't think the current design
is simply broken.
For example, it will be very distracting if the axes area changes
while you're doing some interactive stuff (e.g., panning). Anyhow I
admit that the default layout may not be optimal for figures with
multiple subplots, and there is a room for improvement.

There are a few approach you can take.

* If you're only interested in saved outputs, you may use savefig
with bbox_inches="tight". Note that this changes the size of figure.

* Use Tony's script to adjust the subplot params automatically.

* use axes_grid1 toolkit which enables you to change the axes
position on the fly. Check
http://www.mail-archive.com/matplotlib-users@lists.sourceforge.net/msg18743.html.
For current git master branch, check
examples/axes_grid/make_room_for_ylabel_using_axesgrid.py

Regards,

-JJ

Hi Jae-Loon,

thanks for your comments! Of course I do agree that a figure layout
should not change in interactive mode. However, I don't see why this
should happen upon a panning action. A different case is when the
label or title font sizes are changed, but I was assuming this is
adjusted prior to the creation of the figure.

Since you said the current design is broken, I thought you want things
adjusted *whenever* a figure is updated.

So, I guess what you want is some functionality like what Tony's script does?
One of the reason that I was not very inclined to Tony's approach is
that it only works for subplots (and I guess it only works with
subplots with pure n x m grid. Correct me if I'm wrong). But maybe it
is better than nothing. I'll consider how things can be improved.

Regards,

-JJ

···

On Wed, May 11, 2011 at 5:03 PM, Daniel Mader <danielstefanmader@...982...> wrote:

For the time being I am very happy with Tony's solution. It works nice
most of the time, only very complex figures take forever now to be
drawn.

The current behavior *looks* broken to any user who does not
understand the internals. And it's too likely that even simple figures
look horrible. I'd definitely vote for a more end-user friendly
solution (with end users I have scientific users in mind who generally
appreciate the beauty of the generated plots but who don't integrated
the library into some other application).

Best regards,
Daniel

Hi again,

Hi Jae-Loon,

thanks for your comments! Of course I do agree that a figure layout
should not change in interactive mode. However, I don't see why this
should happen upon a panning action. A different case is when the
label or title font sizes are changed, but I was assuming this is
adjusted prior to the creation of the figure.

Since you said the current design is broken, I thought you want things
adjusted *whenever* a figure is updated.

So, I guess what you want is some functionality like what Tony's script does?
One of the reason that I was not very inclined to Tony's approach is
that it only works for subplots (and I guess it only works with
subplots with pure n x m grid. Correct me if I'm wrong). But maybe it
is better than nothing. I'll consider how things can be improved.

I do sense a match of ideas here :slight_smile: This is exactly what I am missing!
It is very good to hear that you are so open to suggestions and
possible improvements!

It is a great pleasure to work with Scipy/Matplotlib and interact with
the community!

Best regards,
Daniel

[Accidentally sent this reply privately the first time, natch.]

>> >> Hi Jae-Loon,
>> >>
>> >> thanks for your comments! Of course I do agree that a figure layout
>> >> should not change in interactive mode. However, I don't see why this
>> >> should happen upon a panning action. A different case is when the
>> >> label or title font sizes are changed, but I was assuming this is
>> >> adjusted prior to the creation of the figure.
>> >>
> >
> > Since you said the current design is broken, I thought you want things
> > adjusted *whenever* a figure is updated.
> >
> > So, I guess what you want is some functionality like what Tony's script does?
> > One of the reason that I was not very inclined to Tony's approach is
> > that it only works for subplots (and I guess it only works with
> > subplots with pure n x m grid. Correct me if I'm wrong). But maybe it
> > is better than nothing. I'll consider how things can be improved.

  One thing I've always wondered: is it fundamentally impossible to
change the fact that, in matplotlib, you cannot know how big a drawn
object will be until you actually draw it? When I was doing some
animation stuff a while back this caused me a lot of headache, for the
reasons Tony Yu mentioned: it means you have to draw everything
multiple times. It would really help if it were possible to specify
objects' parameters and get their sizes without drawing them.

-- Brendan Barnwell
"Do not follow where the path may lead. Go, instead, where there is no path, and leave a trail." --author unknown

···

On 2011-05-11 04:29, Jae-Joon Lee wrote:
> > On Wed, May 11, 2011 at 5:03 PM, Daniel Mader > > <danielstefanmader@...982...> wrote:

Most things, we do know the sizes of. It is my understanding that it is the text objects that is the unknown. If this could be solved, then a layout engine would be much more feasible. The problem is that even LaTeX has to re-render things multiple times to get this right for an arbitrary font. If we were to restrict ourselves to particular fonts and package those fonts with matplotlib, then we could have an internal table of size information for each glyph and compute it on the fly and lay everything out right. But, that would cause us to give up significant benefits for another benefit.

I think the pain of the bootstrapping/re-rendering approach could be reduced significantly if we could get various aspects of matplotlib figure building to be faster. Last time I checked, there is significant amount of processing time spent in calculating the ticks for the axes. Maybe if we focus some efforts in improving the efficiency of certain parts of matplotlib, maybe we could introduce a convenience function like the one earlier in this thread that some users can choose to use with only a slight penalty in speed. I personally would not want to make it default, but certainly would consider highly advertising such a function.

Just my two cents,
Ben Root

···

On Wed, May 11, 2011 at 12:47 PM, Brendan Barnwell <brenbarn@…1219…> wrote:

[Accidentally sent this reply privately the first time, natch.]

On 2011-05-11 04:29, Jae-Joon Lee wrote:

On Wed, May 11, 2011 at 5:03 PM, Daniel Mader > > > > <danielstefanmader@…982…> wrote:

Hi Jae-Loon,

thanks for your comments! Of course I do agree that a figure

layout

should not change in interactive mode. However, I don’t see

why this

should happen upon a panning action. A different case is when the

label or title font sizes are changed, but I was assuming this is

adjusted prior to the creation of the figure.

Since you said the current design is broken, I thought you want

things

adjusted whenever a figure is updated.

So, I guess what you want is some functionality like what Tony’s

script does?

One of the reason that I was not very inclined to Tony’s approach is

that it only works for subplots (and I guess it only works with

subplots with pure n x m grid. Correct me if I’m wrong). But maybe it

is better than nothing. I’ll consider how things can be improved.

One thing I’ve always wondered: is it fundamentally impossible to

change the fact that, in matplotlib, you cannot know how big a drawn

object will be until you actually draw it? When I was doing some

animation stuff a while back this caused me a lot of headache, for the

reasons Tony Yu mentioned: it means you have to draw everything

multiple times. It would really help if it were possible to specify

objects’ parameters and get their sizes without drawing them.

– Brendan Barnwell

"Do not follow where the path may lead. Go, instead, where there is no

path, and leave a trail." --author unknown

I suppose a compromise would be to have that internal table for a fixed set of fonts, and if the user asks for a font that’s not shipped with matplotlib, then they fall back to the current (presumably slower) method. Would probably complicate things in the layout code, though.

Justin

···

On Wed, May 11, 2011 at 1:59 PM, Benjamin Root <ben.root@…3146…4…> wrote:


Most things, we do know the sizes of. It is my understanding that it is the text objects that is the unknown. If this could be solved, then a layout engine would be much more feasible. The problem is that even LaTeX has to re-render things multiple times to get this right for an arbitrary font. If we were to restrict ourselves to particular fonts and package those fonts with matplotlib, then we could have an internal table of size information for each glyph and compute it on the fly and lay everything out right. But, that would cause us to give up significant benefits for another benefit.

Perhaps there could be three options:

1. Manual mode: current behavior
2. Database mode: uses a list of known fonts. When a font not found
in the database is used, it falls back to manual mode.
3. Automatic mode: uses a list of known fonts. When a font not found
in the database is used, it renders the text alone in an invisible
figure to calculate the space needed, then uses that information to
set the margins. Alternatively, create a temporary mini font database
just for the characters needed. The former approach may be faster,
but the latter may be easier to program since it could share a lot of
code with the database.

There could also be a function to scan a particular font and add to
the database (there would probably be a separate user database in your
matplotlib configuration directory that this would use, as well as
probably caching the measurements from text used in automatic mode for
future versions of the figure).

-Todd

···

On Wed, May 11, 2011 at 1:59 PM, Benjamin Root <ben.root@...1304...> wrote:

On Wed, May 11, 2011 at 12:47 PM, Brendan Barnwell <brenbarn@...1219...> > wrote:

   One thing I&#39;ve always wondered: is it fundamentally impossible to

change the fact that, in matplotlib, you cannot know how big a drawn
object will be until you actually draw it? When I was doing some
animation stuff a while back this caused me a lot of headache, for the
reasons Tony Yu mentioned: it means you have to draw everything
multiple times. It would really help if it were possible to specify
objects' parameters and get their sizes without drawing them.

-- Brendan Barnwell
"Do not follow where the path may lead. Go, instead, where there is no
path, and leave a trail." --author unknown

Most things, we do know the sizes of. It is my understanding that it is the
text objects that is the unknown. If this could be solved, then a layout
engine would be much more feasible. The problem is that even LaTeX has to
re-render things multiple times to get this right for an arbitrary font. If
we were to restrict ourselves to particular fonts and package those fonts
with matplotlib, then we could have an internal table of size information
for each glyph and compute it on the fly and lay everything out right. But,
that would cause us to give up significant benefits for another benefit.

I think the pain of the bootstrapping/re-rendering approach could be reduced
significantly if we could get various aspects of matplotlib figure building
to be faster. Last time I checked, there is significant amount of
processing time spent in calculating the ticks for the axes. Maybe if we
focus some efforts in improving the efficiency of certain parts of
matplotlib, maybe we could introduce a convenience function like the one
earlier in this thread that some users can choose to use with only a slight
penalty in speed. I personally would not want to make it default, but
certainly would consider highly advertising such a function.

Just my two cents,
Ben Root

That might be a possible direction. Obviously, any route taken will have to be well thought-out and designed. What is great about moving over to git is that the user community can easily experiment on larger changes to the code-base, and make it easier for others to test out experimental designs and collaborate. I encourage those in this thread to make a fork of matplotlib on github and experiment with some of these ideas and we all can play around with some of these parts.

As a further bit of information, I believe that there is an old project that attempted a layout engine for matplotlib (https://github.com/matplotlib/mplsizer). I have never used it, nor do I have any idea if it still works, but it may be an interesting codebase to start from.

As a further comment about a database of text size information. An interesting complication I just noticed are fonts that allow certain combinations of characters to overlap a bit. For example, right now I noticed that using Gils Sans in LibreOffice that the word “Tracking” has the ‘r’ in with the ‘T’. Calculating the amount of space a particular set of characters might take up may not be very straight-forward.

Just another 2 cents,
Ben Root

···

On Wed, May 11, 2011 at 1:43 PM, todd rme <toddrme2178@…287…> wrote:

On Wed, May 11, 2011 at 1:59 PM, Benjamin Root <ben.root@…1304…> wrote:

On Wed, May 11, 2011 at 12:47 PM, Brendan Barnwell <brenbarn@…1219…> > > > wrote:

   One thing I've always wondered: is it fundamentally impossible to

change the fact that, in matplotlib, you cannot know how big a drawn

object will be until you actually draw it? When I was doing some

animation stuff a while back this caused me a lot of headache, for the

reasons Tony Yu mentioned: it means you have to draw everything

multiple times. It would really help if it were possible to specify

objects’ parameters and get their sizes without drawing them.

– Brendan Barnwell

"Do not follow where the path may lead. Go, instead, where there is no

path, and leave a trail." --author unknown

Most things, we do know the sizes of. It is my understanding that it is the

text objects that is the unknown. If this could be solved, then a layout

engine would be much more feasible. The problem is that even LaTeX has to

re-render things multiple times to get this right for an arbitrary font. If

we were to restrict ourselves to particular fonts and package those fonts

with matplotlib, then we could have an internal table of size information

for each glyph and compute it on the fly and lay everything out right. But,

that would cause us to give up significant benefits for another benefit.

I think the pain of the bootstrapping/re-rendering approach could be reduced

significantly if we could get various aspects of matplotlib figure building

to be faster. Last time I checked, there is significant amount of

processing time spent in calculating the ticks for the axes. Maybe if we

focus some efforts in improving the efficiency of certain parts of

matplotlib, maybe we could introduce a convenience function like the one

earlier in this thread that some users can choose to use with only a slight

penalty in speed. I personally would not want to make it default, but

certainly would consider highly advertising such a function.

Just my two cents,

Ben Root

Perhaps there could be three options:

  1. Manual mode: current behavior

  2. Database mode: uses a list of known fonts. When a font not found

in the database is used, it falls back to manual mode.

  1. Automatic mode: uses a list of known fonts. When a font not found

in the database is used, it renders the text alone in an invisible

figure to calculate the space needed, then uses that information to

set the margins. Alternatively, create a temporary mini font database

just for the characters needed. The former approach may be faster,

but the latter may be easier to program since it could share a lot of

code with the database.

There could also be a function to scan a particular font and add to

the database (there would probably be a separate user database in your

matplotlib configuration directory that this would use, as well as

probably caching the measurements from text used in automatic mode for

future versions of the figure).

-Todd

     >
     >> One thing I've always wondered: is it fundamentally
    impossible to
     >> change the fact that, in matplotlib, you cannot know how big a drawn
     >> object will be until you actually draw it? When I was doing some
     >> animation stuff a while back this caused me a lot of headache,
    for the
     >> reasons Tony Yu mentioned: it means you have to draw everything
     >> multiple times. It would really help if it were possible to specify
     >> objects' parameters and get their sizes without drawing them.
     >>
     >> -- Brendan Barnwell
     >> "Do not follow where the path may lead. Go, instead, where there
    is no
     >> path, and leave a trail." --author unknown
     >>
     >
     > Most things, we do know the sizes of. It is my understanding
    that it is the
     > text objects that is the unknown. If this could be solved, then
    a layout
     > engine would be much more feasible. The problem is that even
    LaTeX has to
     > re-render things multiple times to get this right for an
    arbitrary font. If
     > we were to restrict ourselves to particular fonts and package
    those fonts
     > with matplotlib, then we could have an internal table of size
    information
     > for each glyph and compute it on the fly and lay everything out
    right. But,
     > that would cause us to give up significant benefits for another
    benefit.
     >
     > I think the pain of the bootstrapping/re-rendering approach could
    be reduced
     > significantly if we could get various aspects of matplotlib
    figure building
     > to be faster. Last time I checked, there is significant amount of
     > processing time spent in calculating the ticks for the axes.
    Maybe if we
     > focus some efforts in improving the efficiency of certain parts of
     > matplotlib, maybe we could introduce a convenience function like
    the one
     > earlier in this thread that some users can choose to use with
    only a slight
     > penalty in speed. I personally would not want to make it
    default, but
     > certainly would consider highly advertising such a function.
     >
     > Just my two cents,
     > Ben Root

    Perhaps there could be three options:

    1. Manual mode: current behavior
    2. Database mode: uses a list of known fonts. When a font not found
    in the database is used, it falls back to manual mode.
    3. Automatic mode: uses a list of known fonts. When a font not found
    in the database is used, it renders the text alone in an invisible
    figure to calculate the space needed, then uses that information to
    set the margins. Alternatively, create a temporary mini font database
    just for the characters needed. The former approach may be faster,
    but the latter may be easier to program since it could share a lot of
    code with the database.

    There could also be a function to scan a particular font and add to
    the database (there would probably be a separate user database in your
    matplotlib configuration directory that this would use, as well as
    probably caching the measurements from text used in automatic mode for
    future versions of the figure).

    -Todd

That might be a possible direction. Obviously, any route taken will
have to be well thought-out and designed. What is great about moving
over to git is that the user community can easily experiment on larger
changes to the code-base, and make it easier for others to test out
experimental designs and collaborate. I encourage those in this thread
to make a fork of matplotlib on github and experiment with some of these
ideas and we all can play around with some of these parts.

As a further bit of information, I believe that there is an old project
that attempted a layout engine for matplotlib
(https://github.com/matplotlib/mplsizer). I have never used it, nor do I
have any idea if it still works, but it may be an interesting codebase
to start from.

As a further comment about a database of text size information. An
interesting complication I just noticed are fonts that allow certain
combinations of characters to overlap a bit. For example, right now I
noticed that using Gils Sans in LibreOffice that the word "Tracking" has
the 'r' in with the 'T'. Calculating the amount of space a particular
set of characters might take up may not be very straight-forward.

The calculation doesn't have to be perfect, it just has to be good enough for layout purposes. If one were to ignore kerning, the predicted width of a text string would be slightly larger than the actual size. I don't think this would cause serious layout problems.

But--is doing the calculation this way actually much faster than letting the renderer do it? Enough to be worth building and maintaining all the extra machinery?

Eric

···

On 05/11/2011 09:11 AM, Benjamin Root wrote:

On Wed, May 11, 2011 at 1:43 PM, todd rme <toddrme2178@…287… > <mailto:toddrme2178@…287…>> wrote:
    On Wed, May 11, 2011 at 1:59 PM, Benjamin Root <ben.root@…1304… > <mailto:ben.root@…1304…>> wrote:
     > On Wed, May 11, 2011 at 12:47 PM, Brendan Barnwell > <brenbarn@…1219… <mailto:brenbarn@…1219…>> > > wrote:

Just another 2 cents,
Ben Root

------------------------------------------------------------------------------
Achieve unprecedented app performance and reliability
What every C/C++ and Fortran developer should know.
Learn how Intel has extended the reach of its next-generation tools
to help boost performance applications - inlcuding clusters.
http://p.sf.net/sfu/intel-dev2devmay

_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users

Kerning, that’s the term. I couldn’t think of it…

As for the issue about is it worth it to have all of this extra machinery, that was pretty much my point of the email. If someone wants to see if they can make an elegant solution that works well and is easy to maintain, then I would have no problem including it into the codebase. However, I am very doubtful of that and I would rather see effort in improving the efficiency of various parts of matplotlib so that various brute-force approaches to layout will have less time penalty. Plus, it wouldn’t hurt to have faster graphics generation for the rest of us, either!

Ben Root

···

On Wed, May 11, 2011 at 4:31 PM, Eric Firing <efiring@…83…202…> wrote:

On 05/11/2011 09:11 AM, Benjamin Root wrote:

On Wed, May 11, 2011 at 1:43 PM, todd rme <toddrme2178@…287… > > mailto:toddrme2178@...287...> wrote:

On Wed, May 11, 2011 at 1:59 PM, Benjamin Root <ben.root@...1304... > >     <mailto:ben.root@...1304...>> wrote:
 >
 >
 > On Wed, May 11, 2011 at 12:47 PM, Brendan Barnwell > >     <brenbarn@...1836...219... <mailto:brenbarn@...3602...19...>> > >      > wrote:
 >>        One thing I've always wondered: is it fundamentally
impossible to
 >> change the fact that, in matplotlib, you cannot know how big a drawn
 >> object will be until you actually draw it?  When I was doing some
 >> animation stuff a while back this caused me a lot of headache,
for the
 >> reasons Tony Yu mentioned: it means you have to draw everything
 >> multiple times.  It would really help if it were possible to specify
 >> objects' parameters and get their sizes without drawing them.
 >>
 >> -- Brendan Barnwell
 >> "Do not follow where the path may lead. Go, instead, where there
is no
 >> path, and leave a trail." --author unknown
 >>
 >
 > Most things, we do know the sizes of.  It is my understanding
that it is the
 > text objects that is the unknown.  If this could be solved, then
a layout
 > engine would be much more feasible.  The problem is that even
LaTeX has to
 > re-render things multiple times to get this right for an
arbitrary font.  If
 > we were to restrict ourselves to particular fonts and package
those fonts
 > with matplotlib, then we could have an internal table of size
information
 > for each glyph and compute it on the fly and lay everything out
right.  But,
 > that would cause us to give up significant benefits for another
benefit.
 >
 > I think the pain of the bootstrapping/re-rendering approach could
be reduced
 > significantly if we could get various aspects of matplotlib
figure building
 > to be faster.  Last time I checked, there is significant amount of
 > processing time spent in calculating the ticks for the axes.
Maybe if we
 > focus some efforts in improving the efficiency of certain parts of
 > matplotlib, maybe we could introduce a convenience function like
the one
 > earlier in this thread that some users can choose to use with
only a slight
 > penalty in speed.  I personally would not want to make it
default, but
 > certainly would consider highly advertising such a function.
 >
 > Just my two cents,
 > Ben Root
Perhaps there could be three options:
1. Manual mode: current behavior
2. Database mode: uses a list of known fonts.  When a font not found
in the database is used, it falls back to manual mode.
3. Automatic mode: uses a list of known fonts.  When a font not found
in the database is used, it renders the text alone in an invisible
figure to calculate the space needed, then uses that information to
set the margins.  Alternatively, create a temporary mini font database
just for the characters needed.  The former approach may be faster,
but the latter may be easier to program since it could share a lot of
code with the database.
There could also be a function to scan a particular font and add to
the database (there would probably be a separate user database in your
matplotlib configuration directory that this would use, as well as
probably caching the measurements from text used in automatic mode for
future versions of the figure).
-Todd

That might be a possible direction. Obviously, any route taken will

have to be well thought-out and designed. What is great about moving

over to git is that the user community can easily experiment on larger

changes to the code-base, and make it easier for others to test out

experimental designs and collaborate. I encourage those in this thread

to make a fork of matplotlib on github and experiment with some of these

ideas and we all can play around with some of these parts.

As a further bit of information, I believe that there is an old project

that attempted a layout engine for matplotlib

(https://github.com/matplotlib/mplsizer). I have never used it, nor do I

have any idea if it still works, but it may be an interesting codebase

to start from.

As a further comment about a database of text size information. An

interesting complication I just noticed are fonts that allow certain

combinations of characters to overlap a bit. For example, right now I

noticed that using Gils Sans in LibreOffice that the word “Tracking” has

the ‘r’ in with the ‘T’. Calculating the amount of space a particular

set of characters might take up may not be very straight-forward.

The calculation doesn’t have to be perfect, it just has to be good

enough for layout purposes. If one were to ignore kerning, the

predicted width of a text string would be slightly larger than the

actual size. I don’t think this would cause serious layout problems.

But–is doing the calculation this way actually much faster than letting

the renderer do it? Enough to be worth building and maintaining all the

extra machinery?

Eric

Most things, we do know the sizes of. It is my understanding that it is the
text objects that is the unknown. If this could be solved, then a layout
engine would be much more feasible.

I doubt it. As far as I know, the main reason that things needed to be
drawn is because the location and size of some artist depends on
location and size of other artists.
Unfortunately, with current matplotlib code, most of these things are
determined inside the "draw" method. Therefore, we need to separate
out those things out from the draw method.

Another option, which I think is more feasible, is to implement a
BBoxRenderer which does not draw anything but only update the size and
location of artists.

Regards,

-JJ

···

On Thu, May 12, 2011 at 2:59 AM, Benjamin Root <ben.root@...1304...> wrote:

The problem is that even LaTeX has to
re-render things multiple times to get this right for an arbitrary font. If
we were to restrict ourselves to particular fonts and package those fonts
with matplotlib, then we could have an internal table of size information
for each glyph and compute it on the fly and lay everything out right. But,
that would cause us to give up significant benefits for another benefit.

Attached is a modified version of Tony's script.

* no drawing is necessary
* support subplots that span multiple rows/columns

Please test it and let me know of any problem.

I'm planning to push these functionality into matplolib after some
refactoring (e.g., it would be good to have pyplot.tight_layout).

Regards,

-JJ

tight_layout.py (8.96 KB)

···

On Wed, May 11, 2011 at 8:50 PM, Daniel Mader <danielstefanmader@...982...> wrote:

Hi again,

Hi Jae-Loon,

thanks for your comments! Of course I do agree that a figure layout
should not change in interactive mode. However, I don't see why this
should happen upon a panning action. A different case is when the
label or title font sizes are changed, but I was assuming this is
adjusted prior to the creation of the figure.

Since you said the current design is broken, I thought you want things
adjusted *whenever* a figure is updated.

So, I guess what you want is some functionality like what Tony's script does?
One of the reason that I was not very inclined to Tony's approach is
that it only works for subplots (and I guess it only works with
subplots with pure n x m grid. Correct me if I'm wrong). But maybe it
is better than nothing. I'll consider how things can be improved.

I do sense a match of ideas here :slight_smile: This is exactly what I am missing!
It is very good to hear that you are so open to suggestions and
possible improvements!

It is a great pleasure to work with Scipy/Matplotlib and interact with
the community!

Best regards,
Daniel