Problem with text bounding box

Recently, I switched from matplotlib 0.99 to 1.0.1 and unfortunately discovered
that my text scaling script stopped working properly. The script scales the given text
to fit into the current figure.

A quick example of what I'm doing (works in 0.99, but not in 1.0.1 and 1.1.1rc):
import matplotlib.pyplot as plt
plt.ion()
fig = plt.figure(1, (6,8), dpi=72)
fig.add_axes([0,0,1,1])
txt1 = plt.text(0.5,0.5,'foobar',horizontalalignment='center',verticalalignment='center')
plt.draw()
# compute width of figure in points and divide by txt1 bounding box width
sf1 = 6*72./txt1.cached.items()[0][1][1][0][1][0]
txt1.set_size(txt1.get_size()*sf1)
plt.draw()

The problem is related to the fact that starting from mpl 1.0.1, the txt1.cached dictionary contains information of all text objects present rather than only of the specific object.
I guess this behavior is intended, however this way it is rather complicated to derive the bounding
box of the specific text object without cycling over the whole dictionary.

Is there a different way to achieve a fitted text object?

Thanks,
br Jakob

Recently, I switched from matplotlib 0.99 to 1.0.1 and unfortunately discovered
that my text scaling script stopped working properly. The script scales the given text
to fit into the current figure.

A quick example of what I'm doing (works in 0.99, but not in 1.0.1 and 1.1.1rc):
import matplotlib.pyplot as plt
plt.ion()
fig = plt.figure(1, (6,8), dpi=72)
fig.add_axes([0,0,1,1])
txt1 = plt.text(0.5,0.5,'foobar',horizontalalignment='center',verticalalignment='center')
plt.draw()
# compute width of figure in points and divide by txt1 bounding box width
sf1 = 6*72./txt1.cached.items()[0][1][1][0][1][0]
txt1.set_size(txt1.get_size()*sf1)
plt.draw()

The problem is related to the fact that starting from mpl 1.0.1, the txt1.cached dictionary contains
information of all text objects present rather than only of the specific object.
I guess this behavior is intended, however this way it is rather complicated to derive the bounding
box of the specific text object without cycling over the whole dictionary.

It looks like you can either use the _get_layout() method (which requires that you specify the renderer), or, if you know the text object will be among the last 50 for which _get_layout() has been called, you can use txt1.cached[txt1.get_prop_typ()].

Is there a different way to achieve a fitted text object?

Not that I know of; but someone else may have a suggestion.

Eric

···

On 2012/09/03 1:38 AM, Jakob Gager wrote:

Thanks,
br Jakob

------------------------------------------------------------------------------
Live Security Virtual Conference
Exclusive live event will cover all the ways today's security and
threat landscape has changed and how IT managers can respond. Discussions
will include endpoint security, mobile security and the latest in malware
threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users

Many thanks for the quick and valuable return. I now use the _get_layout() method and
it works like a charm :slight_smile:

Just replaced:
sf1 = 6*72./txt1.cached.items()[0][1][1][0][1][0]
with:
sf1 = 6*72./txt1._get_layout('GTKAgg')[1][0][1][0]

br
Jakob

···

On 09/03/2012 08:57 PM, Eric Firing wrote:

It looks like you can either use the _get_layout() method (which
requires that you specify the renderer), or, if you know the text object
will be among the last 50 for which _get_layout() has been called, you
can use txt1.cached[txt1.get_prop_typ()].

Is there a different way to achieve a fitted text object?

Not that I know of; but someone else may have a suggestion.

Eric

It looks like you can either use the _get_layout() method (which
requires that you specify the renderer), or, if you know the text object
will be among the last 50 for which _get_layout() has been called, you
can use txt1.cached[txt1.get_prop_typ()].

Is there a different way to achieve a fitted text object?

Not that I know of; but someone else may have a suggestion.

Eric

Many thanks for the quick and valuable return. I now use the _get_layout() method and
it works like a charm :slight_smile:

Just replaced:
sf1 = 6*72./txt1.cached.items()[0][1][1][0][1][0]
with:
sf1 = 6*72./txt1._get_layout('GTKAgg')[1][0][1][0]

Jakob,

