-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
DOC: New color line by value example #28307
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for opening your first PR into Matplotlib!
If you have not heard from us in a week or so, please leave a new comment below and that should bring it to our attention. Most of our reviewers are volunteers and sometimes things fall through the cracks.
You can also join us on gitter for real-time discussion.
For details on testing, writing docs, and our review process, please see the developer guide
We strive to be a welcoming and open project. Please follow our Code of Conduct.
https://matplotlib.org/stable/gallery/lines_bars_and_markers/multicolored_line.html is the correct example to change. If it were me I'd add a second plot to the simpler example. I agree that this strategy is superior to what is in the current example, but it is more convoluted to follow, so I think there is value in both. |
Indeed, it makes sense to collect the content under the multicolored_line example. We could keep parts of the original example. Some suggestions on that:
|
def colored_line(x, y, c, ax, **lc_kwargs): | ||
""" | ||
Plot a line with a color specified along the line by a third value. It does this | ||
by creating a collection of line segments. Each line segment is made up of two | ||
straight lines each connecting the current (x, y) point to the midpoints of the | ||
lines connecting the current point with its two neighbors. This creates a smooth | ||
line with no gaps between the line segments. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is very minor, but I suggest that you add a new line to reflect standard docstring conventions.
def colored_line(x, y, c, ax, **lc_kwargs): | |
""" | |
Plot a line with a color specified along the line by a third value. It does this | |
by creating a collection of line segments. Each line segment is made up of two | |
straight lines each connecting the current (x, y) point to the midpoints of the | |
lines connecting the current point with its two neighbors. This creates a smooth | |
line with no gaps between the line segments. | |
def colored_line(x, y, c, ax, **lc_kwargs): | |
""" | |
Plot a line with a color specified along the line by a third value. | |
It does this by creating a collection of line segments. Each line segment | |
is made up of two straight lines each connecting the current (x, y) point | |
to the midpoints of the lines connecting the current point with its two | |
neighbors. This creates a smooth line with no gaps between the line | |
segments. |
Based on feedback, I merged the new example into the multicolored line example. It's now a bit verbose, but my goal was to put the code into well-documented functions so that using them is easy. That way users can copy these functions and use them for their own purposes without having to do too much parsing of the example. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest you make two independent code blocks for the two plots. It's simpler to follow only half of the code that is relevant for the respective plot. You may also consider giving the two variants separate sections.
Docstring structure:
"""
==================
Multicolored lines
==================
...
Color values at points
----------------------
"""
<first code block>
####################################################################
# Color values between points
# ---------------------------
# ...
<second code block>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor style suggestions.
matplotlib.collections.LineCollection | ||
The generated line collection representing the colored line. | ||
""" | ||
# Give a warning if the user specified an array keyword argument |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# Give a warning if the user specified an array keyword argument |
The comment does not add information that is not already obvious from the code.
# Create the line collection and set the colors of each segment | ||
lc = LineCollection(segments, **default_kwargs) | ||
lc.set_array(c) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# Create the line collection and set the colors of each segment | |
lc = LineCollection(segments, **default_kwargs) | |
lc.set_array(c) | |
lc = LineCollection(segments, **default_kwargs) | |
lc.set_array(c) # set the colors of each segment |
a bit more compact
lc = LineCollection(segments, **default_kwargs) | ||
lc.set_array(c) | ||
|
||
# Add the collection to the axis and return the line collection object |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# Add the collection to the axis and return the line collection object | |
# Add the collection to the Axes and return the line collection object |
But IMHO the comment is on the border of not-needed.
matplotlib.collections.LineCollection | ||
The generated line collection representing the colored line. | ||
""" | ||
# Give a warning if the user specified an array keyword argument |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# Give a warning if the user specified an array keyword argument |
as above
lines = colored_line(x, y, color, ax1, linewidth=10, cmap="plasma") | ||
cax1 = fig1.colorbar(lines) # add a color legend |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lines = colored_line(x, y, color, ax1, linewidth=10, cmap="plasma") | |
cax1 = fig1.colorbar(lines) # add a color legend | |
lines = colored_line(x, y, color, ax1, linewidth=10, cmap="plasma") | |
fig1.colorbar(lines) # add a color legend |
If return values are not used, don't assign them to variables. This keeps the code more readable.
line = colored_line_between_pts(x, y, dydx, ax2, linewidth=2, cmap="viridis") | ||
cax2 = fig2.colorbar(line, ax=ax2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
line = colored_line_between_pts(x, y, dydx, ax2, linewidth=2, cmap="viridis") | |
cax2 = fig2.colorbar(line, ax=ax2) | |
line = colored_line_between_pts(x, y, dydx, ax2, linewidth=2, cmap="viridis") | |
fig2.colorbar(line, ax=ax2, label="dy/dx") |
|
||
# Labels | ||
ax2.set_title("Color between points") | ||
cax2.set_label("dy/dx") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# Labels | |
ax2.set_title("Color between points") | |
cax2.set_label("dy/dx") | |
ax2.set_title("Color between points") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I still found some nits, but let's try to be as precise and helpful to users as possible.
Also please squash your commits. They currently add and remove a file, which CI flags as unnecessary overhead.
coord_start = np.column_stack((x_midpts[:-1], y_midpts[:-1])).reshape(x.size, 1, 2) | ||
coord_mid = np.column_stack((x, y)).reshape(x.size, 1, 2) | ||
coord_end = np.column_stack((x_midpts[1:], y_midpts[1:])).reshape(x.size, 1, 2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optional, but you could use a[:, np.newaxis, :]
instead of a.reshape(x.size, 1, 2)
, wich is slightly more telling that you only introduce an extra dimension.
coord_start = np.column_stack((x_midpts[:-1], y_midpts[:-1])).reshape(x.size, 1, 2) | |
coord_mid = np.column_stack((x, y)).reshape(x.size, 1, 2) | |
coord_end = np.column_stack((x_midpts[1:], y_midpts[1:])).reshape(x.size, 1, 2) | |
coord_start = np.column_stack((x_midpts[:-1], y_midpts[:-1]))[:, np.newaxis, :] | |
coord_mid = np.column_stack((x, y))[:, np.newaxis, :] | |
coord_end = np.column_stack((x_midpts[1:], y_midpts[1:]))[:, np.newaxis, :] |
|
||
# Compute the midpoints of the line segments. Include the first and last points | ||
# twice so we don't need any special syntax later to handle them. | ||
x_midpts = np.hstack((x[0], 0.5 * (x[1:] + x[:-1]), x[-1])) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
x_midpts = np.hstack((x[0], 0.5 * (x[1:] + x[:-1]), x[-1])) | |
x = np.asarray(x) | |
y = np.asarray(y) | |
x_midpts = np.hstack((x[0], 0.5 * (x[1:] + x[:-1]), x[-1])) |
Otherwise, we'd have to claim "array" instead of "array-like" in the docstring.
plt.show() | ||
|
||
|
||
#################################################################### |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want an additional plot to illustrate the mechanism?
#################################################################### | |
#################################################################### | |
# This method is designed to give a smooth impression when distances and color | |
# differences between adjacent points are not too large. The following example | |
# does not meet this criteria and by that serves to illustrate the segmentation | |
# and coloring mechanism. | |
x = [0, 1, 2, 3, 4] | |
y = [0, 1, 2, 1, 1] | |
c = [1, 2, 3, 4, 5] | |
fig, ax = plt.subplots() | |
ax.scatter(x, y, c=c, cmap='rainbow') | |
colored_line(x, y, c=c, ax=ax, cmap='rainbow') | |
#################################################################### |
|
||
Parameters | ||
---------- | ||
x, y : array-like or scalar |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
x, y : array-like or scalar | |
x, y : array-like |
scalars do not work because you index below. But that's ok, let's just not bother with them.
---------- | ||
x, y : array-like or scalar | ||
The horizontal and vertical coordinates of the data points. | ||
c : array-like or scalar |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As above
c : array-like or scalar | |
c : array-like |
These are useful fixes, thanks! I tried fixing the git history, but I think I may have made it worse. What git commands do I need to properly squash the previous commits? |
@eytanadler to squash, you can do an interactive rebase. I strongly recommend saving a backup copy of your branch first if you have not done this (much) before. |
bad8da4
to
19bfcf5
Compare
Thanks @eytanadler and congratulations on your first contribution to Matplotlib 🎉. We hope to hear from you again. |
@meeseeksdev backport to v3.9.x |
Thank you @timhoffm! I’ve gotten so much use out of matplotlib that contributing an example is the least I can do. |
…307-on-v3.9.x Backport PR #28307 on branch v3.9.x (DOC: New color line by value example)
* New color line example with multiple coloring methods
PR summary
I opened issue #28242, which is asking for better ways to plot a line with a color at each point assigned by a third value. @timhoffm suggested a nice way to do this. This PR adds a new example that implements his improved method.
@timhoffm said this should replace this example. @rcomer also thought this example could be replaced by it. I haven't removed either of the examples since I want to be clear on the expectations before I start deleting previous work.
The approach in previous methods produce results that look something like this:

The new approach in the provided example applied to the same plot produces this:

PR checklist