0

enter image description here

I'm quite new in python and been working with pandas & matplotlib a lot recently to display data at work. 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:

  • Green is for low level (values <= 1.5)
  • Orange for medium (values 1.5 < 2.5)
  • Red for high (values 2.5 < 5)
  • Maroon for severe (values >= 5).

I have read documentation for matplotlib multicolored line and managed to produce a plot that i want to create. 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?
  • 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()

1 Answer 1

1

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.

The solution you copied, uses single line segments, the first segment is "(x0, y0) to (x1, y1)". The second segment reuses (x1, y1), drawing (x1, y1) to (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). These segments can be created from the original x and y arrays. All segments together form a 3D array [[[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. Calling .T transposes this to a Nx2 array. 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). Now the points have the structure [[[x0, y0]], [[x1, y1]], ...]

points[:-1] is just a list of all points except the last one. These can be used for the starting points of the segments.

Similarly, points[1:] is just a list of all points except the first. 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. So, this creates the desired list of segments: [[[x0, y0], [x1, y1]], [[x1, y1], [x2, y2]], ... ].

what does lc.set_array(y) do in this code?

Here set_array assigns one "color value" to each individual each line segment. Instead of y any other numerical value could be used. Replacing y by x would have the colors following the x-axis. 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. Just leave out the parameters and calls you don't need, matplotlib will provide adequate defaults. 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. 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.

Sign up to request clarification or add additional context in comments.

1 Comment

Hi @JohanC Thank you so much for the thorough explanation! Now it makes more sense to me. I did not know before that line segment requires 3D array... thankyou :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.