【问题标题】:matplotlib color line by "value" [duplicate]matplotlib颜色线由“值”[重复]
【发布时间】:2018-05-21 02:36:59
【问题描述】:

之前有人问过这个问题的各种版本,我不确定我是应该在其中一个线程上提问还是开始一个新线程。如下:

我有一个 pandas 数据框,其中有一列(例如:速度)我正在尝试绘制,然后是另一列(例如:活动),目前为真/假。根据 active 的值,我想为线图着色。

这个帖子似乎是“正确”的解决方案,但我遇到了一个问题: seaborn or matplotlib line chart, line color depending on variable OP 和我正在努力实现同样的目标:

这是一个损坏的情节/复制器:

Values=[3,4,6, 6,5,4, 3,2,3, 4,5,6]
Colors=['red','red', 'red', 'blue','blue','blue', 'red', 'red', 'red', 'blue', 'blue', 'blue']
myf = pd.DataFrame({'speed': Values, 'colors': Colors})

grouped = myf.groupby('colors')
fig, ax = plt.subplots(1)

for key, group in grouped:
   group.plot(ax=ax, y="speed", label=key, color=key)

结果图有两个问题:不仅改变的颜色线没有“连接”,而且颜色本身“跨”端点连接:

我想看到的是从红色到蓝色的变化,看起来就像是一条连续的线。

Color line by third variable - Python 似乎做了正确的事情,但我不是在处理“线性”颜色数据。我基本上是在列中分配一组线条颜色。我可以轻松地将颜色列的值设置为数字:

Colors=['1','1', '1', '2','2'...]

如果这样可以更容易地生成所需的图。

第一个帖子里有评论:

如果您在颜色更改时复制点,您可以这样做,我已经 修改后的答案

但我基本上是复制并粘贴了答案,所以我不确定该评论是否完全准确。

【问题讨论】:

    标签: python pandas matplotlib plot colors


    【解决方案1】:

    我试了一下。按照您链接的另一个问题中的 cmets 将我带到this。我确实必须深入到 matplotlib 并且不能在 pandas 本身中做到这一点。一旦我将数据框转换为列表,它的代码与mpl page 中的代码几乎相同。

    我创建了类似于你的数据框:

    vals=[3,4,6, 6,5,4, 3,2,3, 4,5,6]
    colors=['red' if x < 5 else 'blue' for x in vals]
    df = pd.DataFrame({'speed': vals, 'danger': colors})
    

    将 val 和索引转换为列表

    x = df.index.tolist()
    y = df['speed'].tolist()
    z = np.array(list(y))
    

    将 val 和索引分解为点,然后创建线段 离开他们。

    points = np.array([x, y]).T.reshape(-1, 1, 2)
    segments = np.concatenate([points[:-1], points[1:]], axis=1)
    

    根据创建数据框时使用的标准创建颜色图。在我的情况下,速度小于 5 是红色的,其余是蓝色的。

    cmap = ListedColormap(['r', 'b'])
    norm = BoundaryNorm([0, 4, 10], cmap.N)
    

    创建线段并相应地分配颜色

    lc = LineCollection(segments, cmap=cmap, norm=norm)
    lc.set_array(z)
    

    情节!

    fig = plt.figure()
    plt.gca().add_collection(lc)
    plt.xlim(min(x), max(x))
    plt.ylim(0, 10)
    

    这是输出:

    注意:在当前代码中,线段的颜色取决于起点。但希望这能给你一个想法。

    在这里回答问题我还是个新手。让我知道是否需要添加/删除一些细节。谢谢!

    【讨论】:

    • 感谢您的回复!这是如此接近。这就要求speed的数值与颜色对应。在我的特殊情况下,虽然这里没有直接说明,但我根据数据框中的另一列手动设置颜色,这就是为什么我有明确的颜色分配。 speed 这里的实际值并不是决定颜色的因素。
    • 我正在尝试做同样的事情,即另一列上线条的基本颜色。例如我有一个值为“a”或“b”的第三列。我想以此列为基础线段的颜色。你是怎么做到的?
    【解决方案2】:

    设置

    import pandas as pd
    import matplotlib.pyplot as plt
    %matplotlib inline
    
    Values=[3,4,6, 6,5,4, 3,2,3, 4,5,6]
    Colors=['red','red', 'red', 'blue','blue','blue', 'red', 'red', 'red', 'blue', 'blue', 'blue']
    myf = pd.DataFrame({'speed': Values, 'colors': Colors})
    

    解决方案

    1。根据Pandas "diff()" with string 检测颜色变化点并标记连续颜色的子组

    myf['change'] = myf.colors.ne(myf.colors.shift().bfill()).astype(int)
    myf['subgroup'] = myf['change'].cumsum()
    
    myf
       colors  speed  change  subgroup
    0     red      3       0         0
    1     red      4       0         0
    2     red      6       0         0
    3    blue      6       1         1
    4    blue      5       0         1
    5    blue      4       0         1
    6     red      3       1         2
    7     red      2       0         2
    8     red      3       0         2
    9    blue      4       1         3
    10   blue      5       0         3
    11   blue      6       0         3
    

    2。在索引中创建间隙以适应颜色子组之间的重复行

    myf.index += myf['subgroup'].values
    
    myf
       colors  speed  change  subgroup
    0     red      3       0         0
    1     red      4       0         0
    2     red      6       0         0
    4    blue      6       1         1  # index is now 4; 3 is missing
    5    blue      5       0         1
    6    blue      4       0         1
    8     red      3       1         2  # index is now 8; 7 is missing
    9     red      2       0         2
    10    red      3       0         2
    12   blue      4       1         3  # index is now 12; 11 is missing
    13   blue      5       0         3
    14   blue      6       0         3
    

    3。保存每个子组第一行的索引

    first_i_of_each_group = myf[myf['change'] == 1].index
    
    first_i_of_each_group
    Int64Index([4, 8, 12], dtype='int64')
    

    4。将每个组的 first 行复制到前一个组的 last 行

    for i in first_i_of_each_group:
        # Copy next group's first row to current group's last row
        myf.loc[i-1] = myf.loc[i]
        # But make this new row part of the current group
        myf.loc[i-1, 'subgroup'] = myf.loc[i-2, 'subgroup']
    # Don't need the change col anymore
    myf.drop('change', axis=1, inplace=True)
    myf.sort_index(inplace=True)
    # Create duplicate indexes at each subgroup border to ensure the plot is continuous.
    myf.index -= myf['subgroup'].values
    
    myf
       colors  speed  subgroup
    0     red      3         0
    1     red      4         0
    2     red      6         0
    3    blue      6         0  # this and next row both have index = 3
    3    blue      6         1  # subgroup 1 picks up where subgroup 0 left off
    4    blue      5         1
    5    blue      4         1
    6     red      3         1
    6     red      3         2
    7     red      2         2
    8     red      3         2
    9    blue      4         2
    9    blue      4         3
    10   blue      5         3
    11   blue      6         3
    

    5。情节

    fig, ax = plt.subplots()
    for k, g in myf.groupby('subgroup'):
        g.plot(ax=ax, y='speed', color=g['colors'].values[0], marker='o')
    ax.legend_.remove()
    

    【讨论】:

      猜你喜欢
      • 2019-11-29
      • 1970-01-01
      • 2018-11-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-31
      • 2018-08-24
      • 1970-01-01
      相关资源
      最近更新 更多