简体   繁体   English

使用 matplotlib 为不同的 y 值创建带有彩色线条的折线图

[英]Create line chart with multicolored lines for different y-values with matplotlib

在此处输入图片说明

I'm quite new in python and been working with pandas & matplotlib a lot recently to display data at work.我在 python 方面很新,最近一直在使用 pandas 和 matplotlib 来显示工作中的数据。 I am trying to plot a vibration chart, where x-axis is the depth (in meter) and y-axis is the vibration level (Axial Z max.).I want to display the vibration level in 4 different colors:我正在尝试绘制振动图表,其中 x 轴是深度(以米为单位),y 轴是振动水平(轴向 Z 最大值)。我想以 4 种不同颜色显示振动水平:

  • Green is for low level (values <= 1.5)绿色代表低级别(值 <= 1.5)
  • Orange for medium (values 1.5 < 2.5)橙色为中等(值 1.5 < 2.5)
  • Red for high (values 2.5 < 5)红色表示高(值 2.5 < 5)
  • Maroon for severe (values >= 5).严重的栗色(值 >= 5)。

I have read documentation for matplotlib multicolored line and managed to produce a plot that i want to create.我已经阅读了 matplotlib 多色线的文档,并设法生成了一个我想要创建的图。 However i still don't understand why it works, there are some lines where i didn't understand the code and how it works in my plot that is why im posting this question to get some clarity.但是我仍然不明白它为什么起作用,有些行我不理解代码以及它在我的情节中是如何工作的,这就是为什么我发布这个问题以获得一些清晰度。 My questions:我的问题:

  • What are the points and segments for?点和段有什么用? Why do i have to reshape and concatenate them?为什么我必须重塑和连接它们?
  • what does lc.set_array(y) do in this code? lc.set_array(y) 在这段代码中做了什么?
  • Is there any way i can make the code shorter and more tidy especially the part where i assign label, line width and autoview?有什么办法可以让代码更短更整洁,尤其是我分配标签、线宽和自动视图的部分? Can I combine all of them in one line?我可以将所有这些组合在一行中吗? Instead of writing each line for each attribute.而不是为每个属性编写每一行。

Thank you so much for your help !非常感谢你的帮助 !

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

What are the points and segments for?点和段有什么用? Why do i have to reshape and concatenate them?为什么我必须重塑和连接它们?

