Skip to content

Simple function for multicolor line #6040

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

Open
anntzer opened this issue Feb 22, 2016 · 9 comments
Open

Simple function for multicolor line #6040

anntzer opened this issue Feb 22, 2016 · 9 comments
Labels
keep Items to be ignored by the “Stale” Github Action New feature

Comments

@anntzer
Copy link
Contributor

anntzer commented Feb 22, 2016

A simple function for a multicolor line (à la http://matplotlib.org/examples/pylab_examples/multicolored_line.html) could be helpful, as the recipe is not that trivial. Shoehorning this into plot is probably going to be difficult, so I'd suggest something like

def plot_multicolor(
    x, y, *,
    line_data=None, line_vmin=None, line_vmax=None, line_norm=None, line_cmap=None,
    point_data=None, point_vmin=None, point_vmax=None, point_norm=None, point_cmap=None,
    vmin=None, vmax=None, norm=None, cmap=None, **properties): ...

(so that both line colors and marker colors can be set; the last line of properties provide defaults if only one of them has to be set, mostly for convenience).
Thoughts?

@tacaswell tacaswell added this to the 2.1 (next point release) milestone Feb 22, 2016
@tacaswell
Copy link
Member

Please do not try to shoe-horn it into plot. There are already too much complexity / magic in that method.

Instead of having a third set of vmin, ... maybe allow the point set of them to take 'line' as a valid input and 'marker' for the line version. If everything is None, just fall back to plot?

@anntzer
Copy link
Contributor Author

anntzer commented Feb 24, 2016

Yup, I wouldn't want to touch plot with a ten foot pole. Perhaps something like

def plot_multi(
    x, y, *, line=None, marker=None, **line_and_marker_properties)

where line and marker can be dicts with a (required) "data" entry (of the correct size, i.e. len(x) for marker but len(x) - 1 for line) and additional entries corresponding respectively to line or marker props, which would override the defaults set in **line_and_marker_properties?

@WeatherGod
Copy link
Member

Remember, we still support python 2.7, so required kwargs aren't available
to us (not having that in __future__ is my biggest gripe about the
2.x->3.x transition).

On Wed, Feb 24, 2016 at 2:35 AM, Antony Lee notifications@github.com
wrote:

Yup, I wouldn't want to touch plot with a ten foot pole. Perhaps
something like

def plot_multi(
x, y, _, line=None, marker=None, *_line_and_marker_properties)

where line and marker can be dicts with a (required) "data" entry (of the
correct size, i.e. len(x) for marker but len(x) - 1 for line) and
additional entries corresponding respectively to line or marker props,
which would override the defaults set in **line_and_marker_properties?


Reply to this email directly or view it on GitHub
#6040 (comment)
.

@anntzer
Copy link
Contributor Author

anntzer commented Feb 24, 2016

Yup, this is just to discuss the API, if we go this route we can always use kwargs-popping.

@dopplershift
Copy link
Contributor

I have an implementation of something like this over in MetPy. I'm not saying it's bullet proof, but I'll offer it as a starting point of the implementation:

def colored_line(x, y, c, **kwargs):
    """Helper function to take a set of points and turn them into a collection of
    lines colored by another array

    Parameters
    ----------
    x : array-like
        x-axis coordinates
    y : array-like
        y-axis coordinates
    c : array-like
        values used for color-mapping
    kwargs : dict
        Other keyword arguments passed to :class:`matplotlib.collections.LineCollection`

    Returns
    -------
        The created :class:`matplotlib.collections.LineCollection` instance.
    """
    # Paste values end to end
    points = concatenate([x, y])

    # Exploit numpy's strides to present a view of these points without copying.
    # Dimensions are (segment, start/end, x/y). Since x and y are concatenated back to back,
    # moving between segments only moves one item; moving start to end is only an item;
    # The move between x any moves from one half of the array to the other
    num_pts = points.size // 2
    final_shape = (num_pts - 1, 2, 2)
    final_strides = (points.itemsize, points.itemsize, num_pts * points.itemsize)
    segments = np.lib.stride_tricks.as_strided(points, shape=final_shape,
                                               strides=final_strides)

    # Create a LineCollection from the segments and set it to colormap based on c
    lc = LineCollection(segments, **kwargs)
    lc.set_array(c)
    return lc

Then again, maybe stride_tricks is a bit too much magic to bite off...

@tacaswell
Copy link
Member

I would also add that there was some discussion about making a new python3 only module and this seems like a good candidate to be the first thing in there.

@anntzer
Copy link
Contributor Author

anntzer commented Jun 1, 2016

I noticed that LineCollection has a much worse performance than a normal plot. plot can handle hundreds of thousands of points instantly, but just creating the LineCollection is already pretty slow:

x = y = np.arange(100000)
c = np.ones_like(x)

ax.plot(x, y) # ~5ms.
colored_line(x, y, c) # > 1s. 

mostly because it needs to create a bunch of Path objects.

@efiring
Copy link
Member

efiring commented Jun 1, 2016

  1. Regarding API and functionality, I suggest leaving out the marker part. I think that scatter already handles that case.
  2. LineCollection is designed for speeding up the rendering of a moderately large number of lines. A more fair comparison would be to using plot to make 100000 individual lines. (Also, in your test case, path simplification is knocking out most of the points in the plot call.)

Nevertheless, if you can find a more efficient way to accomplish the colored_line functionality, that would be great. You might be able to take advantage of path simplification in the case where there are too many data points for the available resolution.

@tacaswell tacaswell modified the milestones: 2.1 (next point release), 2.2 (next next feature release) Oct 3, 2017
@efiring efiring modified the milestones: needs sorting, v3.2.0 Jun 24, 2019
@anntzer anntzer modified the milestones: v3.2.0, unassigned Aug 12, 2019
@story645 story645 modified the milestones: unassigned, needs sorting Oct 6, 2022
@github-actions
Copy link

github-actions bot commented Oct 9, 2023

This issue has been marked "inactive" because it has been 365 days since the last comment. If this issue is still present in recent Matplotlib releases, or the feature request is still wanted, please leave a comment and this label will be removed. If there are no updates in another 30 days, this issue will be automatically closed, but you are free to re-open or create a new issue if needed. We value issue reports, and this procedure is meant to help us resurface and prioritize issues that have not been addressed yet, not make them disappear. Thanks for your help!

@github-actions github-actions bot added the status: inactive Marked by the “Stale” Github Action label Oct 9, 2023
@jklymak jklymak added keep Items to be ignored by the “Stale” Github Action and removed status: inactive Marked by the “Stale” Github Action labels Oct 9, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
keep Items to be ignored by the “Stale” Github Action New feature
Projects
None yet
Development

No branches or pull requests

7 participants