Skip to content
Merged
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: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
ultraplot/tests/baseline
# VIM extras
.session.vim
.vimsession
Expand Down
97 changes: 42 additions & 55 deletions ultraplot/axes/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -2477,54 +2477,43 @@ def _parse_cycle(
Whether to simply return the property cycle or apply it. The cycle is
only applied (and therefore reset) if it differs from the current one.
"""
# Create the property cycler and update it if necessary
# NOTE: Matplotlib Cycler() objects have built-in __eq__ operator
# so really easy to check if the cycler has changed!
if cycle is not None or cycle_kw:
cycle_kw = cycle_kw or {}
if ncycle != 1: # ignore for column-by-column plotting commands
cycle_kw.setdefault("N", ncycle) # if None then filled in Colormap()
if isinstance(cycle, str) and cycle.lower() == "none":
cycle = False
if not cycle:
args = ()
elif cycle is True: # consistency with 'False' ('reactivate' the cycler)
args = (rc["axes.prop_cycle"],)
else:
args = (cycle,)
cycle = constructor.Cycle(*args, **cycle_kw)
with warnings.catch_warnings(): # hide 'elementwise-comparison failed'
warnings.simplefilter("ignore", FutureWarning)
if return_cycle:
pass
elif cycle != self._active_cycle:
self.set_prop_cycle(cycle)

# Manually extract and apply settings to outgoing keyword arguments
# if native matplotlib function does not include desired properties
cycle_kw = cycle_kw or {}
cycle_manually = cycle_manually or {}
parser = self._get_lines # the _process_plot_var_args instance
props = {} # which keys to apply from property cycler
# BREAKING in mpl3.9.1 parse has cycle items and no longer posseses _prop_keys
for prop, key in cycle_manually.items():
if kwargs.get(key, None) is None and any(
prop in item for item in parser._cycler_items
):
props[prop] = key
if props:
for dict_ in parser._cycler_items:
for prop, key in props.items():
value = dict_[prop]
if (
key == "c"
): # special case: scatter() color must be converted to hex
value = pcolors.to_hex(value)
kwargs[key] = value

cycle_kw.setdefault("N", ncycle)

# Match-case for cycle resolution
match cycle:
case None if not cycle_kw:
resolved_cycle = None
case True:
resolved_cycle = constructor.Cycle(rc["axes.prop_cycle"])
case str() if cycle.lower() == "none":
resolved_cycle = None
case str() | int():
resolved_cycle = constructor.Cycle(cycle, **cycle_kw)
case _:
resolved_cycle = None

# Ignore cycle for single-column plotting
resolved_cycle = None if ncycle == 1 else resolved_cycle

# Return or apply cycle
if return_cycle:
return cycle, kwargs # needed for stem() to apply in a context()
else:
return kwargs
return resolved_cycle, kwargs

if resolved_cycle and resolved_cycle != self._active_cycle:
self.set_prop_cycle(resolved_cycle)

# Apply manual cycle properties
if cycle_manually:
current_prop = self._get_lines._cycler_items[self._get_lines._idx]
self._get_lines._idx = (self._get_lines._idx + 1) % len(self._active_cycle)
for prop, key in cycle_manually.items():
if kwargs.get(key) is None and prop in current_prop:
value = current_prop[prop]
kwargs[key] = pcolors.to_rgba(value) if key == "c" else value
Comment on lines +2503 to +2514
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the new changes, this block of code is skipped if return_cycle is True. Why is that?


return kwargs

def _parse_level_lim(
self,
Expand Down Expand Up @@ -3459,12 +3448,9 @@ def _apply_scatter(self, xs, ys, ss, cc, *, vert=True, **kwargs):
ys, kw = inputs._dist_reduce(ys, **kw)
ss, kw = self._parse_markersize(ss, **kw) # parse 's'

# Move _parse_cycle before _parse_color
kw = self._parse_cycle(xs.shape[1] if xs.ndim > 1 else 1, **kw)

# Only parse color if explicitly provided
infer_rgb = True
if cc is not None:
infer_rgb = True
if not isinstance(cc, str):
test = np.atleast_1d(cc)
if (
Expand All @@ -3482,14 +3468,14 @@ def _apply_scatter(self, xs, ys, ss, cc, *, vert=True, **kwargs):
infer_rgb=infer_rgb,
**kw,
)

# Create the cycler object by manually cycling and sanitzing the inputs
guide_kw = _pop_params(kw, self._update_guide)
objs = []
for _, n, x, y, s, c, kw in self._iter_arg_cols(xs, ys, ss, cc, **kw):
# Don't set 'c' explicitly unless it was provided
kw["s"] = s
if c is not None:
kw["c"] = c
# Cycle s and c as they are in cycle_manually
# Note: they could be None
kw["s"], kw["c"] = s, c
kw = self._parse_cycle(n, cycle_manually=cycle_manually, **kw)
*eb, kw = self._add_error_bars(x, y, vert=vert, default_barstds=True, **kw)
*es, kw = self._add_error_shading(x, y, vert=vert, color_key="c", **kw)
if not vert:
Expand Down Expand Up @@ -4029,6 +4015,7 @@ def _apply_violinplot(
bodies = artists.pop("bodies", ()) # should be no other entries
if bodies:
bodies = cbook.silent_list(type(bodies[0]).__name__, bodies)

for i, body in enumerate(bodies):
body.set_alpha(1.0) # change default to 1.0
if fillcolor[i] is not None:
Expand Down
161 changes: 102 additions & 59 deletions ultraplot/constructor.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,13 @@
from . import ticker as pticker
from .config import rc
from .internals import ic # noqa: F401
from .internals import _not_none, _pop_props, _version_cartopy, _version_mpl, warnings
from .internals import (
_not_none,
_pop_props,
_version_cartopy,
_version_mpl,
warnings,
)
from .utils import get_colors, to_hex, to_rgba

try:
Expand Down Expand Up @@ -235,7 +241,12 @@
"height": 15000e3,
},
"tmerc": {"lon_0": 0, "lat_0": 0, "width": 10000e3, "height": 10000e3},
"merc": {"llcrnrlat": -80, "urcrnrlat": 84, "llcrnrlon": -180, "urcrnrlon": 180},
"merc": {
"llcrnrlat": -80,
"urcrnrlat": 84,
"llcrnrlon": -180,
"urcrnrlon": 180,
},
"omerc": {
"lat_0": 0,
"lon_0": 0,
Expand Down Expand Up @@ -762,9 +773,9 @@ def _pop_modification(key):
return cmap


def Cycle(*args, N=None, samples=None, name=None, **kwargs):
class Cycle(cycler.Cycler):
"""
Generate and merge `~cycler.Cycler` instances in a variety of ways.
Generate and merge `~cycler.Cycler` instances in a variety of ways. The new generated class can be used to internally map keywords to the properties of the `~cycler.Cycler` instance. It is used by various plot functions to cycle through colors, linestyles, markers, etc.

Parameters
----------
Expand All @@ -777,12 +788,12 @@ def Cycle(*args, N=None, samples=None, name=None, **kwargs):
* If a `~cycler.Cycler`, nothing more is done.
* If a sequence of RGB tuples or color strings, these colors are used.
* If a `~ultraplot.colors.DiscreteColormap`, colors from the ``colors``
attribute are used.
attribute are used.
* If a string cycle name, that `~ultraplot.colors.DiscreteColormap`
is looked up and its ``colors`` are used.
is looked up and its ``colors`` are used.
* In all other cases, the argument is passed to `Colormap`, and
colors from the resulting `~ultraplot.colors.ContinuousColormap`
are used. See the `samples` argument.
colors from the resulting `~ultraplot.colors.ContinuousColormap`
are used. See the `samples` argument.

If the last positional argument is numeric, it is used for the
`samples` keyword argument.
Expand Down Expand Up @@ -830,12 +841,6 @@ def Cycle(*args, N=None, samples=None, name=None, **kwargs):
to `Colormap` and used to build the `~ultraplot.colors.DiscreteColormap`
from which the cycler will draw its colors.

Returns
-------
cycler.Cycler
A `~cycler.Cycler` instance that can be passed
to `~matplotlib.axes.Axes.set_prop_cycle`.

See also
--------
cycler.cycler
Expand All @@ -845,65 +850,103 @@ def Cycle(*args, N=None, samples=None, name=None, **kwargs):
ultraplot.constructor.Norm
ultraplot.utils.get_colors
"""
# Parse keyword arguments that rotate through other properties
# besides color cycles.
props = _pop_props(kwargs, "line")
if "sizes" in kwargs: # special case, gets translated back by scatter()
props.setdefault("markersize", kwargs.pop("sizes"))
samples = _not_none(samples=samples, N=N) # trigger Colormap default
for key, value in tuple(props.items()): # permit in-place modification
if value is None:
return
elif not np.iterable(value) or isinstance(value, str):
value = (value,)
props[key] = list(value) # ensure mutable list

# If args is non-empty, means we want color cycle; otherwise is black
if not args:
props.setdefault("color", ["black"])
def __init__(self, *args, N=None, samples=None, name=None, **kwargs):
self.name = "_no_name" # default value
cycler_props = self._parse_basic_properties(kwargs)
samples = _not_none(samples=samples, N=N) # trigger Colormap default
if not args:
self._handle_empty_args(cycler_props, kwargs)
elif self._is_all_cyclers(args):
self._handle_cycler_args(args, cycler_props, kwargs)
else:
self._handle_colormap_args(args, cycler_props, kwargs, samples, name)

self._iterator = None # internal reference for cycle

def _parse_basic_properties(self, kwargs):
"""Parse and validate basic properties from kwargs."""
props = _pop_props(kwargs, "line")
if "sizes" in kwargs:
props.setdefault("markersize", kwargs.pop("sizes"))

for key, value in tuple(props.items()):
if value is None:
props[key] = ["black"] # default instead of early return
elif not np.iterable(value) or isinstance(value, str):
props[key] = [value]
else:
props[key] = list(value) # ensure mutable list
return props

def _handle_empty_args(self, props, kwargs):
"""Handle case when no positional arguments are provided."""
props.setdefault("color", "black")
if kwargs:
warnings._warn_ultraplot(f"Ignoring Cycle() keyword arg(s) {kwargs}.")
dicts = ()
self._build_cycler(())

# Merge cycler objects and/or update cycler objects with input kwargs
elif all(isinstance(arg, cycler.Cycler) for arg in args):
def _handle_cycler_args(self, args, props, kwargs):
"""Handle case when arguments are cycler objects."""
if kwargs:
warnings._warn_ultraplot(f"Ignoring Cycle() keyword arg(s) {kwargs}.")
if len(args) == 1 and not props:
return args[0]
dicts = tuple(arg.by_key() for arg in args)
self._build_cycler((args[0].by_key(),))
else:
dicts = tuple(arg.by_key() for arg in args)
self._build_cycler(dicts + (props,))

# Get a cycler from a colormap
# NOTE: Passing discrete=True does not imply default_luminance=90 because
# someone might be trying to make qualitative colormap for use in 2D plot
else:
def _handle_colormap_args(self, args, props, kwargs, samples, name):
"""Handle case when arguments are for creating a colormap."""
if isinstance(args[-1], Number):
args, samples = args[:-1], _not_none(
samples_positional=args[-1], samples=samples
) # noqa: #501
)

cmap = self._create_colormap(args, name, samples, kwargs)
dict_ = {"color": [c if isinstance(c, str) else to_hex(c) for c in cmap.colors]}
self._build_cycler((dict_, props))
self.name = _not_none(name, cmap.name)

def _create_colormap(self, args, name, samples, kwargs):
"""Create a colormap from the given arguments."""
kwargs.setdefault("listmode", "discrete")
kwargs.setdefault("filemode", "discrete")
kwargs["discrete"] = True # triggers application of default 'samples'
kwargs["discrete"] = True
kwargs["default_luminance"] = DEFAULT_CYCLE_LUMINANCE
cmap = Colormap(*args, name=name, samples=samples, **kwargs)
name = _not_none(name, cmap.name)
dict_ = {"color": [c if isinstance(c, str) else to_hex(c) for c in cmap.colors]}
dicts = (dict_,)

# Update the cyler property
dicts = dicts + (props,)
props = {}
for dict_ in dicts:
for key, value in dict_.items():
props.setdefault(key, []).extend(value)

# Build cycler with matching property lengths
maxlen = np.lcm.reduce([len(value) for value in props.values()])
props = {key: value * (maxlen // len(value)) for key, value in props.items()}
cycle = cycler.cycler(**props)
cycle.name = _not_none(name, "_no_name")

return cycle
return Colormap(*args, name=name, samples=samples, **kwargs)

def _is_all_cyclers(self, args):
"""Check if all arguments are Cycler objects."""
return all(isinstance(arg, cycler.Cycler) for arg in args)

def _build_cycler(self, dicts):
"""Build the final cycler from the given dictionaries."""
props = {}
for dict_ in dicts:
for key, value in dict_.items():
props.setdefault(key, []).extend(value)
# Build cycler with matching property lengths
# Ensure at least a default color property exists
if not props:
props = {"color": ["black"]}

# Build cycler with matching property lengths
lengths = [len(value) for value in props.values()]
maxlen = np.lcm.reduce(lengths)
props = {key: value * (maxlen // len(value)) for key, value in props.items()}
mcycler = cycler.cycler(**props)
super().__init__(mcycler)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a comment on what this call does exactly? Does it use matplotlib's init function to update the current cycle to the computed one?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cycler.cycler is not a class but a function in mpl. The logic of the init from the Cycle class is not compatible with the function -- that is we need to pass the output of cycler directly to the parent of the class we introduced.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool. Let's add a comment on this in the code.


def get_next(self):
# Get the next set of properties
if self._iterator is None:
self._iterator = iter(self)
try:
return next(self._iterator)
except StopIteration:
self._iterator = iter(self)
return next(self._iterator)


def Norm(norm, *args, **kwargs):
Expand Down
Binary file removed ultraplot/tests/baseline/test_align_labels.png
Binary file not shown.
Binary file not shown.
Binary file removed ultraplot/tests/baseline/test_aspect_ratios.png
Binary file not shown.
Binary file removed ultraplot/tests/baseline/test_auto_diverging1.png
Binary file not shown.
Binary file removed ultraplot/tests/baseline/test_auto_legend.png
Binary file not shown.
Binary file removed ultraplot/tests/baseline/test_auto_reverse.png
Binary file not shown.
Binary file removed ultraplot/tests/baseline/test_autodiverging3.png
Binary file not shown.
Binary file removed ultraplot/tests/baseline/test_autodiverging4.png
Binary file not shown.
Binary file removed ultraplot/tests/baseline/test_autodiverging5.png
Binary file not shown.
Binary file removed ultraplot/tests/baseline/test_axes_colors.png
Binary file not shown.
Binary file removed ultraplot/tests/baseline/test_bar_vectors.png
Binary file not shown.
Binary file removed ultraplot/tests/baseline/test_bar_width.png
Binary file not shown.
Binary file removed ultraplot/tests/baseline/test_both_ticklabels.png
Binary file not shown.
Binary file removed ultraplot/tests/baseline/test_bounds_ticks.png
Binary file not shown.
Binary file removed ultraplot/tests/baseline/test_boxplot_colors.png
Binary file not shown.
Binary file removed ultraplot/tests/baseline/test_boxplot_vectors.png
Binary file not shown.
Binary file removed ultraplot/tests/baseline/test_cartopy_contours.png
Binary file not shown.
Binary file removed ultraplot/tests/baseline/test_cartopy_labels.png
Binary file not shown.
Binary file removed ultraplot/tests/baseline/test_cartopy_manual.png
Binary file not shown.
Binary file removed ultraplot/tests/baseline/test_centered_legends.png
Binary file not shown.
Binary file removed ultraplot/tests/baseline/test_cmap_cycles.png
Binary file not shown.
Binary file removed ultraplot/tests/baseline/test_colorbar.png
Binary file not shown.
Binary file removed ultraplot/tests/baseline/test_colorbar_ticks.png
Binary file not shown.
Binary file removed ultraplot/tests/baseline/test_colormap_mode.png
Binary file not shown.
Binary file removed ultraplot/tests/baseline/test_column_iteration.png
Binary file not shown.
Binary file removed ultraplot/tests/baseline/test_complex_ticks.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_contour_labels.png
Diff not rendered.
Diff not rendered.
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_contour_negative.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_contour_single.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_cutoff_ticks.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_data_keyword.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_discrete_ticks.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_discrete_vs_fixed.png
Diff not rendered.
Diff not rendered.
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_edge_fix.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_flow_functions.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_font_adjustments.png
Diff not rendered.
Diff not rendered.
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_gray_adjustment.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_histogram_legend.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_histogram_types.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_ignore_message.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_inbounds_data.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_init_format.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_inner_title_zorder.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_inset_basic.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_inset_colorbars.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_inset_colors_1.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_inset_colors_2.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_inset_zoom_update.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_invalid_dist.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_invalid_plot.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_keep_guide_labels.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_label_settings.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_level_restriction.png
Diff not rendered.
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_locale_formatting.png
Diff not rendered.
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_manual_labels.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_multi_formatting.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_multiple_calls.png
Diff not rendered.
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_outer_align.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_panel_dist.png
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_parametric_colors.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_parametric_labels.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_patch_format.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_pie_charts.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_pint_quantities.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_polar_projections.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_projection_dicts.png
Diff not rendered.
Diff not rendered.
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_reversed_levels.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_scatter_alpha.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_scatter_args.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_scatter_cycle.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_scatter_inbounds.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_scatter_sizes.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_seaborn_heatmap.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_seaborn_hist.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_seaborn_relational.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_seaborn_swarmplot.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_segmented_norm.png
Diff not rendered.
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_share_all_basic.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_singleton_legend.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_span_labels.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_spine_offset.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_spine_side.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_standardized_input.png
Diff not rendered.
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_three_axes.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_tick_direction.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_tick_labels.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_tick_length.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_tick_width.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_title_deflection.png
Diff not rendered.
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_tuple_handles.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_twin_axes_1.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_twin_axes_2.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_twin_axes_3.png
Diff not rendered.
Binary file removed ultraplot/tests/baseline/test_uneven_levels.png
Diff not rendered.
19 changes: 12 additions & 7 deletions ultraplot/tests/test_1dplots.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,11 +222,9 @@ def test_pie_charts():
labels = ["foo", "bar", "baz", "biff", "buzz"]
array = np.arange(1, 6)
data = pd.Series(array, index=labels)
fig = uplt.figure()
ax = fig.subplot(121)
ax.pie(array, edgefix=True, labels=labels, ec="k", cycle="reds")
ax = fig.subplot(122)
ax.pie(data, ec="k", cycle="blues")
fig, ax = uplt.subplots(ncols=2)
ax[0].pie(array, edgefix=True, labels=labels, ec="k", cycle="reds")
ax[1].pie(data, ec="k", cycle="blues")
return fig


Expand All @@ -239,7 +237,11 @@ def test_parametric_labels():
uplt.rc.inlinefmt = "svg"
fig, ax = uplt.subplots()
ax.parametric(
state.rand(5), c=list("abcde"), lw=20, colorbar="b", cmap_kw={"left": 0.2}
state.rand(5),
c=list("abcde"),
lw=20,
colorbar="b",
cmap_kw={"left": 0.2},
)
return fig

Expand Down Expand Up @@ -328,7 +330,10 @@ def test_scatter_cycle():
"""
fig, ax = uplt.subplots()
cycle = uplt.Cycle(
"538", marker=["X", "o", "s", "d"], sizes=[20, 100], edgecolors=["r", "k"]
"538",
marker=["X", "o", "s", "d"],
sizes=[20, 100],
edgecolors=["r", "k"],
)
ax.scatter(
state.rand(10, 4),
Expand Down
Loading
Loading