A standard plot uses an array of x-values ( [x0, x1, x2, ...] and y-values ( [y0, y1, y2, ...] . These will be connected as points (x0, y0) to (x1, y1) to (x2, y2) to ... . But this approach only allows for one single color for everything.标准图使用 x 值数组 ( [x0, x1, x2, ...]和 y 值 ( [y0, y1, y2, ...] 。这些将连接为点(x0, y0) to (x1, y1) to (x2, y2) to ... . 但这种方法只允许一种颜色的一切。

The solution you copied, uses single line segments, the first segment is " (x0, y0) to (x1, y1) ".您复制的解决方案,使用单线段,第一段是“ (x0, y0) to (x1, y1) ”。 The second segment reuses (x1, y1) , drawing (x1, y1) to (x2, y2) .第二段重复使用(x1, y1) ,将(x1, y1)绘制到(x2, y2) Such segments can be given individual colors.这些段可以被赋予单独的颜色。 For this, it is needed that each segment is represented as [[x0, y0], [x1, y1]] (a 2D array).为此,需要将每个段表示为[[x0, y0], [x1, y1]] (二维数组)。 These segments can be created from the original x and y arrays.这些段可以从原始的 x 和 y 数组创建。 All segments together form a 3D array [[[x0, y0], [x1, y1]], [[x1, y1], [x2, y2]], ... ] .所有段一起形成一个 3D 数组[[[x0, y0], [x1, y1]], [[x1, y1], [x2, y2]], ... ]

The relevant code looks like:相关代码如下所示:

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

np.array([x, y]) creates a 2xN array of x and corresponding y positions. np.array([x, y])创建一个包含 x 和相应 y 位置的 2xN 数组。 Calling .T transposes this to a Nx2 array.调用.T转置为 Nx2 数组。 To make it similar to the structure needed for the 3D segments array, the points array is reshaped to a Nx1x2 array (note that -1 here gets replaced by the value needed to have the same number of elements in the reshaped array as in the original one).为了使其类似于 3D 线段数组所需的结构,点数组被重新整形为 Nx1x2 数组(请注意,这里的-1被替换为在重新整形的数组中具有与原始数组中相同数量的元素所需的值)一)。 Now the points have the structure [[[x0, y0]], [[x1, y1]], ...]现在这些点的结构为[[[x0, y0]], [[x1, y1]], ...]

points[:-1] is just a list of all points except the last one. points[:-1]只是除最后一个点之外的所有点的列表。 These can be used for the starting points of the segments.这些可用于段的起点。

Similarly, points[1:] is just a list of all points except the first.类似地, points[1:]只是除第一个之外的所有点的列表。 These can be used for the end points of the segments.这些可用于段的端点。

np.concatenate([..., ..., axis=1) joins the two lists of points together over their second dimension ( axis=1 ) in the structure for the segments array. np.concatenate([..., ..., axis=1)将两个点列表在它们的第二个维度 ( axis=1 ) 上连接到线段数组的结构中。 So, this creates the desired list of segments: [[[x0, y0], [x1, y1]], [[x1, y1], [x2, y2]], ... ] .因此,这将创建所需的段列表: [[[x0, y0], [x1, y1]], [[x1, y1], [x2, y2]], ... ]

what does lc.set_array(y) do in this code? lc.set_array(y) 在这段代码中做了什么?

Here set_array assigns one "color value" to each individual each line segment.这里set_array为每个线段的每个单独分配一个“颜色值”。 Instead of y any other numerical value could be used.可以使用任何其他数值代替y Replacing y by x would have the colors following the x-axis.x替换y将具有沿 x 轴的颜色。 These "color values" get converted to real colors using the assigned colormap.这些“颜色值”使用指定的颜色图转换为真实颜色。 The lowest of the values will be mapped to the lowest color, the highest value will be mapped to the highest color, with the rest following smoothly in-between.最低的值将映射到最低的颜色,最高的值将映射到最高的颜色,其余的将平滑地介于两者之间。 (This also works with continuous colormaps, for example a range from blue over white to red.) (这也适用于连续的颜色图,例如从蓝色到白色到红色的范围。)

Is there any way i can make the code shorter and more tidy especially the part where i assign label, line width and autoview?有什么办法可以让代码更短更整洁,尤其是我分配标签、线宽和自动视图的部分? Can I combine all of them in one line?我可以将所有这些组合在一行中吗? Instead of writing each line for each attribute.而不是为每个属性编写每一行。

There now are 3 simple calls, where you can add extra parameters (fontsize, color, ...) in a clear way.现在有 3 个简单的调用,您可以在其中以清晰的方式添加额外的参数(字体大小、颜色等)。 Just leave out the parameters and calls you don't need, matplotlib will provide adequate defaults.只需省略不需要的参数和调用,matplotlib 将提供足够的默认值。 Changing everything to one complex call, where it wouldn't be clear which setting applies to what, would be less readable and harder to maintain.将所有内容更改为一个复杂的调用,在这种调用中,不清楚哪个设置适用于什么,可读性会降低并且更难维护。

Normally, when plotting a curve, the limits for the x and y axes are calculated automatically.通常,在绘制曲线时,会自动计算 x 轴和 y 轴的限制。 But for line segments the axes limits aren't modified (this allows to add arrows and auxiliary lines to a plot while preserving the initial limits).但是对于线段,轴限制不会被修改(这允许在保留初始限制的同时向绘图添加箭头和辅助线)。 Calling ax.autoscale_view() will recalculate the limits in case it is desired.调用ax.autoscale_view()将重新计算的情况下,期望的限制。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM