5

Let's say that I have a certain number of data sets that I want to plot together.

And then I want to zoom on a certain part (for example, using ax.set_xlim, or plt.xlim or plt.axis). When I do that it still keeps the calculated range prior to the zoom. How can I make it rescale to what is currently being shown?

For example, using

import matplotlib
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec

data_x = [d for d in range(100)]
data_y = [2*d for d in range(100)]
data_y2 = [(d-50)*(d-50) for d in range(100)]

fig = plt.figure(constrained_layout=True)
gs = gridspec.GridSpec(2, 1, figure=fig)

ax1 = fig.add_subplot(gs[0, 0])
ax1.grid()
ax1.set_xlabel('x')
ax1.set_ylabel('y')
ax1.scatter(data_x, data_y, s=0.5)
ax1.scatter(data_x, data_y2, s=0.5)

ax2 = fig.add_subplot(gs[1, 0])
ax2.grid()
ax2.set_xlabel('x')
ax2.set_ylabel('y')
ax2.scatter(data_x, data_y, s=0.5)
ax2.scatter(data_x, data_y2, s=0.5)
ax2.set_xlim(35,45)

fig.savefig('scaling.png', dpi=300)
plt.close(fig)

Which generate

failed zoom

as you can see the plot below gets hard to see something since the y-axis kept using the same range as the non-limited version.

I have tried using relim, autoscale or autoscale_view but that did not work. For a single data set, I could use ylim with the minimum and maximum values for that dataset. But for different data set, I would have to look through all of them.

Is there a better way to force a recalculation of the y-axis range?

Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
clem steredenn
  • 352
  • 7
  • 20
  • 2
    Possible duplicate: https://stackoverflow.com/questions/29461608/matplotlib-fixing-x-axis-scale-and-autoscale-y-axis. I haven't closed the question with that yet, in case a new feature has been added to matplotlib in the last 6 years that solves the issue more elegantly – tmdavison May 19 '21 at 08:42

1 Answers1

2
  • Convert the lists to numpy arrays
    • create a Boolean mask of data_x based on xlim_min and xlim_max
    • use the mask to select the relevant data points in the y data
    • combine the two selected y arrays
    • select the min and max values from the selected y values and set them as ylim
import numpy as np
import matplotlib.pyplot as plt

# use a variable for the xlim limits
xlim_min = 35
xlim_max = 45

# convert lists to arrays
data_x = np.array(data_x)
data_y = np.array(data_y)
data_y2 = np.array(data_y2)

# create a mask for the values to be plotted based on the xlims
x_mask = (data_x >= xlim_min) & (data_x <= xlim_max)

# use the mask on y arrays
y2_vals = data_y2[x_mask]
y_vals = data_y[x_mask]

# combine y arrays
y_all = np.concatenate((y2_vals, y_vals))

# get min and max y
ylim_min = y_all.min()
ylim_max = y_all.max()

# other code from op
...

# use the values to set xlim and ylim
ax2.set_xlim(xlim_min, xlim_max)
ax2.set_ylim(ylim_min, ylim_max)

enter image description here

# use a variable for the xlim limits
xlim_min = 35
xlim_max = 45

# convert lists to arrays
data_x = np.array(data_x)
data_y = np.array(data_y)
data_y2 = np.array(data_y2)

# create a mask for the values to be plotted based on the xlims
x_mask = (data_x >= xlim_min) & (data_x <= xlim_max)

# use the mask on x
x_vals = data_x[x_mask]

# use the mask on y
y2_vals = data_y2[x_mask]
y_vals = data_y[x_mask]

# other code from op
...

# plot
ax2.scatter(x_vals, y_vals, s=0.5)
ax2.scatter(x_vals, y2_vals, s=0.5)
Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158