【问题标题】:matching line colors to legend when plotting data from multiple arrays绘制来自多个数组的数据时将线条颜色与图例匹配
【发布时间】:2020-06-21 15:49:14
【问题描述】:

我有来自不同板上多个设备的温度数据,例如,在板 1 上,我有 PCB 本身和 3 个不同 FET 的温度,同样适用于板 2 和 3。 我将数据读入数据框中,并希望将数据与每个测试板的相同颜色一起绘制,但板上每个设备的标记不同。例如,电路板 1 的所有测量值都是蓝色的,PCB 温度使用标记“+”,FET1 使用标记“v”等。
我是这样读取文件的:

for file_name in glob.glob(path+'*.csv'):
    filename[i] = os.path.basename(file_name)
    print(filename[i])
    #x[i]= np.genfromtxt(path+ filename[i], delimiter=',',skip_header=20,usecols=(2,4,6,8))
    x[i]=pd.read_csv(path+filename[i], header=0,usecols=[2,4,6,8], skiprows=12,names=['PCB', 'FET1', 'FET2', 'FET3'])

并创建一个数据框数组。

然后我绘制不同的列:

colors=['r','b','g','c','m']
for i in range(len(filename)):
    #plt.figure()
    plt.plot(sc.decimate(x[i]['PCB'],5),'-+'+colors[i],label="PCB")
    plt.plot(sc.decimate(x[i]['FET1'],5),'-v'+colors[i],label='FET1')
    plt.plot(sc.decimate(x[i]['FET2'],5),'-x'+colors[i],label='FET2')
    plt.plot(sc.decimate(x[i]['FET3'],5),'-o'+colors[i],label='FET3')
    leg=np.append(leg, filename[i][0:7])
    #plt.show()


plt.show()
plt.legend(leg)

标记已正确显示,但当我遍历数据框时,颜色信息丢失了。如何绘制数据并对其进行排列,以便图例使用每组线条相同的颜色(按索引 i 分组)?

以下是一些示例数据: 文件 1:

Name:,Data Instr INSTR 3/5/2020 11:51:59,,,,,,,,,,,,
Owner:,lab1,,,,,,,,,,,,
Comments:,,,,,,,,,,,,,
Acquisition Date:,3/5/2020 11:51,,,,,,,,,,,,
&Instrument:,34970A,Address:,ASRL11::INSTR,Modules:,1,Slot3:,34901A,,,,,,
Total Channels:,4,,,,,,,,,,,,
Channel,Name,Function,Range,Resolution,AdvSettings,Scale,Gain,Offset,Label,Test,Low,High,HWAlarm
316,PCB_CTR,Temp (Type K),None,C,Temp (Type K)#1#0.016#Auto#0.001#C#Internal#0#false,FALSE,1,0,C,High Only,0,105,Alarm 1
317,Q24,Temp (Type K),None,C,Temp (Type K)#1#0.016#Auto#0.001#C#Internal#0#false,FALSE,1,0,C,High Only,0,105,Alarm 1
318,Q25,Temp (Type K),None,C,Temp (Type K)#1#0.016#Auto#0.001#C#Internal#0#false,FALSE,1,0,C,High Only,0,105,Alarm 1
319,Q18,Temp (Type K),None,C,Temp (Type K)#1#0.016#Auto#0.001#C#Internal#0#false,FALSE,1,0,C,High Only,0,105,Alarm 1
Scan  Control:,Start Action:,Immediately,Stop Action:,User Terminated,,,,,,,,,
Scan,Time,316 <PCB_CTR> (C),Alarm 316,317 <Q24> (C),Alarm 317,318 <Q25> (C),Alarm 318,319 <Q18> (C),Alarm 319,,,,
1,3/5/2020 11:51:59:168,30.471,0,29.241,0,29.165,0,33.302,0,,,,
2,3/5/2020 11:52:01:152,32.197,0,30.634,0,30.564,0,34.819,0,,,,
3,3/5/2020 11:52:03:152,33.795,0,32.019,0,31.879,0,36.848,0,,,,
4,3/5/2020 11:52:05:152,35.315,0,33.383,0,33.236,0,38.282,0,,,,
5,3/5/2020 11:52:07:152,36.965,0,34.734,0,34.62,0,39.946,0,,,,
6,3/5/2020 11:52:09:152,38.255,0,36.054,0,35.776,0,41.18,0,,,,
7,3/5/2020 11:52:11:152,39.467,0,37.328,0,37.028,0,42.258,0,,,,

