You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Matplotlib与PyQt5中为Line2D添加标签失败的问题求助

解决Matplotlib Line2D标签不显示的问题

我明白你遇到的困扰了——你已经给Line2D对象设置了label参数,但图例就是没显示出来,没法区分后续要添加的多条监控曲线。别担心,这是因为Matplotlib不会自动生成图例,你需要显式触发这个操作才行。

问题原因

你创建Line2D时设置label='cpu'的操作是正确的,但Matplotlib需要你调用legend()方法来根据这些label生成并渲染图例,否则它不会自动显示。

修复步骤

  1. 保留正确的Line2D label设置:你原来的代码里,把self.line1 = Line2D([], [], color='blue')改成self.line1 = Line2D([], [], color='blue', label='CPU Usage')(或者你想要的标签文本),这部分没问题。
  2. 添加图例生成代码:在CustomFigCanvas类的__init__方法中,所有Line2D对象添加到坐标轴之后,调用self.ax1.legend()来生成图例。
  3. 后续添加多条曲线:只需要给每条新的Line2D都设置label参数,图例会自动包含所有带label的线条。

修改后的完整代码

###################################################################
#                                                                 #
# PLOT A LIVE GRAPH (PyQt5)                                       #
# -----------------------------                                   #
# EMBED A MATPLOTLIB ANIMATION INSIDE YOUR                        #
# OWN GUI!                                                        #
#                                                                 #
###################################################################
import sys
import os
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import functools
import numpy as np
import random as rd
import matplotlib
matplotlib.use("Qt5Agg")
from matplotlib.figure import Figure
from matplotlib.animation import TimedAnimation
from matplotlib.lines import Line2D
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import time
import threading
import subprocess
import platform
from os import linesep
import psutil

class CustomMainWindow(QMainWindow):
    def __init__(self):
        super(CustomMainWindow, self).__init__()
        # Define the geometry of the main window
        self.setGeometry(300, 300, 800, 400)
        self.setWindowTitle("System Monitor")

        # Create FRAME_A
        self.FRAME_A = QFrame(self)
        self.FRAME_A.setStyleSheet("QWidget { background-color: %s }" % QColor(210,210,235,255).name())
        self.LAYOUT_A = QGridLayout()
        self.FRAME_A.setLayout(self.LAYOUT_A)
        self.setCentralWidget(self.FRAME_A)

        # Place the matplotlib figure
        self.myFig = CustomFigCanvas()
        self.LAYOUT_A.addWidget(self.myFig, *(0,1))

        # Add the callbackfunc to ..
        myDataLoop = threading.Thread(name = 'myDataLoop', target = dataSendLoop, daemon = True, args = (self.addData_callbackFunc,))
        myDataLoop.start()

        self.show()
        return

    def addData_callbackFunc(self, value):
        # print("Add data: " + str(value))
        self.myFig.addData(value)
        return

''' End Class '''

class CustomFigCanvas(FigureCanvas, TimedAnimation):
    def __init__(self):
        self.addedData = []
        print(matplotlib.__version__)
        # The data
        self.xlim = 200
        self.n = np.linspace(0, self.xlim - 1, self.xlim)
        a = []
        b = []
        a.append(2.0)
        a.append(4.0)
        a.append(2.0)
        b.append(4.0)
        b.append(3.0)
        b.append(4.0)
        self.y = (self.n * 0.0) + 50

        # The window
        self.fig = Figure(figsize=(5,5), dpi=100)
        self.ax1 = self.fig.add_subplot(111)

        # self.ax1 settings
        self.ax1.set_xlabel('time in 1/10 of a second')
        self.ax1.set_ylabel('usage in %')
        # 1. 给Line2D添加label参数
        self.line1 = Line2D([], [], color='blue', label='CPU Usage')
        self.line1_tail = Line2D([], [], color='blue', linewidth=2)
        self.line1_head = Line2D([], [], color='red', marker='o', markeredgecolor='r')
        self.ax1.add_line(self.line1)
        self.ax1.add_line(self.line1_tail)
        self.ax1.add_line(self.line1_head)
        self.ax1.set_xlim(0, self.xlim)
        self.ax1.set_ylim(0, 100)

        # 2. 添加图例生成代码
        self.ax1.legend()

        FigureCanvas.__init__(self, self.fig)
        TimedAnimation.__init__(self, self.fig, interval = 50, blit = True)
        return

    def new_frame_seq(self):
        return iter(range(self.n.size))

    def _init_draw(self):
        lines = [self.line1, self.line1_tail, self.line1_head]
        for l in lines:
            l.set_data([], [])
        return

    def addData(self, value):
        self.addedData.append(value)
        return

    def zoomIn(self, value):
        bottom = self.ax1.get_ylim()[0]
        top = self.ax1.get_ylim()[1]
        bottom += value
        top -= value
        self.ax1.set_ylim(bottom,top)
        self.draw()
        return

    def _step(self, *args):
        # Extends the _step() method for the TimedAnimation class.
        try:
            TimedAnimation._step(self, *args)
        except Exception as e:
            self.abc += 1
            print(str(self.abc))
            TimedAnimation._stop(self)
            pass
        return

    def _draw_frame(self, framedata):
        margin = 2
        while(len(self.addedData) > 0):
            self.y = np.roll(self.y, -1)
            self.y[-1] = self.addedData[0]
            del(self.addedData[0])

        self.line1.set_data(self.n[ 0 : self.n.size - margin ], self.y[ 0 : self.n.size - margin ])
        self.line1_tail.set_data(np.append(self.n[-10:-1 - margin], self.n[-1 - margin]), np.append(self.y[-10:-1 - margin], self.y[-1 - margin]))
        self.line1_head.set_data(self.n[-1 - margin], self.y[-1 - margin])
        self._drawn_artists = [self.line1, self.line1_tail, self.line1_head]
        return

''' End Class '''

# You need to setup a signal slot mechanism, to
# send data to your GUI in a thread-safe way.
# Believe me, if you don't do this right, things
# go very very wrong..
class Communicate(QObject):
    data_signal = pyqtSignal(float)

''' End Class '''

def dataSendLoop(addData_callbackFunc):
    # Setup the signal-slot mechanism.
    mySrc = Communicate()
    mySrc.data_signal.connect(addData_callbackFunc)

    # Simulate some data
    n = np.linspace(0, 499, 500)
    y = 50 + 25*(np.sin(n / 8.3)) + 10*(np.sin(n / 7.5)) - 5*(np.sin(n / 1.5))
    i = 0
    while(True):
        if(i > 499):
            i = 0
        time.sleep(0.1)
        #mySrc.data_signal.emit(y[i]) # <- Here you emit a signal!
        mySrc.data_signal.emit(psutil.cpu_percent())
        i += 1

###
###
if __name__== '__main__':
    app = QApplication(sys.argv)
    QApplication.setStyle(QStyleFactory.create('Plastique'))
    myGUI = CustomMainWindow()
    sys.exit(app.exec_())

额外提示

如果后续要添加内存监控之类的第二条曲线,只需要:

  • 新增一个self.y_memory数组来存储内存数据
  • 创建新的Line2D对象:self.line2 = Line2D([], [], color='green', label='Memory Usage')
  • 将其添加到坐标轴:self.ax1.add_line(self.line2)
  • 在_draw_frame方法中更新这条线的数据

这样图例就会自动显示两条曲线的标签了。

内容的提问来源于stack exchange,提问作者Matthijs990

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:00:37