Skip to content
  • Sponsor matplotlib/matplotlib

  • Notifications You must be signed in to change notification settings
  • Fork 7.9k

Simple function for multicolor line #6040

Open
@anntzer

Description

@anntzer

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?

Activity

added this to the 2.1 (next point release) milestone on Feb 22, 2016
tacaswell

tacaswell commented on Feb 22, 2016

@tacaswell
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

anntzer commented on Feb 24, 2016

@anntzer
ContributorAuthor

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

WeatherGod commented on Feb 24, 2016

@WeatherGod
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

anntzer commented on Feb 24, 2016

@anntzer
ContributorAuthor

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

dopplershift

dopplershift commented on Feb 24, 2016

@dopplershift
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

tacaswell commented on Feb 24, 2016

@tacaswell
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

anntzer commented on Jun 1, 2016

@anntzer
ContributorAuthor

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

efiring commented on Jun 1, 2016

@efiring
Member
  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.

modified the milestone: 2.1 (next point release) on Oct 3, 2017
modified the milestones: needs sorting, v3.2.0 on Jun 24, 2019

10 remaining items

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    New featurekeepItems to be ignored by the “Stale” Github Action

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      Simple function for multicolor line · Issue #6040 · matplotlib/matplotlib