文件 2

Name:,Data Instr INSTR 3/5/2020 10:03:21,,,,,,,,,,,,
Owner:,lab1,,,,,,,,,,,,
Comments:,,,,,,,,,,,,,
Acquisition Date:,3/5/2020 10:03,,,,,,,,,,,,
&Instrument:,34970A,Address:,ASRL11::INSTR,Modules:,1,Slot3:,34901A,,,,,,
Total Channels:,4,,,,,,,,,,,,
Channel,Name,Function,Range,Resolution,AdvSettings,Scale,Gain,Offset,Label,Test,Low,High,HWAlarm
316,PCB_CTR,Temp (Type K),None,C,Temp (Type K)#1#0.016#Auto#0.001#C#Internal#0#false,FALSE,1,0,C,High Only,0,105,Alarm 1
317,Q24,Temp (Type K),None,C,Temp (Type K)#1#0.016#Auto#0.001#C#Internal#0#false,FALSE,1,0,C,High Only,0,105,Alarm 1
318,Q25,Temp (Type K),None,C,Temp (Type K)#1#0.016#Auto#0.001#C#Internal#0#false,FALSE,1,0,C,High Only,0,105,Alarm 1
319,Q18,Temp (Type K),None,C,Temp (Type K)#1#0.016#Auto#0.001#C#Internal#0#false,FALSE,1,0,C,High Only,0,105,Alarm 1
Scan  Control:,Start Action:,Immediately,Stop Action:,User Terminated,,,,,,,,,
Scan,Time,316 <PCB_CTR> (C),Alarm 316,317 <Q24> (C),Alarm 317,318 <Q25> (C),Alarm 318,319 <Q18> (C),Alarm 319,,,,
1,3/5/2020 10:03:21:164,46.334,0,43.755,0,45.706,0,49.129,0,,,,
2,3/5/2020 10:03:22:149,46.997,0,44.262,0,46.35,0,49.773,0,,,,
3,3/5/2020 10:03:23:149,47.615,0,44.671,0,46.974,0,50.402,0,,,,
4,3/5/2020 10:03:24:149,48.267,0,45.229,0,47.628,0,50.879,0,,,,
5,3/5/2020 10:03:25:149,48.861,0,45.711,0,48.164,0,51.495,0,,,,
6,3/5/2020 10:03:26:149,49.455,0,46.323,0,48.783,0,51.9,0,,,,
7,3/5/2020 10:03:27:149,50.014,0,46.796,0,49.351,0,52.334,0,,,,

文件 3

