8000 Merge pull request #8861 from tacaswell/fix_eventplot_colors_kwarg · matplotlib/matplotlib@4ec14fb · GitHub
[go: up one dir, main page]

Skip to content

Commit 4ec14fb

Browse files
authored
Merge pull request #8861 from tacaswell/fix_eventplot_colors_kwarg
FIX: eventplot colors kwarg
2 parents 8fac114 + 4d4fe07 commit 4ec14fb

File tree

3 files changed

+138
-67
lines changed

3 files changed

+138
-67
lines changed

lib/matplotlib/axes/_axes.py

Lines changed: 68 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1083,53 +1083,84 @@ def eventplot(self, positions, orientation='horizontal', lineoffsets=1,
10831083
linelengths=1, linewidths=None, colors=None,
10841084
linestyles='solid', **kwargs):
10851085
"""
1086-
Plot identical parallel lines at specific positions.
1086+
Plot identical parallel lines at the given positions.
10871087
1088-
Plot parallel lines at the given positions. positions should be a 1D
1089-
or 2D array-like object, with each row corresponding to a row or column
1090-
of lines.
1088+
*positions* should be a 1D or 2D array-like object, with each row
1089+
corresponding to a row or column of lines.
10911090
10921091
This type of plot is commonly used in neuroscience for representing
1093-
neural events, where it is commonly called a spike raster, dot raster,
1092+
neural events, where it is usually called a spike raster, dot raster,
10941093
or raster plot.
10951094
10961095
However, it is useful in any situation where you wish to show the
10971096
timing or position of multiple sets of discrete events, such as the
10981097
arrival times of people to a business on each day of the month or the
10991098
date of hurricanes each year of the last century.
11001099
1101-
*orientation* : [ 'horizontal' | 'vertical' ]
1102-
'horizontal' : the lines will be vertical and arranged in rows
1103-
'vertical' : lines will be horizontal and arranged in columns
1100+
Parameters
1101+
----------
1102+
positions : 1D or 2D array-like object
1103+
Each value is an event. If *positions* is a 2D array-like, each
1104+
row corresponds to a row or a column of lines (depending on the
1105+
*orientation* parameter).
1106+
1107+
orientation : {'horizontal', 'vertical'}, optional
1108+
Controls the direction of the event collections:
1109+
1110+
- 'horizontal' : the lines are arranged horizontally in rows,
1111+
and are vertical.
1112+
- 'vertical' : the lines are arranged vertically in columns,
1113+
and are horizontal.
1114+
1115+
lineoffsets : scalar or sequence of scalars, optional, default: 1
1116+
The offset of the center of the lines from the origin, in the
1117+
direction orthogonal to *orientation*.
1118+
1119+
linelengths : scalar or sequence of scalars, optional, default: 1
1120+
The total height of the lines (i.e. the lines stretches from
1121+
``lineoffset - linelength/2`` to ``lineoffset + linelength/2``).
1122+
1123+
linewidths : scalar, scalar sequence or None, optional, default: None
1124+
The line width(s) of the event lines, in points. If it is None,
1125+
defaults to its rcParams setting.
1126+
1127+
colors : color, sequence of colors or None, optional, default: None
1128+
The color(s) of the event lines. If it is None, defaults to its
1129+
rcParams setting.
11041130
1105-
*lineoffsets* :
1106-
A float or array-like containing floats.
1131+
linestyles : str or tuple or a sequence of such values, optional
1132+
Default is 'solid'. Valid strings are ['solid', 'dashed',
1133+
'dashdot', 'dotted', '-', '--', '-.', ':']. Dash tuples
1134+
should be of the form::
11071135
1108-
*linelengths* :
1109-
A float or array-like containing floats.
1136+
(offset, onoffseq),
11101137
1111-
*linewidths* :
1112-
A float or array-like containing floats.
1138+
where *onoffseq* is an even length tuple of on and off ink
1139+
in points.
11131140
1114-
*colors*
1115-
must be a sequence of RGBA tuples (e.g., arbitrary color
1116-
strings, etc, not allowed) or a list of such sequences
1141+
**kwargs : optional
1142+
Other keyword arguments are line collection properties. See
1143+
:class:`~matplotlib.collections.LineCollection` for a list of
1144+
the valid properties.
11171145
1118-
*linestyles* :
1119-
[ 'solid' | 'dashed' | 'dashdot' | 'dotted' ] or an array of these
1120-
values
1146+
Returns
1147+
-------
11211148
1122-
For linelengths, linewidths, colors, and linestyles, if only a single
1123-
value is given, that value is applied to all lines. If an array-like
1124-
is given, it must have the same length as positions, and each value
1125-
will be applied to the corresponding row or column in positions.
1149+
A list of :class:`matplotlib.collections.EventCollection` objects that
1150+
were added.
11261151
1127-
Returns a list of :class:`matplotlib.collections.EventCollection`
1128-
objects that were added.
1152+
Notes
1153+
-----
11291154
1130-
kwargs are :class:`~matplotlib.collections.LineCollection` properties:
1155+
For *linelengths*, *linewidths*, *colors*, and *linestyles*, if only
1156+
a single value is given, that value is applied to all lines. If an
1157+
array-like is given, it must have the same length as *positions*, and
1158+
each value will be applied to the corresponding row of the array.
11311159
1132-
%(LineCollection)s
1160+
Example
1161+
-------
1162+
1163+
.. plot:: mpl_examples/pylab_examples/eventplot_demo.py
11331164
"""
11341165
self._process_unit_info(xdata=positions,
11351166
ydata=[lineoffsets, linelengths],
@@ -1181,6 +1212,15 @@ def eventplot(self, positions, orientation='horizontal', lineoffsets=1,
11811212
lineoffsets = [None]
11821213
if len(colors) == 0:
11831214
colors = [None]
1215+
try:
1216+
# Early conversion of the colors into RGBA values to take care
1217+
# of cases like colors='0.5' or colors='C1'. (Issue #8193)
1218+
colors = mcolors.to_rgba_array(colors)
1219+
except ValueError:
1220+
# Will fail if any element of *colors* is None. But as long
1221+
# as len(colors) == 1 or len(positions), the rest of the
1222+
# code should process *colors* properly.
1223+
pass
11841224

11851225
if len(lineoffsets) == 1 and len(positions) != 1:
11861226
lineoffsets = np.tile(lineoffsets, len(positions))

lib/matplotlib/collections.py

Lines changed: 41 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1240,15 +1240,15 @@ class EventCollection(LineCollection):
12401240
'''
12411241
A collection of discrete events.
12421242
1243-
An event is a 1-dimensional value, usually the position of something along
1244-
an axis, such as time or length. Events do not have an amplitude. They
1245-
are displayed as v
1243+
The events are given by a 1-dimensional array, usually the position of
1244+
something along an axis, such as time or length. They do not have an
1245+
amplitude and are displayed as vertical or horizontal parallel bars.
12461246
'''
12471247

12481248
_edge_default = True
12491249

12501250
def __init__(self,
1251-
positions, # Can be None.
1251+
positions, # Cannot be None.
12521252
orientation=None,
12531253
lineoffset=0,
12541254
linelength=1,
@@ -1259,58 +1259,60 @@ def __init__(self,
12591259
**kwargs
12601260
):
12611261
"""
1262-
*positions*
1263-
a sequence of numerical values or a 1D numpy array. Can be None
1262+
Parameters
1263+
----------
1264+
positions : 1D array-like object
1265+
Each value is an event.
12641266
1265-
*orientation* [ 'horizontal' | 'vertical' | None ]
1266-
defaults to 'horizontal' if not specified or None
1267+
orientation : {None, 'horizontal', 'vertical'}, optional
1268+
The orientation of the **collection** (the event bars are along
1269+
the orthogonal direction). Defaults to 'horizontal' if not
1270+
specified or None.
12671271
1268-
*lineoffset*
1269-
a single numerical value, corresponding to the offset of the center
1270-
of the markers from the origin
1272+
lineoffset : scalar, optional, default: 0
1273+
The offset of the center of the markers from the origin, in the
1274+
direction orthogonal to *orientation*.
12711275
1272-
*linelength*
1273-
a single numerical value, corresponding to the total height of the
1274-
marker (i.e. the marker stretches from lineoffset+linelength/2 to
1275-
lineoffset-linelength/2). Defaults to 1
1276+
linelength : scalar, optional, default: 1
1277+
The total height of the marker (i.e. the marker stretches from
1278+
``lineoffset - linelength/2`` to ``lineoffset + linelength/2``).
12761279
1277-
*linewidth*
1278-
a single numerical value
1280+
linewidth : scalar or None, optional, default: None
1281+
If it is None, defaults to its rcParams setting, in sequence form.
12791282
1280-
*color*
1281-
must be a sequence of RGBA tuples (e.g., arbitrary color
1282-
strings, etc, not allowed).
1283+
color : color, sequence of colors or None, optional, default: None
1284+
If it is None, defaults to its rcParams setting, in sequence form.
12831285
1284-
*linestyle* [ 'solid' | 'dashed' | 'dashdot' | 'dotted' ]
1286+
linestyle : str or tuple, optional, default: 'solid'
1287+
Valid strings are ['solid', 'dashed', 'dashdot', 'dotted',
1288+
'-', '--', '-.', ':']. Dash tuples should be of the form::
12851289
1286-
*antialiased*
1287-
1 or 2
1290+
(offset, onoffseq),
12881291
1289-
If *linewidth*, *color*, or *antialiased* is None, they
1290-
default to their rcParams setting, in sequence form.
1292+
where *onoffseq* is an even length tuple of on and off ink
1293+
in points.
12911294
1292-
*norm*
1293-
None (optional for :class:`matplotlib.cm.ScalarMappable`)
1294-
*cmap*
1295-
None (optional for :class:`matplotlib.cm.ScalarMappable`)
1295+
antialiased : {None, 1, 2}, optional
1296+
If it is None, defaults to its rcParams setting, in sequence form.
12961297
1297-
*pickradius* is the tolerance for mouse clicks picking a line.
1298-
The default is 5 pt.
1298+
**kwargs : optional
1299+
Other keyword arguments are line collection properties. See
1300+
:class:`~matplotlib.collections.LineCollection` for a list of
1301+
the valid properties.
12991302
1300-
The use of :class:`~matplotlib.cm.ScalarMappable` is optional.
1301-
If the :class:`~matplotlib.cm.ScalarMappable` array
1302-
:attr:`~matplotlib.cm.ScalarMappable._A` is not None (i.e., a call to
1303-
:meth:`~matplotlib.cm.ScalarMappable.set_array` has been made), at
1304-
draw time a call to scalar mappable will be made to set the colors.
1303+
Example
1304+
-------
1305+
1306+
.. plot:: mpl_examples/pylab_examples/eventcollection_demo.py
13051307
"""
13061308

13071309
segment = (lineoffset + linelength / 2.,
13081310
lineoffset - linelength / 2.)
1309-
if len(positions) == 0:
1311+
if positions is None or len(positions) == 0:
13101312
segments = []
13111313
elif hasattr(positions, 'ndim') and positions.ndim > 1:
1312-
raise ValueError('if positions is an ndarry it cannot have '
1313-
'dimensionality great than 1 ')
1314+
raise ValueError('positions cannot be an array with more than '
1315+
'one dimension.')
13141316
elif (orientation is None or orientation.lower() == 'none' or
13151317
orientation.lower() == 'horizontal'):
13161318
positions.sort()

lib/matplotlib/tests/test_axes.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import matplotlib.colors as mcolors
2828
from numpy.testing import assert_allclose, assert_array_equal
2929
from matplotlib.cbook import IgnoredKeywordWarning
30+
from matplotlib.cbook._backports import broadcast_to
3031

3132
# Note: Some test cases are run twice: once normally and once with labeled data
3233
# These two must be defined in the same test function or need to have
@@ -2985,6 +2986,34 @@ def test_eventplot_defaults():
29852986
colls = axobj.eventplot(data)
29862987

29872988

2989+
@pytest.mark.parametrize(('colors'), [
2990+
('0.5',), # string color with multiple characters: not OK before #8193 fix
2991+
('tab:orange', 'tab:pink', 'tab:cyan', 'bLacK'), # case-insensitive
2992+
('red', (0, 1, 0), None, (1, 0, 1, 0.5)), # a tricky case mixing types
2993+
('rgbk',) # len('rgbk') == len(data) and each character is a valid color
2994+
])
2995+
def test_eventplot_colors(colors):
2996+
'''Test the *colors* parameter of eventplot. Inspired by the issue #8193.
2997+
'''
2998+
data = [[i] for i in range(4)] # 4 successive events of different nature
2999+
3000+
# Build the list of the expected colors
3001+
expected = [c if c is not None else 'C0' for c in colors]
3002+
# Convert the list into an array of RGBA values
3003+
# NB: ['rgbk'] is not a valid argument for to_rgba_array, while 'rgbk' is.
3004+
if len(expected) == 1:
3005+
expected = expected[0]
3006+
expected = broadcast_to(mcolors.to_rgba_array(expected), (len(data), 4))
3007+
3008+
fig, ax = plt.subplots()
3009+
if len(colors) == 1: # tuple with a single string (like '0.5' or 'rgbk')
3010+
colors = colors[0]
3011+
collections = ax.eventplot(data, colors=colors)
3012+
3013+
for coll, color in zip(collections, expected):
3014+
assert_allclose(coll.get_color(), color)
3015+
3016+
29883017
@image_comparison(baseline_images=['test_eventplot_problem_kwargs'],
29893018
extensions=['png'], remove_text=True)
29903019
def test_eventplot_problem_kwargs():

0 commit comments

Comments
 (0)
0