I have for quite some time noticed that some of the spirograph images were plotted smaller than I expected. They would be towards the bottom of the figure with a lot of empty background above them. I figured that somehow Matplotlib was not handling the calls to autoscale()
correctly. And, the axes somehow kept the plot limits from the previous image. Or some such thing.
I figured if I wanted to save one of these kinds of image that when I recreated it with my repeat
route that the image would be displayed as I expected it to be—filling out the plot area.
Putting That to the Test
I recently had just such an image I wished to save. So I finally had the chance to test my hypothesis.
Here’s what it looked like when I first generated the image.
So I set up the data in the repeats
module. Then I made sure that this was the first image I plotted after starting the development server. To my surprise, no change.
So I decided to do the repeat but without plotting any background on the image.
Now that’s what I expect the curve to look like. Nicely filling out the area available in the plot’s axes.
Background Image Issue?
Would appear the problem is somehow caused by the way I add the background.
The function called to generate the background is as follows.
def set_bg(axb):
abg = None
baxt = None
if g.use_bb2:
if not g.do_rpt or not g.abg:
baxt, abg = blotch_bg_2(axb, extent=(0, 1, 0, 1), dim=g.bb2_dim,
cmap=g.bg_cmap, alpha=g.bg_lpha, transform=axb.transAxes, zorder=1, aspect='auto')
else:
baxt, abg = blotch_bg_2(axb, extent=(0, 1, 0, 1), abg=g.abg, dim=g.bb2_dim,
cmap=g.bg_cmap, alpha=g.bg_lpha, transform=axb.transAxes, zorder=1, aspect='auto')
return baxt, abg
I figured by using the transAxes
transform with the extent
parameter set as shown, that I was setting the background to cover the whole of the axes’ area. I assumed the transform would convert the extent
provided to the appropriate data coordinates for imshow()
to use. I am now guessing that is not the case.
For reference, here’s the blotch_bg_2 function.
def blotch_bg_2(axb, extent, abg=None, dim=5, **kwargs):
if abg is not None:
A = abg
else:
# A = np.random.rand(dim, dim)
A = rng.random((dim, dim))
c = axb.imshow(A, extent=extent, interpolation='bilinear', **kwargs)
axb.autoscale()
return c, A
I tried a variety of things but nothing really worked. After re-reading the imshow documentation, I finally decided to get the x
and y
limits for the axes and pass those in the function call.
def set_bg(axb):
abg = None
baxt = None
if g.use_bb2:
axb.autoscale()
bxmin, bxmax = axb.get_xlim()
bymin, bymax = axb.get_ylim()
if not g.do_rpt or not g.abg:
baxt, abg = blotch_bg_2(axb, extent=(bxmin, bxmax, bymin, bymax), dim=g.bb2_dim,
cmap=g.bg_cmap, alpha=g.bg_lpha, zorder=1, aspect='auto')
else:
baxt, abg = blotch_bg_2(axb, extent=(bxmin, bxmax, bymin, bymax), abg=g.abg,
dim=g.bb2_dim, cmap=g.bg_cmap, alpha=g.bg_lpha, zorder=1, aspect='auto')
axb.autoscale()
return baxt, abg
And, bingo!
Happily, Done
I don’t really understand why the use of the transform
parameter failed to work. Likely imshow()
ignored it as I can’t find any reference for its use in the documentation. So it simply treated the extent as data coordinates and plotted the background accordingly.
Given the plot limits for the above curve before adding the background were: -1.5930286154874118, 1.5933027977633585, -0.387623702605103, 0.3876237026051031
. Then by specifying the extent as (0, 1, 0, 1)
the upper y-axis
limit was moved to 1.0
, shrinking the curve into the bottom half of the figure.
I had mentally been trying to sort this issue every time a shrunken curve was generated. With this refactoring I am no longer getting any such images produced by the app. So, a rather short post; but one I am extremely happy to have finally been able to write.
Resources
- matplotlib.pyplot.imshow