Name:,Data Instr INSTR 3/5/2020 13:41:06,,,,,,,,,,,,
Owner:,lab1,,,,,,,,,,,,
Comments:,,,,,,,,,,,,,
Acquisition Date:,3/5/2020 13:41,,,,,,,,,,,,
&Instrument:,34970A,Address:,ASRL11::INSTR,Modules:,1,Slot3:,34901A,,,,,,
Total Channels:,4,,,,,,,,,,,,
Channel,Name,Function,Range,Resolution,AdvSettings,Scale,Gain,Offset,Label,Test,Low,High,HWAlarm
316,PCB_CTR,Temp (Type K),None,C,Temp (Type K)#1#0.016#Auto#0.001#C#Internal#0#false,FALSE,1,0,C,High Only,0,105,Alarm 1
317,Q24,Temp (Type K),None,C,Temp (Type K)#1#0.016#Auto#0.001#C#Internal#0#false,FALSE,1,0,C,High Only,0,105,Alarm 1
318,Q25,Temp (Type K),None,C,Temp (Type K)#1#0.016#Auto#0.001#C#Internal#0#false,FALSE,1,0,C,High Only,0,105,Alarm 1
319,Q18,Temp (Type K),None,C,Temp (Type K)#1#0.016#Auto#0.001#C#Internal#0#false,FALSE,1,0,C,High Only,0,105,Alarm 1
Scan  Control:,Start Action:,Immediately,Stop Action:,User Terminated,,,,,,,,,
Scan,Time,316 <PCB_CTR> (C),Alarm 316,317 <Q24> (C),Alarm 317,318 <Q25> (C),Alarm 318,319 <Q18> (C),Alarm 319,,,,
1,3/5/2020 13:41:06:162,28.121,0,26.882,0,28.785,0,31.061,0,,,,
2,3/5/2020 13:41:08:147,30.582,0,27.873,0,30.691,0,33.024,0,,,,
3,3/5/2020 13:41:10:147,31.782,0,28.935,0,32.578,0,34.876,0,,,,
4,3/5/2020 13:41:12:147,34.003,0,30.094,0,34.247,0,36.652,0,,,,
5,3/5/2020 13:41:14:147,35.097,0,31.199,0,35.975,0,38.142,0,,,,
6,3/5/2020 13:41:16:147,36.708,0,32.334,0,37.504,0,39.721,0,,,,
7,3/5/2020 13:41:18:147,38.274,0,33.508,0,39.048,0,41.198,0,,,,

感谢您的帮助。

编辑

在@ilke444 的帮助下,我离我想要的更近了,但我仍然有问题:

for i in range(len(filename)):
    l=plt.plot(sc.decimate(x[i]['PCB'],5),'-+'+colors[i],label="PCB")
    lines=np.append(lines,l[0].get_label())
    l=plt.plot(sc.decimate(x[i]['FET1'],5),'-v'+colors[i],label='FET1')
    lines=np.append(lines,l[0].get_label())
    l=plt.plot(sc.decimate(x[i]['FET2'],5),'-x'+colors[i],label='FET2')
    lines=np.append(lines,l[0].get_label())
    l=plt.plot(sc.decimate(x[i]['FET3'],5),'-o'+colors[i],label='FET3')
    lines=np.append(lines,l[0].get_label())

    linesclr=np.append(linesclr, l)  # save color info
    names = np.append(names, filename[i][0:7])

fig.legend(lines, loc=1)
fig.legend(linesclr, labels=names, loc=2)
plt.show()

如下所示,我尝试添加的第二个图例没有显示正确的颜色,即每个文件读取一种颜色(左上角):

我不明白为什么左边的图例没有显示正确的颜色,因为颜色信息在lineslr数组的每个元素中:

linesclr[0].get_color()
Out[4]: 'r'
linesclr[0].get_color()
Out[5]: 'r'
linesclr[1].get_color()
Out[6]: 'b'
linesclr[2].get_color()
Out[7]: 'g'

此外,我不明白为什么该图例中所有键的标记并不总是圆圈 ('o')。

我正在寻找的解决方案:

在我看来,在图上传达信息的最佳方式是使用 2 个图例,但右侧的图例仅显示每种设备类型的每一行的标记(带有相应标记的黑线),左侧的图例显示了用于该文件中所有温度读数的文件名和颜色(没有标记的行)。

所以,我想让右边的图例只显示带有标记的 4 个热电偶位置:

+ PCB
v FET1 
x FET2 
o FET3

左边的图例显示:红色的 ACI50#5,蓝色的 ACI50#,绿色的 ACI50#6,青色的 KDE5515(或者无论我读入多少文件,每个文件都有相应的绘图颜色)。

我已经尝试在 matplotlib 上阅读和文学关于图例和撰写自定义图例,并在互联网上寻找示例,但我没有成功理解我正在阅读的内容!

