Basically, I want to achieve the same as in https://stackoverflow.com/a/58413766/6197439 - except with a two plots.
The example code for this is pasted below, and here is an animated gif of how it behaves:
The thing is:
- I have to make the dual axis a
twiny
ofax2
(the bottom subplot) so it is drawn below the shared x axis at the bottom - else it gets drawn below the top plot (and overlapping the top of the bottom plot) - After start, I first drag in the bottom subplot - both axes follow as they should
- If I zoom in the bottom subplot, both x-axes scale properly - but the twin axes does not have all the labels (that is why I have
on_xlims_change
, which helped fix that in the linked post, where there was only one plot - but here I cannot get it to work) - If then I drag in the top subplot - only the original x-axis moves, the dual/twinned cloned x-axis does not (the gif doesn't show that, but the same goes for zooming in top subplot as well)
I have tried using the callback on either and both ax
and ax2
, and I couldn't get an improved behavior - however, note that the gif shows the behavior as in the code posted here (where the callback is not used).
So, how can I make the dual/twinned x-axis follow the original shared x-axis - across both zoom and pan, in both the top and the bottom subplot?
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]
y2_seq = [0.3*x**2 for x in x_seq]
#
# Scatter plot
fig, (ax, ax2) = plt.subplots(2, 1, sharex=True, figsize=(9, 6), dpi=120, gridspec_kw={'height_ratios': [2, 1]}) # two rows, one column
# Remove horizontal space between axes
fig.subplots_adjust(hspace=0)
ax.plot(x_seq, y_seq)
ax2.plot(x_seq, y2_seq)
# https://stackoverflow.com/questions/31803817/how-to-add-second-x-axis-at-the-bottom-of-the-first-one-in-matplotlib
ax22 = ax2.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.1))
factor = 655
old_xlims = ax2.get_xlim()
new_xlims = (factor*old_xlims[0], factor*old_xlims[1])
old_tlocs = ax2.get_xticks()
new_tlocs = [i*factor for i in old_tlocs]
print("old_xlims {} new_xlims {} old_tlocs {} new_tlocs {}".format(old_xlims, new_xlims, old_tlocs, new_tlocs))
ax22.set_xticks(new_tlocs)
ax22.set_xlim(*new_xlims)
def on_xlims_change(axes):
old_tlocs = axes.get_xticks()
new_tlocs = [i*factor for i in old_tlocs]
ax22.set_xticks(new_tlocs)
# ax.callbacks.connect('xlim_changed', on_xlims_change)
# ax2.callbacks.connect('xlim_changed', on_xlims_change)
#
# Show
plt.show()