From 78e2134d1d17f245f85b580354cd6da169a3a20b Mon Sep 17 00:00:00 2001 From: Adrien F Vincent Date: Sat, 4 Mar 2017 11:08:24 +0100 Subject: [PATCH 1/4] Naive fix for issue 8193 --- lib/matplotlib/axes/_axes.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index bfbf81bc67be..cc0777929503 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -1181,6 +1181,15 @@ def eventplot(self, positions, orientation='horizontal', lineoffsets=1, lineoffsets = [None] if len(colors) == 0: colors = [None] + try: + # Early conversion of the colors into RGBA values to take care + # of cases like colors='0.5' or colors='C1'. (Issue #8193) + colors = mcolors.to_rgba_array(colors) + except ValueError: + # Will fail if any element of *colors* is None. But as long + # as len(colors) == 1 or len(positions), the rest of the + # code should process *colors* properly. + pass if len(lineoffsets) == 1 and len(positions) != 1: lineoffsets = np.tile(lineoffsets, len(positions)) From 79c00e9900dc1ad4c06a45484cb3d232b277e282 Mon Sep 17 00:00:00 2001 From: Adrien F Vincent Date: Sun, 5 Mar 2017 11:39:30 +0100 Subject: [PATCH 2/4] Add a non-picture test dedicated to the 'colors' parameter --- lib/matplotlib/tests/test_axes.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index 94ba3119fa7f..8d0024026fe4 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -27,6 +27,7 @@ import matplotlib.colors as mcolors from numpy.testing import assert_allclose, assert_array_equal from matplotlib.cbook import IgnoredKeywordWarning +from matplotlib.cbook._backports import broadcast_to # Note: Some test cases are run twice: once normally and once with labeled data # These two must be defined in the same test function or need to have @@ -2985,6 +2986,33 @@ def test_eventplot_defaults(): colls = axobj.eventplot(data) +@pytest.mark.parametrize(('colors'), [ + ('0.5',), # string color with multiple characters: not OK before #8193 fix + ('tab:orange', 'tab:pink', 'tab:cyan', 'bLacK'), # case-insensitive + ('red', (0, 1, 0), None, (1, 0, 1, 0.5)), # a tricky case mixing types + ('rgbk',) # len('rgbk') == len(data) and each character is a valid color +]) +def test_eventplot_colors(colors): + '''Test the *colors* parameter of eventplot. Inspired by the issue #8193. + ''' + data = [[i] for i in range(4)] # 4 successive events of different nature + + # Build the list of the expected colors + expected = [c if c is not None else 'C0' for c in colors] + # Convert the list into an array of RGBA values + # NB: ['rgbk'] is not a valid argument for to_rgba_array, while 'rgbk' is. + if len(expected) == 1: + expected = expected[0] + expected = broadcast_to(mcolors.to_rgba_array(expected), (len(data), 4)) + + fig, ax = plt.subplots() + if len(colors) == 1: # tuple with a single string (like '0.5' or 'rgbk') + colors = colors[0] + collections = ax.eventplot(data, colors=colors) + + for coll, color in zip(collections, expected): + assert_allclose(coll.get_color(), color) + @image_comparison(baseline_images=['test_eventplot_problem_kwargs'], extensions=['png'], remove_text=True) def test_eventplot_problem_kwargs(): From 5214a62f52cf6bb4d60e8326816e518a15335791 Mon Sep 17 00:00:00 2001 From: Adrien F Vincent Date: Sun, 5 Mar 2017 13:18:41 +0100 Subject: [PATCH 3/4] eventplot and EventCollection docstrings overhaul (+ make the latter consistent with its behavior) --- lib/matplotlib/axes/_axes.py | 88 +++++++++++++++++++++---------- lib/matplotlib/collections.py | 80 ++++++++++++++-------------- lib/matplotlib/tests/test_axes.py | 1 + 3 files changed, 102 insertions(+), 67 deletions(-) diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index cc0777929503..4e0018d479de 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -1083,14 +1083,13 @@ def eventplot(self, positions, orientation='horizontal', lineoffsets=1, linelengths=1, linewidths=None, colors=None, linestyles='solid', **kwargs): """ - Plot identical parallel lines at specific positions. + Plot identical parallel lines at the given positions. - Plot parallel lines at the given positions. positions should be a 1D - or 2D array-like object, with each row corresponding to a row or column - of lines. + *positions* should be a 1D or 2D array-like object, with each row + corresponding to a row or column of lines. This type of plot is commonly used in neuroscience for representing - neural events, where it is commonly called a spike raster, dot raster, + neural events, where it is usually called a spike raster, dot raster, or raster plot. However, it is useful in any situation where you wish to show the @@ -1098,38 +1097,71 @@ def eventplot(self, positions, orientation='horizontal', lineoffsets=1, arrival times of people to a business on each day of the month or the date of hurricanes each year of the last century. - *orientation* : [ 'horizontal' | 'vertical' ] - 'horizontal' : the lines will be vertical and arranged in rows - 'vertical' : lines will be horizontal and arranged in columns + Parameters + ---------- + positions : 1D or 2D array-like object + Each value is an event. If *positions* is a 2D array-like, each + row corresponds to a row or a column of lines (depending on the + *orientation* parameter). + + orientation : {'horizontal', 'vertical'}, optional + Controls the direction of the event collections: - *lineoffsets* : - A float or array-like containing floats. + - 'horizontal' : the lines are arranged horizontally in rows, + and are vertical. + - 'vertical' : the lines are arranged vertically in columns, + and are horizontal. - *linelengths* : - A float or array-like containing floats. + lineoffsets : scalar or sequence of scalars, optional, default: 1 + The offset of the center of the lines from the origin, in the + direction orthogonal to *orientation*. - *linewidths* : - A float or array-like containing floats. + linelengths : scalar or sequence of scalars, optional, default: 1 + The total height of the lines (i.e. the lines stretches from + ``lineoffset - linelength/2`` to ``lineoffset + linelength/2``). - *colors* - must be a sequence of RGBA tuples (e.g., arbitrary color - strings, etc, not allowed) or a list of such sequences + linewidths : scalar, scalar sequence or None, optional, default: None + The line width(s) of the event lines, in points. If it is None, + defaults to its rcParams setting. - *linestyles* : - [ 'solid' | 'dashed' | 'dashdot' | 'dotted' ] or an array of these - values + colors : color, sequence of colors or None, optional, default: None + The color(s) of the event lines. If it is None, defaults to its + rcParams setting. - For linelengths, linewidths, colors, and linestyles, if only a single - value is given, that value is applied to all lines. If an array-like - is given, it must have the same length as positions, and each value - will be applied to the corresponding row or column in positions. + linestyles : str or tuple or a sequence of such values, optional + Default is 'solid'. Valid strings are ['solid', 'dashed', + 'dashdot', 'dotted', '-', '--', '-.', ':']. Dash tuples + should be of the form:: - Returns a list of :class:`matplotlib.collections.EventCollection` - objects that were added. + (offset, onoffseq), - kwargs are :class:`~matplotlib.collections.LineCollection` properties: + where *onoffseq* is an even length tuple of on and off ink + in points. + + **kwargs : optional + Other keyword arguments are line collection properties. See + :class:`~matplotlib.collections.LineCollection` for a list of + the valid properties. + + Returns + ------- + + A list of :class:`matplotlib.collections.EventCollection` objects that + were added. + + Notes + ----- + + For *linelengths*, *linewidths*, *colors*, and *linestyles*, if only + a single value is given, that value is applied to all lines. If an + array-like is given, it must have the same length as *positions*, and + each row of the array will be applied to the corresponding row or + column of events. + + Example + ------- - %(LineCollection)s + .. plot:: mpl_examples/pylab_examples/eventplot_demo.py """ self._process_unit_info(xdata=positions, ydata=[lineoffsets, linelengths], diff --git a/lib/matplotlib/collections.py b/lib/matplotlib/collections.py index d9aaacf57eaa..3cf72314d20d 100644 --- a/lib/matplotlib/collections.py +++ b/lib/matplotlib/collections.py @@ -1240,15 +1240,15 @@ class EventCollection(LineCollection): ''' A collection of discrete events. - An event is a 1-dimensional value, usually the position of something along - an axis, such as time or length. Events do not have an amplitude. They - are displayed as v + The events are given by a 1-dimensional array, usually the position of + something along an axis, such as time or length. They do not have an + amplitude and are displayed as vertical or horizontal parallel bars. ''' _edge_default = True def __init__(self, - positions, # Can be None. + positions, # Cannot be None. orientation=None, lineoffset=0, linelength=1, @@ -1259,58 +1259,60 @@ def __init__(self, **kwargs ): """ - *positions* - a sequence of numerical values or a 1D numpy array. Can be None + Parameters + ---------- + positions : 1D array-like object + Each value is an event. - *orientation* [ 'horizontal' | 'vertical' | None ] - defaults to 'horizontal' if not specified or None + orientation : {None, 'horizontal', 'vertical'}, optional + The orientation of the **collection** (the event bars are along + the orthogonal direction). Defaults to 'horizontal' if not + specified or None. - *lineoffset* - a single numerical value, corresponding to the offset of the center - of the markers from the origin + lineoffset : scalar, optional, default: 0 + The offset of the center of the markers from the origin, in the + direction orthogonal to *orientation*. - *linelength* - a single numerical value, corresponding to the total height of the - marker (i.e. the marker stretches from lineoffset+linelength/2 to - lineoffset-linelength/2). Defaults to 1 + linelength : scalar, optional, default: 1 + The total height of the marker (i.e. the marker stretches from + ``lineoffset - linelength/2`` to ``lineoffset + linelength/2``). - *linewidth* - a single numerical value + linewidth : scalar or None, optional, default: None + If it is None, defaults to its rcParams setting, in sequence form. - *color* - must be a sequence of RGBA tuples (e.g., arbitrary color - strings, etc, not allowed). + color : color, sequence of colors or None, optional, default: None + If it is None, defaults to its rcParams setting, in sequence form. - *linestyle* [ 'solid' | 'dashed' | 'dashdot' | 'dotted' ] + linestyle : str or tuple, optional, default: 'solid' + Valid strings are ['solid', 'dashed', 'dashdot', 'dotted', + '-', '--', '-.', ':']. Dash tuples should be of the form:: - *antialiased* - 1 or 2 + (offset, onoffseq), - If *linewidth*, *color*, or *antialiased* is None, they - default to their rcParams setting, in sequence form. + where *onoffseq* is an even length tuple of on and off ink + in points. - *norm* - None (optional for :class:`matplotlib.cm.ScalarMappable`) - *cmap* - None (optional for :class:`matplotlib.cm.ScalarMappable`) + antialiased : {None, 1, 2}, optional + If it is None, defaults to its rcParams setting, in sequence form. - *pickradius* is the tolerance for mouse clicks picking a line. - The default is 5 pt. + **kwargs : optional + Other keyword arguments are line collection properties. See + :class:`~matplotlib.collections.LineCollection` for a list of + the valid properties. - The use of :class:`~matplotlib.cm.ScalarMappable` is optional. - If the :class:`~matplotlib.cm.ScalarMappable` array - :attr:`~matplotlib.cm.ScalarMappable._A` is not None (i.e., a call to - :meth:`~matplotlib.cm.ScalarMappable.set_array` has been made), at - draw time a call to scalar mappable will be made to set the colors. + Example + ------- + + .. plot:: mpl_examples/pylab_examples/eventcollection_demo.py """ segment = (lineoffset + linelength / 2., lineoffset - linelength / 2.) - if len(positions) == 0: + if positions is None or len(positions) == 0: segments = [] elif hasattr(positions, 'ndim') and positions.ndim > 1: - raise ValueError('if positions is an ndarry it cannot have ' - 'dimensionality great than 1 ') + raise ValueError('positions cannot have a dimensionality greater ' + 'than 1 (in the ndarray sense)') elif (orientation is None or orientation.lower() == 'none' or orientation.lower() == 'horizontal'): positions.sort() diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index 8d0024026fe4..b58345a51184 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -3013,6 +3013,7 @@ def test_eventplot_colors(colors): for coll, color in zip(collections, expected): assert_allclose(coll.get_color(), color) + @image_comparison(baseline_images=['test_eventplot_problem_kwargs'], extensions=['png'], remove_text=True) def test_eventplot_problem_kwargs(): From 4d4fe0708beb9b8c8f4e09b28f61b115b1faf8a6 Mon Sep 17 00:00:00 2001 From: Adrien F Vincent Date: Wed, 22 Mar 2017 08:33:12 +0100 Subject: [PATCH 4/4] Fix the phrasing of some sentences. --- lib/matplotlib/axes/_axes.py | 3 +-- lib/matplotlib/collections.py | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index 4e0018d479de..ba530a56282b 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -1155,8 +1155,7 @@ def eventplot(self, positions, orientation='horizontal', lineoffsets=1, For *linelengths*, *linewidths*, *colors*, and *linestyles*, if only a single value is given, that value is applied to all lines. If an array-like is given, it must have the same length as *positions*, and - each row of the array will be applied to the corresponding row or - column of events. + each value will be applied to the corresponding row of the array. Example ------- diff --git a/lib/matplotlib/collections.py b/lib/matplotlib/collections.py index 3cf72314d20d..eec3afa45dec 100644 --- a/lib/matplotlib/collections.py +++ b/lib/matplotlib/collections.py @@ -1311,8 +1311,8 @@ def __init__(self, if positions is None or len(positions) == 0: segments = [] elif hasattr(positions, 'ndim') and positions.ndim > 1: - raise ValueError('positions cannot have a dimensionality greater ' - 'than 1 (in the ndarray sense)') + raise ValueError('positions cannot be an array with more than ' + 'one dimension.') elif (orientation is None or orientation.lower() == 'none' or orientation.lower() == 'horizontal'): positions.sort() pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy