0

The question is bettered explained with examples. Let's say below is a figure I tried to plot: in matlab

So the figure region is square in shape, and there are axis labels explaining the meaning of the values. In MATLAB the code is simple and works as expected.

t = linspace(0, 2*pi, 101);
y = sin(t);

figure(1)
h = gcf;
set(h,'PaperUnits','inches');
set(h,'PaperSize',[3.5 3.5]);

plot(t, y)
xlim([0, 2*pi])
ylim([-1.1, 1.1])
xlabel('Time (s)')
ylabel('Voltage (V)')
axis('square')

Now let's work with Python and Matplotlib. The code is below:

from numpy import *
from matplotlib import pyplot as plt

t = linspace(0, 2*pi, 101)
y = sin(t)

plt.figure(figsize = (3.5, 3.5))
plt.plot(t, y)
plt.xlim(0, 2*pi)
plt.ylim(-1.1, 1.1)
plt.xlabel('Time (s)')
plt.ylabel('Voltage (V)')
plt.axis('equal') # square / tight
plt.show()

It does not work, see the first row of the figure below, where I tried three options of the axis command ('equal', 'square' and 'tight'). I wondered if this is due to the order of axis() and the xlim/ylim, they do affect the result, yet still I don't have what I want. Python I found this really confusing to understand and frustrating to use. The relative position of the curve and axis seems go haywire. I did extensive research on stackoverflow, but couldn't find the answer. It appears to me adding axis labels would compress the canvas region, but it really should not, because the label is just an addon to a figure, and they should have separate space allocations.

Taozi
  • 373
  • 5
  • 13

2 Answers2

0

It doesn't explain the figures you obtain but here is one way to achieve square axes with the right axes limits. In this example, I just calculate the axes aspect ratio using the x and y range:

plt.figure()
ax = plt.axes()
ax.plot(t, y)
xrange = (0, 2*pi)
yrange = (-1.1, 1.1)
plt.xlim(xrange)
plt.ylim(yrange)
plt.xlabel('Time (s)')
plt.ylabel('Voltage (V)')
ax.set_aspect((xrange[1]-xrange[0])/(yrange[1]-yrange[0]))
plt.show()

Another method is to create a square figure and square axes:

plt.figure(figsize = (5, 5))
ax = plt.axes([0.15, 0.15, 0.7, 0.7])
ax.plot(t, y)
plt.xlim(0, 2*pi)
plt.ylim(-1.1, 1.1)
plt.xlabel('Time (s)')
plt.ylabel('Voltage (V)')
plt.show()

enter image description here

Julien Spronck
  • 15,069
  • 4
  • 47
  • 55
  • Thank you for your reply. I experimented with your answer, the first one leaves wide blank region in the figure (and the saved image file), the second method cuts off part of the axis labels. So still no solution. BTW, I could't find much justification for matplotlb's exposure of things like ax.set_aspect, bbox_inches in savefig, tight_layout so on and so force, it's like you have to understand food science to eat. – Taozi Sep 11 '16 at 20:29
  • strange ... i guess we don't have the same version of matplotlib because both methods work fine for me and give the same result. – Julien Spronck Sep 11 '16 at 20:37
  • Mine is 2.0.0b1, what's yours? – Taozi Sep 11 '16 at 20:41
0

I do not have a computer at hand right now but it seems this answer might work: https://stackoverflow.com/a/7968690/2768172 Another solution might be to add the axis with a fixed size manually with: ax=fig.add_axes(bottom, left, width, height). If width and height are the same the axis should be squared.

Community
  • 1
  • 1
pathoren
  • 1,634
  • 2
  • 14
  • 22