3

I would like to draw a plot with a logarithmic y axis and a linear x axis on a square plot area in matplotlib. I can draw linear-linear as well as log-log plots on squares, but the method I use, Axes.set_aspect(...), is not implemented for log-linear plots. Is there a good workaround?


linear-linear plot on a square:

from pylab import *
x = linspace(1,10,1000)
y = sin(x)**2+0.5
plot (x,y)
ax = gca()
data_aspect = ax.get_data_ratio()
ax.set_aspect(1./data_aspect)
show()

Square linear-linear plot


log-log plot on a square:

from pylab import *
x = linspace(1,10,1000)
y = sin(x)**2+0.5
plot (x,y)
ax = gca()
ax.set_yscale("log")
ax.set_xscale("log")
xmin,xmax = ax.get_xbound()
ymin,ymax = ax.get_ybound()
data_aspect = (log(ymax)-log(ymin))/(log(xmax)-log(xmin))
ax.set_aspect(1./data_aspect)
show()

square log-log plot


But when I try this with a log-linear plot, I do not get the square area, but a warning

from pylab import *
x = linspace(1,10,1000)
y = sin(x)**2+0.5
plot (x,y)
ax = gca()
ax.set_yscale("log")
xmin,xmax = ax.get_xbound()
ymin,ymax = ax.get_ybound()
data_aspect = (log(ymax)-log(ymin))/(xmax-xmin)
ax.set_aspect(1./data_aspect)
show()

yielding the warning:

axes.py:1173: UserWarning: aspect is not supported for Axes with xscale=linear, yscale=log

not-square log-linear plot


Is there a good way of achieving square log-linear plots despite the lack support in Axes.set_aspect?

1 Answer 1

6

Well, there is a sort of a workaround. The actual axis area (the area where the plot is, not including external ticks &c) can be resized to any size you want it to have.

You may use the ax.set_position to set the relative (to the figure) size and position of the plot. In order to use it in your case we need a bit of maths:

from pylab import *

x = linspace(1,10,1000)
y = sin(x)**2+0.5
plot (x,y)
ax = gca()
ax.set_yscale("log")

# now get the figure size in real coordinates:
fig  = gcf()
fwidth = fig.get_figwidth()
fheight = fig.get_figheight()

# get the axis size and position in relative coordinates
# this gives a BBox object
bb = ax.get_position()

# calculate them into real world coordinates
axwidth = fwidth * (bb.x1 - bb.x0)
axheight = fheight * (bb.y1 - bb.y0)

# if the axis is wider than tall, then it has to be narrowe
if axwidth > axheight:
    # calculate the narrowing relative to the figure
    narrow_by = (axwidth - axheight) / fwidth
    # move bounding box edges inwards the same amount to give the correct width
    bb.x0 += narrow_by / 2
    bb.x1 -= narrow_by / 2
# else if the axis is taller than wide, make it vertically smaller
# works the same as above
elif axheight > axwidth:
    shrink_by = (axheight - axwidth) / fheight
    bb.y0 += shrink_by / 2
    bb.y1 -= shrink_by / 2

ax.set_position(bb)

show()

A slight stylistic comment is that import pylab is not usually used. The lore goes:

import matplotlib.pyplot as plt

pylab as an odd mixture of numpy and matplotlib imports created to make interactive IPython use easier. (I use it, too.)

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.