我正在尝试创建一个继承
pyqthraph
的
TextItem
类的自定义类,以便我可以拥有多行,每行具有不同的颜色,就像仅 1 个 TextItem 对象一样。我希望能够在类中存储行位置和颜色的逻辑,基本上,如果删除文本行,所有后续行都会向上移动。
下面的代码概要是:它是一种随机游走,绘制当前价格并更新每次迭代。在 6 次迭代中,新价格
sub1_value
作为新线添加到图中并进行更新。在 8 次迭代时添加另一个,
sub2_value
然后,在 10 次迭代时,删除 sub1,将 sub2 价格移至 sub1 的位置,然后在 14 次迭代时删除 sub2 价格。
问题是旧文本行(sub1 和 sub2 价格)仍然存在。第一行
main
发生变化,但值
sub1
和
sub2
的线无论其最后的值是什么,都保留在绘图上。我打算删除 sub1,然后将 sub2 放在第 2 行(索引 = 1)中,然后删除 sub2,仅显示主(红色)数字。
我已放入打印以查看 html 文本并且这些行被删除,但每当主要价格更新时就会再次重新引入
import sys
import numpy as np
import pyqtgraph as pg
from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import QTimer
class CustomTextItem(pg.TextItem):
def __init__(self, *args, **kwargs):
"""
self.stock_line_mapping to find the correct line in the html text that corresponds to the stock of the text
self.stock_colour_mapping to find the correct colour in the html text that corresponds to the stock of the text
self.number_of_lines how many lines of text is present
"""
self.stock_line_mapping = {}
self.stock_colour_mapping = {}
self.number_of_lines = 0
super().__init__(*args, **kwargs)
# Creating the line text
def create_line(self, value, colour):
value_str = f'{value:,.2f}'
new_line = f"<span style='color:{colour};'>{value_str}</span>"
return new_line
# Adding a label
def add_stock_price_label(self, stock, value, colour):
new_line = self.create_line(value, colour)
if hasattr(self, "HtmlText"):
updated_html_text = self.HtmlText + "<br>" + new_line # Appends a new line if the text exists.
else:
updated_html_text = new_line
self.HtmlText = updated_html_text
self.setHtml(updated_html_text) # updates the text
# Updates corresponding mapping values
self.stock_line_mapping[stock] = self.number_of_lines
self.stock_colour_mapping[stock] = colour
self.number_of_lines += 1
def remove_stock(self, stock):
"""
We find the index that is being removed, split the Html text into a list, remove that str and attach the list again with line breaks
"""
line_to_remove = self.stock_line_mapping[stock]
lines = self.HtmlText.split('<br>')
del lines[line_to_remove] # The index value.
new_line = '<br>'.join(lines)
self.setHtml(new_line) # set new text
# Since the lines after the removed line is moved up, we must update the mappings to correspond to the correct line index.
for stock_to_move, value in self.stock_line_mapping.copy().items():
if value > line_to_remove:
self.stock_line_mapping[stock_to_move] -= 1
del self.stock_line_mapping[stock]
self.number_of_lines -= 1
def update_value(self, stock, new_value):
# Add new line plot
line_to_update = self.stock_line_mapping[stock]
lines = self.HtmlText.split("<br>")
colour = self.stock_colour_mapping[stock]
new_line = self.create_line(new_value, colour)
lines[line_to_update] = new_line
updated_html = '<br>'.join(lines)
self.HtmlText = updated_html
self.setHtml(updated_html)
app = QApplication([])
win = pg.GraphicsLayoutWidget(show=True, title="Random Walk with TextItem")
win.resize(800, 600)
plot = win.addPlot(title="Random Walk")
curve = plot.plot(pen='y')
text_item = CustomTextItem(color='r', anchor=(0.5, 0.5), fill=(0, 0, 0, 150))
plot.addItem(text_item)
x = np.arange(100)
y = np.cumsum(np.random.randn(100))
first_creating = True
counter = 0
sub1_creating = True
sub2_creating = True
def update():
global x, y, first_creating, sub1_creating, sub2_creating, counter
y = np.roll(y, -1)
y[-1] = y[-2] + np.random.randn()
sub1_value = np.random.rand()
sub2_value = np.random.rand()
curve.setData(x, y)
last_x = x[-1]
last_y = y[-1]
"""
Initially create the main walk stock textItem and if it's created, call update_value() method
"""
if first_creating:
text_item.add_stock_price_label('main', last_y, 'red')
first_creating=False
else:
text_item.update_value('main', last_y)
"""
Between 5 to 10 iterations, create the sub TextItem, then after 10 iterations remove the item.
"""
if 10 > counter > 5:
if sub1_creating:
text_item.add_stock_price_label('sub1', sub1_value, 'white')
sub1_creating = False
else:
text_item.update_value('sub1', sub1_value)
if counter == 10:
text_item.remove_stock('sub1')
if 14 > counter > 7:
if sub2_creating:
text_item.add_stock_price_label('sub2', sub2_value, 'green')
sub2_creating = False
else:
text_item.update_value('sub2', sub2_value)
if counter == 14:
text_item.remove_stock('sub2')
counter+=1
text_item.setPos(last_x, last_y)
timer = QTimer()
timer.timeout.connect(update)
timer.start(1000)
if __name__ == '__main__':
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
sys.exit(app.exec_())
在更新文本项时遇到的问题源于如何替换 HTML 行。没有用包含更新值的新行替换整个行,而是仅替换了该行的一部分,从而留下了旧值的痕迹。
这是修复后的代码:
import sys
import numpy as np
import pyqtgraph as pg
from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import QTimer
class CustomTextItem(pg.TextItem):
def __init__(self, *args, **kwargs):
"""
self.stock_line_mapping to find the correct line in the html text that corresponds to the stock of the text
self.stock_colour_mapping to find the correct colour in the html text that corresponds to the stock of the text
self.number_of_lines how many lines of text is present
"""
self.stock_line_mapping = {}
self.stock_colour_mapping = {}
self.number_of_lines = 0
super().__init__(*args, **kwargs)
# Creating the line text
def create_line(self, value, colour):
value_str = f'{value:,.2f}'
new_line = f"<span style='color:{colour};'>{value_str}</span>"
return new_line
# Adding a label
def add_stock_price_label(self, stock, value, colour):
new_line = self.create_line(value, colour)
if hasattr(self, "HtmlText"):
updated_html_text = self.HtmlText + "<br>" + new_line # Appends a new line if the text exists.
else:
updated_html_text = new_line
self.HtmlText = updated_html_text
self.setHtml(updated_html_text) # updates the text
# Updates corresponding mapping values
self.stock_line_mapping[stock] = self.number_of_lines
self.stock_colour_mapping[stock] = colour
self.number_of_lines += 1
def remove_stock(self, stock):
"""
We find the index that is being removed, split the Html text into a list, remove that str and attach the list again with line breaks
"""
line_to_remove = self.stock_line_mapping[stock]
lines = self.HtmlText.split("<br>")
del lines[line_to_remove] # The index value.
new_line = "<br>".join(lines)
self.setHtml(new_line) # set new text
# Since the lines after the removed line is moved up, we must update the mappings to correspond to the correct line index.
for stock_to_move, value in self.stock_line_mapping.copy().items():
if value > line_to_remove:
self.stock_line_mapping[stock_to_move] -= 1
del self.stock_line_mapping[stock]
self.number_of_lines -= 1
def update_value(self, stock, new_value):
# Add new line plot
line_to_update = self.stock_line_mapping[stock]
lines = self.HtmlText.split("<br>")
colour = self.stock_colour_mapping[stock]
new_line = self.create_line(new_value, colour)
# Update the entire line
lines[line_to_update] = new_line
updated_html = "<br>".join(lines)
self.HtmlText = updated_html
self.setHtml(updated_html)
app = QApplication([])
win = pg.GraphicsLayoutWidget(show=True, title="Random Walk with TextItem")
win.resize(800, 600)
plot = win.addPlot(title="Random Walk")
curve = plot.plot(pen='y')
text_item = CustomTextItem(color='r', anchor=(0.5, 0.5), fill=(0, 0, 0, 150))
plot.addItem(text_item)
x = np.arange(100)
y = np.cumsum(np.random.randn(100))
first_creating = True
counter = 0
sub1_creating = True
sub2_creating = True
def update():
global x, y, first_creating, sub1_creating, sub2_creating, counter
y = np.roll(y, -1)
y[-1] = y[-2] + np.random.randn()
sub1_value = np.random.rand()
sub2_value = np.random.rand()
curve.setData(x, y)
last_x = x[-1]
last_y = y[-1]
"""
Initially create the main walk stock textItem and if it's created, call update_value() method
"""
if first_creating:
text_item.add_stock_price_label('main', last_y, 'red')
first_creating=False
else:
text_item.update_value('main', last_y)
"""
Between 5 to 10 iterations, create the sub TextItem, then after 10 iterations remove the item.
"""
if 10 > counter > 5:
if sub1_creating:
text_item.add_stock_price_label('sub1', sub1_value, 'white')
sub1_creating = False
else:
text_item.update_value('sub1', sub1_value)
if counter == 10:
text_item.remove_stock('sub1')
if 14 > counter > 7:
if sub2_creating:
text_item.add_stock_price_label('sub2', sub2_value, 'green')
sub2_creating = False
else:
text_item.update_value('sub2', sub2_value)
if counter == 14:
text_item.remove_stock('sub2')
counter+=1
text_item.setPos(last_x, last_y)
timer = QTimer()
timer.timeout.connect(update)
timer.start(1000)
if __name__ == '__main__':
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
sys.exit(app.exec_())
通过用包含新值的完整行替换整个行,将确保旧文本被完全删除,从而解决问题并正确更新文本项。
标签:python,pyqt,pyqt5,pyqtgraph From: 79017551