I am designing a GUI in which whenever I click a button, the figure inside the GUI will be updated. This figure contains two y-axes with a common x-axis. I am using twinx function inside matplotlib. Everything is working as expected, except the ytick of the 2nd y-axis.
Here is my code:
import sys
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
from numpy import *
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(650, 400)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.pushButton_15 = QtWidgets.QPushButton(self.centralwidget)
self.pushButton_15.setGeometry(QtCore.QRect(430, 50, 191, 23))
self.pushButton_15.setObjectName("pushButton_15")
self.pushButton_15.clicked.connect(self.PlotOnCanvas)
self.frame = QtWidgets.QFrame(self.centralwidget)
self.frame.setGeometry(QtCore.QRect(20, 25, 421, 290))
self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
self.frame.setObjectName("frame")
self.frame_2 = QtWidgets.QFrame(self.frame)
self.frame_2.setGeometry(QtCore.QRect(9, 10, 401, 271))
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.frame_2.sizePolicy().hasHeightForWidth())
self.frame_2.setSizePolicy(sizePolicy)
self.frame_2.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.frame_2.setFrameShadow(QtWidgets.QFrame.Raised)
self.frame_2.setObjectName("frame_2")
self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.frame_2)
self.horizontalLayout_2.setObjectName("HorizontalLayout_2")
self.figure, self.ax = plt.subplots()
self.canvas = FigureCanvas(self.figure)
self.horizontalLayout_2.addWidget(self.canvas)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.pushButton_15.setText(_translate("MainWindow", "test"))
def PlotOnCanvas(self):
self.ax.clear()
x = np.linspace(0, 4 * pi, 1000)
y1 = np.sin(2 * pi * np.random.rand() * 2 * x)
y2 = np.sin(2 * pi * np.random.rand() * 2 * x)
colory2 = 'tab:red'
colory1 = 'tab:blue'
ax1 = self.ax
ax2 = ax1.twinx()
ax1.set_xlabel('x axis', fontsize=8)
ax1.xaxis.set_tick_params(labelsize=8)
ax1.set_ylabel('y1 axis', color=colory1, fontsize=8)
ax2.set_ylabel('y2 axis', color=colory2, fontsize=8)
ax1.yaxis.set_tick_params(labelcolor=colory1, labelsize=8)
ax2.yaxis.set_tick_params(labelcolor=colory2, labelsize=8)
ax1.set_yticks([-1, -0.5, 0, 0.5, 1])
ax2.set_yticks([-1, -0.5, 0, 0.5, 1])
ax1.set_ylim(-1.2, 1.2)
ax2.set_ylim(-1.2, 1.2)
l1, = ax1.plot(x, y1, lw=2, color=colory1)
l2, = ax2.plot(x, y2, lw=2, color=colory2)
plt.legend([l1, l2], ['y1', 'y2'], fontsize=8, loc="upper right")
plt.title('y1/y2', fontsize=8)
plt.tight_layout()
self.canvas.draw()
ax2.clear()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
and here is the output:
After 1st click

After multiple clicks

After 1st click, I can get both axis in the format that I want. However, after the 2nd click, the 2nd axis start to behave strangely. Its range changes from (-1,1) to (0,1); in addition, its ticks (0,0.2, ..., 1) starts to print on top of each other. As a result, its font becomes thicker.
I tried clearing the axis and both axes using ax.cla() and ax.clf() but it didn't work.
It looks like you keep making a new
twinxaxis every click. InsetupUifunction, I'd changeself.figure, self.ax = plt.subplots()toself.figure, self.ax1 = plt.subplots()and then add a line afterwards that isself.ax2 = self.ax1.twinx(). This will only usetwinxonce in the setup.Now that you have those two axes defined, you can change, your
PlotOnCanvasfunction to only reference those two axes. To do this, you can create convenience variablesax1 = self.ax1andax2 = self.ax2, removingax2 = ax1.twinx(), which was dealt with in the other function. You can then callax1.clear()andax2.clear()before running the rest of the function. With those changes, I think it should now update properly because it is referencing the proper axes and not adding a newtwinxaxis every click.To address the twinx's y-axis label moving to the wrong side, add
ax2.yaxis.set_label_position("right")to thePlotOnCanvasfunction before callingax2.set_ylabel().Putting it all together, we have