Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Set autoscale limits on plot to have buffer around all points

I would like to plot a set of points using pyplot in matplotlib but have none of the points be on the edge of my axes. The autoscale (or something) sets the xlim and ylim such that often the first and last points lie at x = xmin or xmax making it difficult to read in some situations.

This is more often problematic with loglog() or semilog() plots because the autoscale would like xmin and xmax to be exact powers of ten, but if my data contains only three points, e.g. at xdata = [10**2,10**3,10**4] then the first and last points will lie on the border of the plot.

Attempted Workaround

This is my solution to add a 10% buffer to either side of the graph. But is there a way to do this more elegantly or automatically?

from numpy import array, log10
from matplotlib.pyplot import *

xdata = array([10**2,10**3,10**4])
ydata = xdata**2

figure()
loglog(xdata,ydata,'.')
xmin,xmax = xlim()
xbuff = 0.1*log10(xmax/xmin)
xlim(xmin*10**(-xbuff),xmax*10**(xbuff))

I am hoping for a one- or two-line solution that I can easily use whenever I make a plot like this.

Linear Plot

To make clear what I'm doing in my workaround, I should add an example in linear space (instead of log space):

plot(xdata,ydata)
xmin,xmax = xlim()
xbuff = 0.1*(xmax-xmin)
xlim(xmin-xbuff,xmax+xbuff))

which is identical to the previous example but for a linear axis.

Limits too large

A related problem is that sometimes the limits are too large. Say my data is something like ydata = xdata**0.25 so that the variance in the range is much less than a decade but ends at exactly 10**1. Then, the autoscale ylim are 10**0 to 10**1 though the data are only in the top portion of the plot. Using my workaround above, I can increase ymax so that the third point is fully within the limits but I don't know how to increase ymin so that there is less whitespace at the lower portion of my plot. i.e., the point is that I don't always want to spread my limits apart but would just like to have some constant (or proportional) buffer around all my points.

like image 453
askewchan Avatar asked May 24 '11 16:05

askewchan


People also ask

How do you set limits on the y-axis?

ylim( limits ) sets the y-axis limits for the current axes or chart. Specify limits as a two-element vector of the form [ymin ymax] , where ymax is greater than ymin .

Does matplotlib autoscale?

The limits on an axis can be set manually (e.g. ax. set_xlim(xmin, xmax) ) or Matplotlib can set them automatically based on the data already on the axes. There are a number of options to this autoscaling behaviour, discussed below.

How do I remove the margins in matplotlib?

Show activity on this post. The python plotting library matplotlib will by default add margins to any plot that it generates. They can be reduced to a certain degree through some options of savefig() , namely bbox_inches='tight' and pad_inches=0 .


2 Answers

@askewchan I just succesfully achieved how to change matplotlib settings by editing matplotlibrc configuration file and running python directly from terminal. Don't know the reason yet, but matplotlibrc is not working when I run python from spyder3 (my IDE). Just follow steps here matplotlib.org/users/customizing.html.

1) Solution one (default for all plots)

Try put this in matplotlibrc and you will see the buffer increase:

axes.xmargin        : 0.1  # x margin.  See `axes.Axes.margins`
axes.ymargin        : 0.1  # y margin See `axes.Axes.margins`

Values must be between 0 and 1.

Obs.: Due to bugs, scale is not correctly working yet. It'll be fixed for matplotlib 1.5 (mine is 1.4.3 yet...). More info:

  • axes.xmargin/ymargin rcParam behaves differently than pyplot.margins() #2298
  • Better auto-selection of axis limits #4891

2) Solution two (individually for each plot inside the code)

There is also the margins function (for put directly in the code). Example:

import numpy as np
from matplotlib import pyplot as plt 
t = np.linspace(-6,6,1000)
plt.plot(t,np.sin(t))
plt.margins(x=0.1, y=0.1)
plt.savefig('plot.png')

Obs.: Here scale is working (0.1 will increase 10% of buffer before and after x-range and y-range).

like image 128
rodrigo souto Avatar answered Dec 23 '22 15:12

rodrigo souto


A similar question was posed to the matplotlib-users list earlier this year. The most promising solution involves implementing a Locator (based on MaxNLocator in this case) to override MaxNLocator.view_limits.

like image 38
Ben Gamari Avatar answered Dec 23 '22 16:12

Ben Gamari