'How to plot without extending axis limits?

I'm trying to draw on an existing axis without extending or modifying its limits.

For example:

import numpy as np
import matplotlib.pyplot as plt

xy = np.random.randn(100, 2)

plt.scatter(xy[:,0], xy[:,1])

Makes a fine plot with well-fitting axis limits.

However, when I try to draw a line on top of it:

xlim = plt.gca().get_xlim()
plt.plot(xlim, xlim, 'k--')

the axis limits are extended, presumably to create padding around the new data.

How can I draw a line without this padding?



Solution 1:[1]

Setting plt.autoscale(False) prevents autoscaling from happening.

import numpy as np; np.random.seed(42)
import matplotlib.pyplot as plt

xy = np.random.randn(100, 2)
# By default plots are autoscaled. 
plt.scatter(xy[:,0], xy[:,1])

#Turn autoscaling off
plt.autoscale(False)
xlim = plt.gca().get_xlim()
plt.plot(xlim, xlim, 'k--')

plt.show()

enter image description here

Solution 2:[2]

You can use the autoscale property of Axes objects:

Per the documentation:

Axes.autoscale(enable=True, axis='both', tight=None)

Autoscale the axis view to the data (toggle).

Convenience method for simple axis view autoscaling. It turns autoscaling on or off, and then, if autoscaling for either axis is on, it performs the autoscaling on the specified axis or axes. Parameters:

enable : bool or None, optional
         True (default) turns autoscaling on, False turns it off. None leaves the autoscaling state unchanged.
axis : {'both', 'x', 'y'}, optional
       which axis to operate on; default is 'both'
tight: bool or None, optional
       If True, set view limits to data limits; if False, let the locator
       and margins expand the view limits; if None, use tight scaling
       if the only artist is an image, otherwise treat tight as False.
       The tight setting is retained for future autoscaling until it is
       explicitly changed.
fig, ax = plt.subplots()
ax.plot(np.random.normal(size=(100,)),np.random.normal(size=(100,)),'bo')
ax.autoscale(tight=True)
xlim = ax.get_xlim()
plt.plot(xlim, xlim, 'k--')

enter image description here

Solution 3:[3]

One brute-force solution is to keep track of the axis limits before drawing, and reset them after.

Like so:

from contextlib import contextmanager

@contextmanager
def preserve_limits(ax=None):
    """ Plot without modifying axis limits """
    if ax is None:
        ax = plt.gca()

    xlim = ax.get_xlim()
    ylim = ax.get_ylim()

    try:
        yield ax
    finally:
        ax.set_xlim(xlim)
        ax.set_ylim(ylim)

Now compare

plt.scatter(xy[:,0], xy[:,1])

xlim = plt.gca().get_xlim()
plt.plot(xlim, xlim, 'k--')

with

plt.scatter(xy[:,0], xy[:,1])

with preserve_limits():
    xlim = plt.gca().get_xlim()
    plt.plot(xlim, xlim, 'k--')

Solution 4:[4]

If you set the x-axis limits separately, they won't be overwritten until you change them, regardless of what is plotted. to make it mesh with your code, try:

plt.xlim(xlim)

when you get xlim, it gets the current limits, but once you 'set' them, they're locked until you change them again. This works for the y-axis as well, if you want those to be fixed too (just swap 'x' for 'y' and add the code).

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 ImportanceOfBeingErnest
Solution 2
Solution 3
Solution 4 Jgd