10000 Allow empty linestyle for collections by oscargus · Pull Request #23056 · matplotlib/matplotlib · GitHub
[go: up one dir, main page]

Skip to content

Allow empty linestyle for collections #23056

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

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion ci/mypy-stubtest-allowlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ matplotlib.ticker.LogLocator.set_params
matplotlib.axes._base._AxesBase.axis

# Aliases (dynamically generated, not type hinted)
matplotlib.collections.Collection.get_dashes
matplotlib.collections.Collection.get_ec
matplotlib.collections.Collection.get_edgecolors
matplotlib.collections.Collection.get_facecolors
Expand Down
2 changes: 1 addition & 1 deletion lib/matplotlib/axes/_axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -8055,7 +8055,7 @@ def spy(self, Z, precision=0, marker=None, markersize=None,
if 'linestyle' in kwargs:
raise _api.kwarg_error("spy", "linestyle")
ret = mlines.Line2D(
x, y, linestyle='None', marker=marker, markersize=markersize,
x, y, linestyle='none', marker=marker, markersize=markersize,
**kwargs)
self.add_line(ret)
nr, nc = Z.shape
Expand Down
151 changes: 87 additions & 64 deletions lib/matplotlib/collections.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"antialiased": ["antialiaseds", "aa"],
"edgecolor": ["edgecolors", "ec"],
"facecolor": ["facecolors", "fc"],
"linestyle": ["linestyles", "dashes", "ls"],
"linestyle": ["linestyles", "ls"],
"linewidth": ["linewidths", "lw"],
"offset_transform": ["transOffset"],
})
Expand Down Expand Up @@ -79,7 +79,7 @@ def __init__(self, *,
edgecolors=None,
facecolors=None,
linewidths=None,
linestyles='solid',
linestyles='-',
capstyle=None,
joinstyle=None,
antialiaseds=None,
Expand All @@ -104,15 +104,8 @@ def __init__(self, *,
Face color for each patch making up the collection.
linewidths : float or list of floats, default: :rc:`patch.linewidth`
Line width for each patch making up the collection.
linestyles : str or tuple or list thereof, default: 'solid'
Valid strings are ['solid', 'dashed', 'dashdot', 'dotted', '-',
'--', '-.', ':']. Dash tuples should be of the form::

(offset, onoffseq),

where *onoffseq* is an even length tuple of on and off ink lengths
in points. For examples, see
:doc:`/gallery/lines_bars_and_markers/linestyles`.
linestyles : str or tuple or list thereof, default: '-'
Line style or list of line styles. See `set_linestyle` for details.
capstyle : `.CapStyle`-like, default: :rc:`patch.capstyle`
Style to use for capping lines for all paths in the collection.
Allowed values are %(CapStyle)s.
Expand Down Expand Up @@ -156,11 +149,12 @@ def __init__(self, *,
cm.ScalarMappable.__init__(self, norm, cmap)
# list of un-scaled dash patterns
# this is needed scaling the dash pattern by linewidth
self._us_linestyles = [(0, None)]
self._unscaled_dash_patterns = [(0, None)]
# list of dash patterns
self._linestyles = [(0, None)]
self._dash_patterns = [(0, None)]
self._linestyles = ['-']
# list of unbroadcast/scaled linewidths
self._us_lw = [0]
self._unscaled_lw = [0]
self._linewidths = [0]

self._gapcolor = None # Currently only used by LineCollection.
Expand Down Expand Up @@ -379,7 +373,7 @@ def draw(self, renderer):
if (len(paths) == 1 and len(trans) <= 1 and
len(facecolors) == 1 and len(edgecolors) == 1 and
len(self._linewidths) == 1 and
all(ls[1] is None for ls in self._linestyles) and
all(dash[1] is None for dash in self._dash_patterns) and
len(self._antialiaseds) == 1 and len(self._urls) == 1 and
self.get_hatch() is None):
if len(trans):
Expand All @@ -400,7 +394,7 @@ def draw(self, renderer):
if do_single_path_optimization:
gc.set_foreground(tuple(edgecolors[0]))
gc.set_linewidth(self._linewidths[0])
gc.set_dashes(*self._linestyles[0])
gc.set_dashes(*self._dash_patterns[0])
gc.set_antialiased(self._antialiaseds[0])
gc.set_url(self._urls[0])
renderer.draw_markers(
Expand All @@ -422,7 +416,7 @@ def draw(self, renderer):
gc, transform.frozen(), paths,
self.get_transforms(), offsets, offset_trf,
self.get_facecolor(), self.get_edgecolor(),
self._linewidths, self._linestyles,
self._linewidths, self._dash_patterns,
self._antialiaseds, self._urls,
"screen") # offset_position, kept for backcompat.

Expand Down Expand Up @@ -579,54 +573,82 @@ def set_linewidth(self, lw):
if lw is None:
lw = self._get_default_linewidth()
# get the un-scaled/broadcast lw
self._us_lw = np.atleast_1d(lw)
self._unscaled_lw = np.atleast_1d(lw)

# scale all of the dash patterns.
self._linewidths, self._linestyles = self._bcast_lwls(
self._us_lw, self._us_linestyles)
self._linewidths, self._dash_patterns = self._bcast_lwls(
self._unscaled_lw, self._unscaled_dash_patterns)
self.stale = True

def set_linestyle(self, ls):
"""
Set the linestyle(s) for the collection.
Set the line style(s) for the collection.

Parameters
----------
ls : str or tuple or list thereof
The line style. Possible values:

=========================== =================
linestyle description
=========================== =================
``'-'`` or ``'solid'`` solid line
``'--'`` or ``'dashed'`` dashed line
``'-.'`` or ``'dashdot'`` dash-dotted line
``':'`` or ``'dotted'`` dotted line
=========================== =================
- A string:

Alternatively a dash tuple of the following form can be provided::
========================================== =================
linestyle description
========================================== =================
``'-'`` or ``'solid'`` solid line
``'--'`` or ``'dashed'`` dashed line
``'-.'`` or ``'dashdot'`` dash-dotted line
``':'`` or ``'dotted'`` dotted line
``'none'``, ``'None'``, ``' '``, or ``''`` draw nothing
========================================== =================

(offset, onoffseq),
- Alternatively a dash tuple of the following form can be
provided::

where ``onoffseq`` is an even length tuple of on and off ink in points.
(offset, onoffseq)

Parameters
----------
ls : str or tuple or list thereof
Valid values for individual linestyles include {'-', '--', '-.',
':', '', (offset, on-off-seq)}. See `.Line2D.set_linestyle` for a
complete description.
where ``onoffseq`` is an even length tuple of on and off ink
in points.

If a single value is provided, this applies to all objects in the
collection. A list can be provided to set different line styles to
different objects.

For examples see :doc:`/gallery/lines_bars_and_markers/linestyles`.

The ``'dashed'``, ``'dashdot'``, and ``'dotted'`` line styles are
controlled by :rc:`lines.dashed_pattern`,
:rc:`lines.dashdot_pattern`, and :rc:`lines.dotted_pattern`,
respectively.
"""
try:
dashes = [mlines._get_dash_pattern(ls)]
except ValueError:
if isinstance(ls, str):
dashes, ls_norm = map(list, zip(mlines._get_dash_pattern(ls)))
elif not ls:
dashes, ls_norm = [], []
else:
try:
dashes = [mlines._get_dash_pattern(x) for x in ls]
except ValueError as err:
emsg = f'Do not know how to convert {ls!r} to dashes'
raise ValueError(emsg) from err
dashes, ls_norm = map(list, zip(mlines._get_dash_pattern(ls)))
except ValueError:
dashes, ls_norm = map(
list, zip(*[mlines._get_dash_pattern(x) for x in ls]))

# get the list of raw 'unscaled' dash patterns
self._us_linestyles = dashes
self._unscaled_dash_patterns = dashes

# broadcast and scale the lw and dash patterns
self._linewidths, self._linestyles = self._bcast_lwls(
self._us_lw, self._us_linestyles)
self._linewidths, self._dash_patterns = self._bcast_lwls(
self._unscaled_lw, self._unscaled_dash_patterns)
self._linestyles = ls_norm

# Dashes used to be an alias of linestyle
set_dashes = set_linestyle

def get_dashes(self):
"""
Return the dash patterns.

.. versionadded:: 3.8
"""
return self._dash_patterns

@_docstring.interpd
def set_capstyle(self, cs):
Expand Down Expand Up @@ -827,7 +849,12 @@ def get_linewidth(self):
return self._linewidths

def get_linestyle(self):
return self._linestyles
_api.warn_external(
"Collection.get_linestyle will change return type from a list of dash "
"pattern to a list of linestyle strings. This is consistent with Line2D. "
"To get the previous result now and in the future without this warning, "
"use get_dashes.")
return self.get_dashes()

def _set_mappable_flags(self):
"""
Expand Down Expand Up @@ -918,8 +945,10 @@ def update_from(self, other):
self._original_facecolor = other._original_facecolor
self._facecolors = other._facecolors
self._linewidths = other._linewidths
self._unscaled_lw = other._unscaled_lw
self._linestyles = other._linestyles
self._us_linestyles = other._us_linestyles
self._unscaled_dash_patterns = other._unscaled_dash_patterns
self._dash_patterns = other._dash_patterns
self._pickradius = other._pickradius
self._hatch = other._hatch

Expand Down Expand Up @@ -1528,11 +1557,11 @@ def _get_inverse_paths_linestyles(self):
to nans to prevent drawing an inverse line.
"""
path_patterns = [
(mpath.Path(np.full((1, 2), np.nan)), ls)
if ls == (0, None) else
(path, mlines._get_inverse_dash_pattern(*ls))
for (path, ls) in
zip(self._paths, itertools.cycle(self._linestyles))]
(mpath.Path(np.full((1, 2), np.nan)), dash_patterns)
if dash_patterns == (0, None) else
(path, mlines._get_inverse_dash_pattern(*dash_patterns))
for (path, dash_patterns) in
zip(self._paths, itertools.cycle(self._dash_patterns))]

return zip(*path_patterns)

Expand All @@ -1555,7 +1584,7 @@ def __init__(self,
linelength=1,
linewidth=None,
color=None,
linestyle='solid',
linestyle='-',
antialiased=None,
**kwargs
):
Expand All @@ -1578,14 +1607,8 @@ def __init__(self,
The line width of the event lines, in points.
color : color or list of colors, default: :rc:`lines.color`
The color of the event lines.
linestyle : str or tuple or list thereof, default: 'solid'
Valid strings are ['solid', 'dashed', 'dashdot', 'dotted',
'-', '--', '-.', ':']. Dash tuples should be of the form::

(offset, onoffseq),

where *onoffseq* is an even length tuple of on and off ink
in points.
linestyle : str or tuple or list thereof, default: '-'
Line style or list of line styles. See `set_linestyle` for details.
antialiased : bool or list thereof, default: :rc:`lines.antialiased`
Whether to use antialiasing for drawing the lines.
**kwargs
Expand Down
3 changes: 2 additions & 1 deletion lib/matplotlib/collections.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import numpy as np
from numpy.typing import ArrayLike
from collections.abc import Callable, Iterable, Sequence
from typing import Literal
from .typing import ColorType, LineStyleType, CapStyleType, JoinStyleType
from .typing import ColorType, LineStyleType, CapStyleType, JoinStyleType, DashPatternType

class Collection(artist.Artist, cm.ScalarMappable):
def __init__(
Expand Down Expand Up @@ -63,6 +63,7 @@ class Collection(artist.Artist, cm.ScalarMappable):
def set_alpha(self, alpha: float | Sequence[float] | None) -> None: ...
def get_linewidth(self) -> float | Sequence[float]: ...
def get_linestyle(self) -> LineStyleType | Sequence[LineStyleType]: ...
def get_dashes(self) -> DashPatternType | Sequence[DashPatternType]: ...
def update_scalarmappable(self) -> None: ...
def get_fill(self) -> bool: ...
def update_from(self, other: Artist) -> None: ...
Expand Down
6 changes: 3 additions & 3 deletions lib/matplotlib/contour.py
Original file line number Diff line number Diff line change
Expand Up @@ -954,7 +954,7 @@ def collections(self):
fcs = self.get_facecolor()
ecs = self.get_edgecolor()
lws = self.get_linewidth()
lss = self.get_linestyle()
lss = self.get_dashes()
self._old_style_split_collections = []
for idx, path in enumerate(self._paths):
pc = mcoll.PathCollection(
Expand Down Expand Up @@ -1041,7 +1041,7 @@ def legend_elements(self, variable_name='x', str_format=str):
[], [],
color=self.get_edgecolor()[idx],
linewidth=self.get_linewidths()[idx],
linestyle=self.get_linestyles()[idx],
linestyle=self.get_dashes()[idx],
))
labels.append(fr'${variable_name} = {str_format(level)}$')

Expand Down Expand Up @@ -1470,7 +1470,7 @@ def draw(self, renderer):
hatch=self.hatches[idx % len(self.hatches)],
array=[self.get_array()[idx]],
linewidths=[self.get_linewidths()[idx % len(self.get_linewidths())]],
linestyles=[self.get_linestyles()[idx % len(self.get_linestyles())]],
dashes=[self.get_dashes()[idx % len(self.get_dashes())]],
):
super().draw(renderer)

Expand Down
8 changes: 4 additions & 4 deletions lib/matplotlib/legend_handler.py
C6EC
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ def _create_line(orig_handle, width, height):
# Unfilled StepPatch should show as a line
legline = Line2D([0, width], [height/2, height/2],
color=orig_handle.get_edgecolor(),
linestyle=orig_handle.get_linestyle(),
linestyle=orig_handle.get_dashes(),
linewidth=orig_handle.get_linewidth(),
)

Expand Down Expand Up @@ -407,7 +407,7 @@ def get_numpoints(self, legend):

def _default_update_prop(self, legend_handle, orig_handle):
lw = orig_handle.get_linewidths()[0]
dashes = orig_handle._us_linestyles[0]
dashes = orig_handle._unscaled_dash_patterns[0]
color = orig_handle.get_colors()[0]
legend_handle.set_color(color)
legend_handle.set_linestyle(dashes)
Expand Down Expand Up @@ -713,7 +713,7 @@ def _copy_collection_props(self, legend_handle, orig_handle):
`.Line2D` *legend_handle*.
"""
legend_handle.set_color(orig_handle.get_color()[0])
legend_handle.set_linestyle(orig_handle.get_linestyle()[0])
legend_handle.set_linestyle(orig_handle.get_dashes()[0])


class HandlerTuple(HandlerBase):
Expand Down Expand Up @@ -798,7 +798,7 @@ def get_first(prop_array):
legend_handle._hatch_color = orig_handle._hatch_color
# Setters are fine for the remaining attributes.
legend_handle.set_linewidth(get_first(orig_handle.get_linewidths()))
legend_handle.set_linestyle(get_first(orig_handle.get_linestyles()))
legend_handle.set_linestyle(get_first(orig_handle.get_dashes()))
legend_handle.set_transform(get_first(orig_handle.get_transforms()))
legend_handle.set_figure(orig_handle.get_figure())
# Alpha is already taken into account by the color attributes.
Expand Down
Loading
0