Changing plot alignment for different placing of colorbar() in twinx plot
If one combines a pcolormesh plot/hist2d plot with a standard plot by using twinx, the graph from the plot moves to wrong x values if the colorbar is called after the plot call. If it is called before, the alignment is fine.
I am not sure if this is a bug or just wrong usage.
However, one of the resulting graphs has a wrong extent that might lead to misinterpretations.
Code for reproduction
importnumpyasnpimportmatplotlib.pyplotaspltdata=np.random.random((64, 128)) *2.0x=np.arange(128)
y=np.arange(64)
plt.pcolormesh(x, y, data)
#plt.colorbar() --> here it works fineplt.twinx()
plt.colorbar()
# --> here it gives wrong x values for the orange plotplt.plot(x, np.sin(x/10), color="orange", lw=4)
plt.show()
Actual outcome
Next to the confusing layout the plot shows actually a wrong graph:
the orange plot just goes to around x=100 but should go to x=128.
(The axis of the colorbar is correct and shows the range of data.)
Expected outcome
If colorbar is called before twinx, the orange graph has the correct extent.
I am not sure if this is a bug or a wrong usage of matplotlib. In any case the wrong extent of the (in this case) orange plot is a dangerous behavior that might lead to misinterpretations of the data.
Matplotlib version
Operating System: Ubuntu 14.04.1
Matplotlib Version: 2.0.0rc1
Python Version: 3.4.3
Jupyter Version: 1.0.0 (I am using %matplotlib inline)
I would call it a shortcoming of the twinx implementation: it makes a second Axes at the same position as the first, but it has no mechanism for ensuring that if the position of either is subsequently changed, the position of the other is also changed to match it. Ideally, the position of both Axes would be the same object so that it would not be necessary to use callbacks to keep them synchronized. There are several attributes related to position, so I'm not sure whether this would be a simple change, a difficult one, or a complete can of worms.
#9082 addresses this (though you can't use the pyplot interface)
data=np.random.random((64, 128)) *2.0x=np.arange(128)
y=np.arange(64)
fig, ax=plt.subplots(constrained_layout=True)
pcm=ax.pcolormesh(x, y, data)
#plt.colorbar() --> here it works fineax2=ax.twinx()
fig.colorbar(pcm)
# --> here it gives wrong x values for the orange plotax2.plot(x, np.sin(x/10), color="orange", lw=4)
plt.show()
while I got the same problem, here is my code: if a twinx exist, then if you remove the colorbar, and the axe shrink, even if you apply tight layout, it won't recover.
importsysimportnumpyasnpfromPyQt5importQtWidgetsimportmatplotlibfrommatplotlib.backends.backend_qt5aggimportFigureCanvasQTAggfrommatplotlib.backends.backend_qt5aggimportNavigationToolbar2QTasNavigationToolbarimportmatplotlib.pyplotaspltmatplotlib.use("Qt5Agg")
classMplCanvas(FigureCanvasQTAgg):
def__init__(self, parent=None, width=5, height=4, dpi=100):
self.fig=plt.figure(figsize=(width, height), dpi=dpi)
self.axe=self.fig.add_subplot(1, 1, 1, label='good')
super().__init__(self.fig)
classMainWindow(QtWidgets.QMainWindow):
def__init__(self):
super().__init__()
v_layout=QtWidgets.QVBoxLayout()
self.canvas=MplCanvas(self, width=5, height=4, dpi=100)
self.axe=self.canvas.axeself.figure=self.canvas.fig# draw a scatter plot on self.axenp.random.seed(19680801)
rx, ry=3., 1.area=rx*ry*np.pitheta=np.arange(0, 2*np.pi+0.01, 0.1)
verts=np.column_stack([rx/area*np.cos(theta), ry/area*np.sin(theta)])
x, y, s, c=np.random.rand(4, 30)
s*=10**2self.image=self.axe.scatter(x, y, s=s, c=c, marker=verts)
# add a twinx: it fails the tight layout*********************x=np.arange(0, 1, 0.01)
y=np.random.randn(len(x))
self.ax2=self.axe.twinx()
self.ax2.plot(x, y, lw=2, linestyle='-', label='signal')
# ***********************************************************toolbar=NavigationToolbar(self.canvas, self)
v_layout.addWidget(toolbar)
v_layout.addWidget(self.canvas)
label=QtWidgets.QLabel('Show Color Bar')
self.checkBox_colorBar=QtWidgets.QCheckBox(self)
h_layout=QtWidgets.QHBoxLayout(self)
h_layout.addWidget(label)
h_layout.addWidget(self.checkBox_colorBar)
v_layout.addLayout(h_layout)
widget=QtWidgets.QWidget()
widget.setLayout(v_layout)
self.setCentralWidget(widget)
self.checkBox_colorBar.toggled.connect(self.showColorBar)
defshowColorBar(self):
color_bar=self.image.colorbar# None if no color barifself.checkBox_colorBar.isChecked():
ifcolor_barisNone:
self.figure.colorbar(self.image)
else:
ifcolor_barisnotNone:
color_bar.remove()
delcolor_barself.canvas.draw()
if__name__=='__main__':
app=QtWidgets.QApplication(sys.argv)
window=MainWindow()
mw=windowmw.show()
app.exec_()
it gives out the following result if toggle the show color bar check box a few times.
Please open a new bug report including all relevant version info. However I do not think removing a Colorbar will magically reallocate its space using tight_layout. It may work with constrained_layout
Activity
efiring commented on Jun 29, 2017
I would call it a shortcoming of the twinx implementation: it makes a second Axes at the same position as the first, but it has no mechanism for ensuring that if the position of either is subsequently changed, the position of the other is also changed to match it. Ideally, the position of both Axes would be the same object so that it would not be necessary to use callbacks to keep them synchronized. There are several attributes related to position, so I'm not sure whether this would be a simple change, a difficult one, or a complete can of worms.
jklymak commented on Dec 11, 2017
#9082 addresses this (though you can't use the pyplot interface)
PrometheusPi commented on Dec 12, 2017
@jklymak Thanks for posting this. I will cherry pick your pull request.
efiring commented on Jan 21, 2018
This is also addressed by #10033.
efiring commented on Jan 26, 2018
Closed by #10033.
bactone commented on Nov 24, 2021
while I got the same problem, here is my code: if a twinx exist, then if you remove the colorbar, and the axe shrink, even if you apply tight layout, it won't recover.
it gives out the following result if toggle the show color bar check box a few times.




jklymak commented on Nov 24, 2021
Please open a new bug report including all relevant version info. However I do not think removing a Colorbar will magically reallocate its space using tight_layout. It may work with constrained_layout