matplotlib颜色线由“值”

时间:2017-12-07 04:04:39

标签: python pandas matplotlib plot colors

之前已经问过这个问题的各种版本,我不确定我是否应该在其中一个主题上提出我的问题或者开始一个新主题。这是:

我有一个pandas数据框,其中有一个我想要绘制的列(例如:speed),然后是另一列(例如:active),现在是true / false。根据活动的值,我想为线图着色。

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

contiguous multi-colored line

这是一个破碎的情节/再现者:

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)

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

lines are non-contiguous

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

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

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

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

第一个帖子中有评论:

  

如果你在颜色改变时重复点,你可以这样做,我已经   修改后的答案

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

2 个答案:

答案 0 :(得分:2)

我对它采取了一个裂缝。根据您链接的其他问题中的评论,将我引导至this。我确实必须开始使用matplotlib并且不能在熊猫本身做到这一点。将数据框转换为列表后,其代码与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})

将vals和index转换为列表

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

将vals和index分解为点,然后创建线段 他们之外。

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)

这是输出:

enter image description here

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

我在这里回答问题还是新手。如果我需要添加/删除一些细节,请告诉我。谢谢!

答案 1 :(得分:1)

设置

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。根据{{​​3}}

检测颜色变化点和连续颜色的标签子组
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。将每个群组的第一个行复制到上一个群组最后

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()

Pandas "diff()" with string