首页 > 解决方案 > 使用 matplotlib 为不同的 y 值创建带有彩色线条的折线图

问题描述

在此处输入图像描述

我是 python 的新手,最近经常使用 pandas 和 matplotlib 来显示工作中的数据。我正在尝试绘制振动图表,其中 x 轴是深度(以米为单位),y 轴是振动水平(最大轴向 Z)。我想以 4 种不同颜色显示振动水平:

我已经阅读了 matplotlib 多色线的文档,并设法生成了我想要创建的图。但是我仍然不明白它为什么起作用,有些行我不理解代码以及它在我的情节中是如何工作的,这就是为什么我发布这个问题以获得一些清晰度。我的问题:

非常感谢你的帮助 !

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
from matplotlib.colors import ListedColormap, BoundaryNorm

df = pd.read_excel("C:/Users/AmeliaB/Documents/Python/8-5in_plotting.xlsx", header=0)
df['DATETIME'] = pd.to_datetime(df.DATETIME)
# define variables
y = np.array(df["DHT001_Accel_Axial_Z_Max"])
x = np.array(df["Hole_Depth"])

# Create a set of line segments so we can color them individually
# This creates the points as a N x 1 x 2 array so that we can stack points
# together easily to get the segments. The segments array for line collection
# needs to be (numlines) x (points per line) x 2 (for x and y)
points = np.array([x, y]).T.reshape(-1, 1, 2)
segments = np.concatenate([points[:-1], points[1:]], axis=1)

fig, ax = plt.subplots(1)

cmap = ListedColormap(['green', 'orange', 'red', "maroon"])
norm = BoundaryNorm([1, 1.5, 2.5, 5, 5.5], cmap.N)
lc = LineCollection(segments, cmap=cmap, norm=norm)
lc.set_array(y)
lc.set_linewidth(1)  # The thickness of the line
ax.add_collection(lc)
ax.autoscale_view()
fig.colorbar(lc) #Add colorbar
plt.xlabel ("Hole depth")
plt.ylabel ("Vibration level")
plt.show()

标签: pythonmatplotlib

解决方案


点和段有什么用?为什么我必须重塑和连接它们?

[x0, x1, x2, ...]标准绘图使用 x 值 (和 y 值 ( )的数组[y0, y1, y2, ...]。这些将作为点连接(x0, y0)(x1, y1)to (x2, y2)... 。但是这种方法只允许为所有内容使用一种颜色。

您复制的解决方案使用单线段,第一段是“(x0, y0)(x1, y1)”。第二段再利用(x1, y1)(x1, y1)拉到(x2, y2)。这样的片段可以被赋予单独的颜色。为此,需要将每个段表示为[[x0, y0], [x1, y1]](二维数组)。这些段可以从原始的 x 和 y 数组创建。所有段一起形成一个 3D 数组[[[x0, y0], [x1, y1]], [[x1, y1], [x2, y2]], ... ]

相关代码如下:

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

np.array([x, y])创建一个包含 x 和相应 y 位置的 2xN 数组。调用.T将其转置为 Nx2 数组。为了使其类似于 3D 段数组所需的结构,点数组被重新整形为 Nx1x2 数组(请注意,-1这里被替换为在重新整形的数组中具有与原始数组中相同数量的元素所需的值) . 现在点有结构[[[x0, y0]], [[x1, y1]], ...]

points[:-1]只是除了最后一个点之外的所有点的列表。这些可用于段的起点。

同样,points[1:]只是除第一个点之外的所有点的列表。这些可用于段的端点。

np.concatenate([..., ..., axis=1)axis=1在segments数组的结构中通过它们的第二维()将两个点列表连接在一起。因此,这将创建所需的段列表:[[[x0, y0], [x1, y1]], [[x1, y1], [x2, y2]], ... ].

lc.set_array(y) 在这段代码中做了什么?

这里set_array为每个线段的每个人分配一个“颜色值”。y可以使用任何其他数值来代替。替换yx将具有沿 x 轴的颜色。这些“颜色值”使用分配的颜色图转换为真实颜色。最低的值将被映射到最低的颜色,最高的值将被映射到最高的颜色,其余的平滑地介于两者之间。(这也适用于连续的颜色图,例如从蓝色到白色到红色的范围。)

有什么办法可以让代码更短更整洁,尤其是我分配标签、线宽和自动查看的部分?我可以将它们全部组合在一条线上吗?而不是为每个属性编写每一行。

现在有 3 个简单的调用,您可以在其中以清晰的方式添加额外的参数(字体大小、颜色、...)。只需省略您不需要的参数和调用,matplotlib 将提供足够的默认值。将所有内容更改为一个复杂的调用,其中不清楚哪个设置适用于什么,可读性和维护难度会降低。

通常,在绘制曲线时,会自动计算 x 轴和 y 轴的限制。但是对于线段,轴限制不会被修改(这允许在保留初始限制的同时将箭头和辅助线添加到绘图中)。如果需要,调用ax.autoscale_view()将重新计算限制。


推荐阅读