The below code example is modified from the basis on Matplotlib: Finding out xlim and ylim after zoom
Basically, in that example, I want to have a dual x axis; and I want the second (doubled) x axis to behave as the original one. So, the link uses a callback to do that. However:
- While I only pan the plot, everything is fine - the dual copy is synchronized to the original X axis
- Once I zoom - something goes wrong, and apparently, the wrong range is applied to the dual axis - EVEN IF when printing the ranges in the callback, gives the expected range for the drawing after the zoom
- Once I start dragging after zoom, the two axes are dragged correspondingly - however, since the initial condition from the previous step is wrong, so is this part
- Now, I've added an extra call to the callback, on button release - so once I release the button from the drag move motion, THEN the two axes get synchronized again ??!!
Here is an animated gif (Matplotlib 3.1.1, Python 3.7.4 on MSYS2/MINGW64 on Windows 10):
I truly, truly don't understand this. How come, when I just pan/drag the plot, ax.get_xlim()
gives the right numbers, and ax22.set_xlim()
applies them - but when I zoom the plot, ax.get_xlim()
gives the right numbers, but ax22.set_xlim()
does NOT apply them (or rather, applies them, but late - that is, applies the data from previous request in the current request) ????!!! What is this sorcery?!
And how can I get the dual ax22
to be synchronized with the original ax
axis, regardless if I drag or zoom in interactive mode?
The code:
#!/usr/bin/env python3
import matplotlib
print("matplotlib.__version__ {}".format(matplotlib.__version__))
import matplotlib.pyplot as plt
#
# Some toy data
x_seq = [x / 100.0 for x in range(1, 100)]
y_seq = [x**2 for x in x_seq]
#
# Scatter plot
fig, ax = plt.subplots(1, 1)
ax.plot(x_seq, y_seq)
# https://stackoverflow.com/questions/31803817/how-to-add-second-x-axis-at-the-bottom-of-the-first-one-in-matplotlib
ax22 = ax.twiny() # instantiate a second axes that shares the same y-axis
# Move twinned axis ticks and label from top to bottom
ax22.xaxis.set_ticks_position("bottom")
ax22.xaxis.set_label_position("bottom")
# Offset the twin axis below the host
ax22.spines["bottom"].set_position(("axes", -0.06))
ax22.set_xlim(*ax.get_xlim())
#
# Declare and register callbacks
def on_xlims_change(axes):
print("updated xlims: ", ax.get_xlim())
ax22.set_xlim(*ax.get_xlim())
ax.callbacks.connect('xlim_changed', on_xlims_change)
fig.canvas.mpl_connect('button_release_event', on_xlims_change)
#
# Show
plt.show()