【问题讨论】:

    标签: python matplotlib legend


    【解决方案1】:

    我希望这就是你要找的:)

    我认为有两种解决方案:

    抱歉,我不得不模拟数据,所以情节看起来不像有序线,但我认为无论如何都没有问题

    1. 所有文件都有一个图例:
    import glob
    import pandas as pd
    import matplotlib.pyplot as plt
    import matplotlib.cm as cm
    import scipy.signal as sc
    import numpy as np
    
    dfs = [] # store df
    cmap = cm.get_cmap('Set1')
    cols = {}
    
    for i, fn in enumerate(glob.glob("*.csv")) :
        #dfs.append(pd.read_csv(fn, header=0, usecols=[2,4,6,8], skiprows=12, names=['PCB', 'FET1', 'FET2', 'FET3'])) # Uncommenting this line to read from your files should work
        dfs.append(pd.DataFrame(np.random.randn(100, 4), columns=['PCB', 'FET1', 'FET2', 'FET3'])) # Just random data
        cols[i] = cmap(i) # Maps one color to one file with a dict
    
    mrks = {"PCB":'+',"FET1":'v',"FET2":'x',"FET3":'o'} # Maps one sensor to one marker type
    
    fig, ax = plt.subplots(figsize=(12,12))
    for n, d in enumerate(dfs) :
        ax.plot(sc.decimate(d['PCB'],5), ls='-', marker=mrks['PCB'], color=cols[n], label="PCB") # Use label to map to files
        ax.plot(sc.decimate(d['FET1'],5), ls='-', marker=mrks['FET1'], color=cols[n], label="FET1")
        ax.plot(sc.decimate(d['FET2'],5), ls='-', marker=mrks['FET2'], color=cols[n], label="FET2")
        ax.plot(sc.decimate(d['FET3'],5), ls='-', marker=mrks['FET3'], color=cols[n], label="FET3")
    
    ax.legend()
    plt.show()
    

    给出这个情节:

    1. 带有单独的图例(抱歉,在我的示例中,我交换了位置,但您可以轻松调整它
    import glob
    import pandas as pd
    import matplotlib.pyplot as plt
    import matplotlib.cm as cm
    import scipy.signal as sc
    import numpy as np
    from matplotlib.lines import Line2D
    
    # create a marker for each thermocouple
    mrks = {"PCB":'+',"FET1":'v',"FET2":'x',"FET3":'o'}
    marker_legend = [Line2D([0], [0], lw=1, color="k", marker=v, label=k) for k, v in mrks.items()]
    color_legend = []
    
    dfs = [] # store df
    cmap = cm.get_cmap('Set1')
    cols = {}
    for i, fn in enumerate(glob.glob("*.csv")) : # read files and map colors to each
        #dfs.append(pd.read_csv(fn, header=0, usecols=[2,4,6,8], skiprows=12, names=['PCB', 'FET1', 'FET2', 'FET3']))
        dfs.append(pd.DataFrame(np.random.randn(100, 4), columns=['PCB', 'FET1', 'FET2', 'FET3']))
        cols[i] = cmap(i)
        color_legend.append(Line2D([0], [0], color=cmap(i), lw=1, label=fn))
    
    fig, ax = plt.subplots(figsize=(12,12))
    for n, d in enumerate(dfs) :
        ax.plot(sc.decimate(d['PCB'],5), ls='-', marker=mrks['PCB'], color=cols[n])
        ax.plot(sc.decimate(d['FET1'],5), ls='-', marker=mrks['FET1'], color=cols[n])
        ax.plot(sc.decimate(d['FET2'],5), ls='-', marker=mrks['FET2'], color=cols[n])
        ax.plot(sc.decimate(d['FET3'],5), ls='-', marker=mrks['FET3'], color=cols[n])
    
    first_legend = plt.legend(handles=marker_legend, loc="upper left")
    ax = plt.gca().add_artist(first_legend)
    second_legend = plt.legend(handles=color_legend, loc="upper right")
    
    plt.show()
    

    这是结果图:

    如果您不想使用 matplotlib 中的 cmap,您仍然可以创建一个颜色列表,您知道该列表将比您从中读取和绘制的文件数长,而不是像这样:

    cmap = ["r","g","b","cyan", ...]
    ...
    for i, fn in enumerate(glob.glob("*.csv")) :
       ...
       cols[i] = cmap[i]
       ...
    

    【讨论】:

    • 这正是我想要的。我很感激有多种选择可以帮助我了解如何创建不同的图例。谢谢。
    【解决方案2】:

    循环中相同调用绘制的每个图都会重写图例,即使数据不同。因此,您需要保存它们,然后在无法再覆盖后将它们添加到图例中。

    fig = plt.figure()
    lines = []
    colors=['r','b','g','c','m']
    for i in range(len(filename)):
        l=plt.plot(sc.decimate(x[i]['PCB'],5),'-+'+colors[i],label="PCB")
        lines=np.append(lines,l)
        l=plt.plot(sc.decimate(x[i]['FET1'],5),'-v'+colors[i],label='FET1')
        lines=np.append(lines,l)
        l=plt.plot(sc.decimate(x[i]['FET2'],5),'-x'+colors[i],label='FET2')
        lines=np.append(lines,l)
        l=plt.plot(sc.decimate(x[i]['FET3'],5),'-o'+colors[i],label='FET3')
        lines=np.append(lines,l)
    
    fig.legend(lines)
    plt.show()
    

    这将提供具有交替颜色的len(filename)*4 大小图例。如果您只想为每个文件提供颜色,您可以为每个 i 保存一行。

    fig = plt.figure()
    lines = []
    names = []
    colors=['r','b','g','c','m']
    for i in range(len(filename)):
        l=plt.plot(sc.decimate(x[i]['PCB'],5),'-+'+colors[i],label="PCB")
        lines=np.append(lines,l)
        names=np.append(names, filename[i][0:7])
        plt.plot(sc.decimate(x[i]['FET1'],5),'-v'+colors[i],label='FET1')
        plt.plot(sc.decimate(x[i]['FET2'],5),'-x'+colors[i],label='FET2')
        plt.plot(sc.decimate(x[i]['FET3'],5),'-o'+colors[i],label='FET3')
    
    fig.legend(lines,labels=names)
    plt.show()
    

    编辑:作为第三个选项,您还可以直接存储第一行集合的图例句柄并在以后设置它们。为了使其正常工作,您需要将其他人设置为没有图例。假设您无论如何都不在绘图中显示这些标签,这也是一种选择。

    lines = []
    names = []
    colors=['r','b','g','c','m']
    for i in range(len(filename)):
        plt.plot(sc.decimate(x[i]['PCB'],5),'-+'+colors[i],label="PCB")
        handles, labels = plt.gca().get_legend_handles_labels()
        lines=np.append(lines,handles[0])
        names=np.append(names, filename[i][0:7])
        plt.plot(sc.decimate(x[i]['FET1'],5),'-v'+colors[i],label='_nolegend_')
        plt.plot(sc.decimate(x[i]['FET2'],5),'-x'+colors[i],label='_nolegend_')
        plt.plot(sc.decimate(x[i]['FET3'],5),'-o'+colors[i],label='_nolegend_')
    
    plt.legend(lines,labels=names)
    plt.show()
    

    【讨论】:

    • 谢谢您....对于您的第二个选项,图例确实显示了文件名,但标记和颜色是错误的.....根据您提供的代码,我预计行是每个文件中的 PCB 线列表。相反,图例显示所有红线,并且每个文件名都有一个不同的标记。我不明白为什么/如何拾取其他标记(它们都应该是“+”),而唯一存储的标记应该是来自 PCB 绘图线的标记......,另外,我将如何从第一个选项中删除每个图例标签的“line2D”部分?再次感谢。
    • 好的,如果将“lines”分配更改为“lines=np.append(lines,l[0].get_label())”,我可以取回“PCB”、“FET1” 、“FET2”等标签。我想我需要做的是 2 个图例,一个显示指示 PCB、FET1、FET2、FET3 的标记,另一个显示什么颜色与什么文件搭配的图例.....
    • 我放了第三个选项来保存图例句柄而不是行集合。图例中的线标记现在都是+。
    猜你喜欢
    • 2021-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多