近来需要画一个多段折线图,并且每段颜色都不一样,搜索得知,大部分已有的实现都是基于 matplotlibLineCollection

1
from matplotlib.collections import LineCollection

这种方式还要自己组装 segments ,略显晦涩,索性自己实现了。效果如下:

segmented-color buyixiao blog

其中 x,y 序列大致如下,没什么特殊的。

1
2
3
4
5
6
7
8
9
10
x
['2023-02-06 12', '2023-02-06 18', '2023-02-07 00', '2023-02-07 06', '2023-02-07 12', '2023-02-07 18', '2023-02-08 00', '2023-02-08 06', '2023-02-08 12', '2023-02-08 18', '2023-02-09 00', '2023-02-09 06', '2023-02-09 12', '2023-02-09 18', '2023-02-10 00', '2023-02-10 06', '2023-02-10 12', '2023-02-10 18', '2023-02-11 00', '2023-02-11 06', '2023-02-11 12', '2023-02-11 18', '2023-02-12 00', '2023-02-12 06', '2023-02-12 12', '2023-02-12 18', '2023-02-13 00', '2023-02-13 06', '2023-02-13 12', '2023-02-13 18', '2023-02-14 00', '2023-02-14 06', '2023-02-14 12', '2023-02-14 18', '2023-02-15 00', '2023-02-15 06', '2023-02-15 12', '2023-02-15 18', '2023-02-16 00', '2023-02-16 06', '2023-02-16 12', '2023-02-16 18', '2023-02-17 00', '2023-02-17 06', ...]

y
[ 1 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 1 1 3 0 1 2 0 0 0 0 0 0
0 0 0 0 0 1 0 0 1 0 0 0 0 0
0 0 0 0 2 0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 1 4 375 83 145 15 197 264
135 47 164 69 116 39 109 41 54 16 20 13 27 17...]

均分多段

第一种需求是均分多段,即等分折现,其实现代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# -*- coding: utf-8 -*-
# author: inspurer(月小水长)
# create_time: 2023/5/13 14:31
# 运行环境 Python3.6+
# github https://github.com/inspurer
# website https://buyixiao.github.io/
# 微信公众号 月小水长

import matplotlib.pyplot as plt

import numpy as np
from matplotlib import ticker

plt.rcParams['font.sans-serif'] = ['SimHei'] # 指定默认字体
plt.rcParams['axes.unicode_minus'] = False # 解决保存图像是负号'-'显示为方块的问题


def unique_color():
return plt.cm.gist_ncar(np.random.random())


def plot_colored_seg(x, y):
"""
均分多段
"""
print('x\n', x)
print('y\n', y)

seg_x_list = []
seg_y_list = []

max_x = max(x)
max_y = max(y)

seg_cnt = 4

seg_label = [f'the label of {i}th turning point' for i in range(seg_cnt)]

seg_point_cnt = len(x) // seg_cnt

cur_seg_pointer = 1

for index, ele in enumerate(x):
if len(seg_x_list) < seg_point_cnt and index < len(x) - 1:
seg_x_list.append(ele)
seg_y_list.append(y[index])

else:
cur_color = unique_color()
plt.plot(seg_x_list, seg_y_list, color=cur_color)

if cur_seg_pointer < seg_cnt:
plt.axvline(x[index - 1], color=cur_color, linestyle="dashed")
plt.text(x[index - 1], max_y // 1.5, seg_label[cur_seg_pointer], fontsize=12,
ha='center')
seg_x_list = [x[index - 1]]
seg_y_list = [y[index - 1]]

cur_seg_pointer += 1

plt.gca().xaxis.set_major_locator(ticker.MultipleLocator(50))
plt.ylim((0, max_y))
plt.xlabel('per 6h')
plt.ylabel('period weibo cnt')
plt.show()

# to prepare your own x,y list
plot_colored_seg([str(x) for x in ts_6h.index.strftime('%Y-%m-%d %H')], ts_6h.values)

值分多段

第二种是值分多段,即按照 x 或者 y 的值划分多段,这种更灵活,可以说是均分多段的超集,其源代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# -*- coding: utf-8 -*-
# author: inspurer(月小水长)
# create_time: 2023/5/13 14:31
# 运行环境 Python3.6+
# github https://github.com/inspurer
# website https://buyixiao.github.io/
# 微信公众号 月小水长

import matplotlib.pyplot as plt

import numpy as np
from matplotlib import ticker

plt.rcParams['font.sans-serif'] = ['SimHei'] # 指定默认字体
plt.rcParams['axes.unicode_minus'] = False # 解决保存图像是负号'-'显示为方块的问题


def unique_color():
return plt.cm.gist_ncar(np.random.random())

def plot_colored_seg_2(x, y):
"""
值分多段
"""
print('x\n', x)
print('y\n', y)

seg_x_list = []
seg_y_list = []

max_x = max(x)
max_y = max(y)

turn_points_x = ['2023-03-07 06', '2023-03-16 12', '2023-04-08 06']
seg_color_list = [unique_color() for _ in range(len(turn_points_x))]

for index, ele in enumerate(x):

if ele in turn_points_x:
turn_index = turn_points_x.index(ele)
cur_color = seg_color_list[turn_index]
plt.plot(seg_x_list, seg_y_list, color=cur_color)
plt.axvline(x[index - 1], color=cur_color, linestyle="dashed")
plt.text(x[index - 1], max_y // 1.5, f'the label of {turn_index + 1}th turning point', fontsize=12,
ha='center')

seg_x_list = [x[index - 1]]
seg_y_list = [y[index - 1]]

else:
seg_x_list.append(ele)
seg_y_list.append(y[index])

plt.gca().xaxis.set_major_locator(ticker.MultipleLocator(50))
plt.ylim((0, max_y))
plt.xlabel('per 6h')
plt.ylabel('period weibo cnt')
plt.show()

# to prepare your own x,y list
plot_colored_seg_2([str(x) for x in ts_6h.index.strftime('%Y-%m-%d %H')], ts_6h.values)

转载请注明来源,如有更好的思路,欢迎留言~