`tick_params` 对于第二个 Y 轴不起作用。

huangapple go评论69阅读模式
英文:

tick_params doesn't work properly for 2nd y-axis

问题

我正在设计一个图形用户界面(GUI),每当我点击一个按钮时,GUI 内的图形将会更新。该图形包含两个 y 轴和一个共同的 x 轴。我在 matplotlib 中使用了 twinx 函数。一切都按预期进行,除了第二个 y 轴的刻度。在第一次点击后,我可以得到我想要的轴格式。然而,在第二次点击后,第二个轴开始表现奇怪。其范围从 (-1,1) 变为 (0,1);此外,它的刻度 (0,0.2, ..., 1) 开始重叠显示。结果,其字体变得更粗。

我尝试清除轴和两个轴,使用了 ax.cla() 和 ax.clf(),但没有起作用。

英文:

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

`tick_params` 对于第二个 Y 轴不起作用。

After multiple clicks

`tick_params` 对于第二个 Y 轴不起作用。

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.

答案1

得分: 1

看起来每次点击都会创建一个新的twinx轴。在setupUi函数中,我会将self.figure, self.ax = plt.subplots()更改为self.figure, self.ax1 = plt.subplots(),然后在后面添加一行代码self.ax2 = self.ax1.twinx()。这样就只在设置中使用了一次twinx

现在,您已经定义了这两个轴,可以将PlotOnCanvas函数更改为仅引用这两个轴。为此,您可以创建方便的变量ax1 = self.ax1ax2 = self.ax2,删除ax2 = ax1.twinx(),这在其他函数中已经处理了。然后在运行函数的其余部分之前调用ax1.clear()ax2.clear()。通过这些更改,我认为现在应该可以正确更新,因为它引用了正确的轴,而不是在每次点击时都添加一个新的twinx轴。

为了解决twinx的y轴标签移到错误的一侧的问题,在调用ax2.set_ylabel()之前,在PlotOnCanvas函数中添加ax2.yaxis.set_label_position("right")

把所有这些放在一起,我们有:

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        # 在绘图创建之前的一切都一样
        # 在设置中使用twinx,然后在后面引用相同的ax2
        self.figure, self.ax1 = plt.subplots()
        self.ax2 = self.ax1.twinx()
        
        # 这个函数中的其它部分保持不变


    def PlotOnCanvas(self):
        # 使用保存的ax1和ax2
        ax1 = self.ax1
        ax2 = self.ax2
        ax1.clear()
        ax2.clear()
        
        # 直到轴标签之前的其他代码
        # 在设置y标签之前添加这一行
        ax2.yaxis.set_label_position("right")
        ax2.set_ylabel('y2轴', color=colory2, fontsize=8)

        # 其他部分保持不变

希望这对您有所帮助!

英文:

It looks like you keep making a new twinx axis every click. In setupUi function, I'd change self.figure, self.ax = plt.subplots() to self.figure, self.ax1 = plt.subplots() and then add a line afterwards that is self.ax2 = self.ax1.twinx(). This will only use twinx once in the setup.

Now that you have those two axes defined, you can change, your PlotOnCanvas function to only reference those two axes. To do this, you can create convenience variables ax1 = self.ax1 and ax2 = self.ax2, removing ax2 = ax1.twinx(), which was dealt with in the other function. You can then call ax1.clear() and ax2.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 new twinx axis every click.

To address the twinx's y-axis label moving to the wrong side, add ax2.yaxis.set_label_position("right") to the PlotOnCanvas function before calling ax2.set_ylabel().

Putting it all together, we have

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        # everything is the same until the plot creation
        # use twinx in the setup and reference the same ax2 afterward
        self.figure, self.ax1 = plt.subplots()
        self.ax2 = self.ax1.twinx()
        
        # everything else in this function is the same


    def PlotOnCanvas(self):
        # use the saved ax1 and ax2
        ax1 = self.ax1
        ax2 = self.ax2
        ax1.clear()
        ax2.clear()
        
        # other code until the axis labels
        # add this line before setting the y-label
        ax2.yaxis.set_label_position("right")
        ax2.set_ylabel('y2 axis', color=colory2, fontsize=8)

        # everything else unchanged

huangapple
  • 本文由 发表于 2023年6月8日 04:58:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/76427077.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定