What is actually happening here is that the first two lines of _get_layout() are equivalent to the second method I suggested (that's where I got the idea for that method), and the renderer argument is never being used. This is good, because the renderer argument would have to be a renderer instance, not the string name of a backend.

There is also the caution that the leading underscore means _get_layout() is intended for internal mpl use only, and subject to change without notice. So, with some future version of mpl, you may need to change your code again.

Eric

···

On 2012/09/03 8:33 PM, Jakob Gager wrote:

On 09/03/2012 08:57 PM, Eric Firing wrote:

br
Jakob

------------------------------------------------------------------------------
Live Security Virtual Conference
Exclusive live event will cover all the ways today's security and
threat landscape has changed and how IT managers can respond. Discussions
will include endpoint security, mobile security and the latest in malware
threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users

Hi Eric,

does this mean you would suggest to use txt1.cached[txt1.get_prop_tup()] to be on the save side for future versions? I'm aware of the leading underscore notation, however, the txt.cached dictionary has changed as well (without leading underscore and notice?), therefore, slight modifications in the scrips
cannot be precluded anyway.

Regarding the renderer argument...
I first thought about passing a renderer instance to the _get_layout method, but as I had no clue where to get this instance from. So I simply tried with the backend name and luckly it worked :).

Thanks again, and have a nice day!
Jakob

···

On 09/04/2012 09:13 AM, Eric Firing wrote:

On 2012/09/03 8:33 PM, Jakob Gager wrote:

On 09/03/2012 08:57 PM, Eric Firing wrote:

It looks like you can either use the _get_layout() method (which
requires that you specify the renderer), or, if you know the text object
will be among the last 50 for which _get_layout() has been called, you
can use txt1.cached[txt1.get_prop_typ()].

Eric

Many thanks for the quick and valuable return. I now use the _get_layout() method and
it works like a charm :slight_smile:

Just replaced:
sf1 = 6*72./txt1.cached.items()[0][1][1][0][1][0]
with:
sf1 = 6*72./txt1._get_layout('GTKAgg')[1][0][1][0]

Jakob,

What is actually happening here is that the first two lines of
_get_layout() are equivalent to the second method I suggested (that's
where I got the idea for that method), and the renderer argument is
never being used. This is good, because the renderer argument would have
to be a renderer instance, not the string name of a backend.

There is also the caution that the leading underscore means
_get_layout() is intended for internal mpl use only, and subject to
change without notice. So, with some future version of mpl, you may need
to change your code again.

Eric

It looks like you can either use the _get_layout() method (which
requires that you specify the renderer), or, if you know the text object
will be among the last 50 for which _get_layout() has been called, you
can use txt1.cached[txt1.get_prop_typ()].

Eric

Many thanks for the quick and valuable return. I now use the _get_layout() method and
it works like a charm :slight_smile:

Just replaced:
sf1 = 6*72./txt1.cached.items()[0][1][1][0][1][0]
with:
sf1 = 6*72./txt1._get_layout('GTKAgg')[1][0][1][0]

Jakob,

What is actually happening here is that the first two lines of
_get_layout() are equivalent to the second method I suggested (that's
where I got the idea for that method), and the renderer argument is
never being used. This is good, because the renderer argument would have
to be a renderer instance, not the string name of a backend.

There is also the caution that the leading underscore means
_get_layout() is intended for internal mpl use only, and subject to
change without notice. So, with some future version of mpl, you may need
to change your code again.

Eric

Hi Eric,

does this mean you would suggest to use txt1.cached[txt1.get_prop_tup()] to be on the save side for
future versions? I'm aware of the leading underscore notation, however, the txt.cached dictionary has
changed as well (without leading underscore and notice?), therefore, slight modifications in the scrips
cannot be precluded anyway.

You are right; although it lacks the underscore, I doubt the "cached" attribute and the "get_prop_tup()" method were intended for anything but internal use. There is no safe solution!

Regarding the renderer argument...
I first thought about passing a renderer instance to the _get_layout method, but as I had no clue where
to get this instance from. So I simply tried with the backend name and luckly it worked :).

That's the advantage of the txt1.cached[] approach; it doesn't require you to supply a bogus but unused argument. It's probably what I would pick.

In any case, I'm glad you are back in business.

Eric

···

On 2012/09/03 9:36 PM, Jakob Gager wrote:

On 09/04/2012 09:13 AM, Eric Firing wrote:

On 2012/09/03 8:33 PM, Jakob Gager wrote:

On 09/03/2012 08:57 PM, Eric Firing wrote:

Thanks again, and have a nice day!
Jakob

------------------------------------------------------------------------------
Live Security Virtual Conference
Exclusive live event will cover all the ways today's security and
threat landscape has changed and how IT managers can respond. Discussions
will include endpoint security, mobile security and the latest in malware
threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users