英文:
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
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.
答案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.ax1
和ax2 = 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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论