Skip to content

Commit 521351a

Browse files
committed
Make constructor funcs return copies
1 parent 6582805 commit 521351a

File tree

2 files changed

+20
-18
lines changed

2 files changed

+20
-18
lines changed

proplot/constructor.py

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
# NOTE: Used to include the raw variable names that define string keys as
1111
# part of documentation, but this is redundant and pollutes the namespace.
1212
# User should just inspect docstrings, use trial-error, or see online tables.
13+
import copy
1314
import os
1415
import re
1516
from functools import partial
@@ -851,9 +852,9 @@ def Norm(norm, *args, **kwargs):
851852
----------
852853
norm : str or `~matplotlib.colors.Normalize`
853854
The normalizer specification. If a `~matplotlib.colors.Normalize`
854-
instance already, the input argument is simply returned. Otherwise,
855-
`norm` should be a string corresponding to one of the "registered"
856-
colormap normalizers (see below table).
855+
instance already, a `copy.copy` of the instance is returned.
856+
Otherwise, `norm` should be a string corresponding to one of
857+
the "registered" colormap normalizers (see below table).
857858
858859
If `norm` is a list or tuple and the first element is a "registered"
859860
normalizer name, subsequent elements are passed to the normalizer class
@@ -892,7 +893,7 @@ def Norm(norm, *args, **kwargs):
892893
if np.iterable(norm) and not isinstance(norm, str):
893894
norm, *args = *norm, *args
894895
if isinstance(norm, mcolors.Normalize):
895-
return norm
896+
return copy.copy(norm)
896897
if not isinstance(norm, str):
897898
raise ValueError(f'Invalid norm name {norm!r}. Must be string.')
898899
if norm not in NORMS:
@@ -915,8 +916,8 @@ def Locator(locator, *args, index=False, discrete=False, **kwargs):
915916
locator : `~matplotlib.ticker.Locator`, str, bool, float, or sequence
916917
The locator specification, interpreted as follows:
917918
918-
* If a `~matplotlib.ticker.Locator` instance already, the input
919-
argument is simply returned.
919+
* If a `~matplotlib.ticker.Locator` instance already,
920+
a `copy.copy` of the instance is returned.
920921
* If ``False``, a `~matplotlib.ticker.NullLocator` is used, and if
921922
``True``, the default `~matplotlib.ticker.AutoLocator` is used.
922923
* If a number, this specifies the *step size* between tick locations.
@@ -995,7 +996,7 @@ def Locator(locator, *args, index=False, discrete=False, **kwargs):
995996
):
996997
locator, *args = *locator, *args
997998
if isinstance(locator, mticker.Locator):
998-
return locator
999+
return copy.copy(locator)
9991000
if isinstance(locator, str):
10001001
if locator == 'index': # defaults
10011002
args = args or (1,)
@@ -1042,8 +1043,8 @@ def Formatter(formatter, *args, date=False, index=False, **kwargs):
10421043
formatter : `~matplotlib.ticker.Formatter`, str, bool, callable, or sequence
10431044
The formatter specification, interpreted as follows:
10441045
1045-
* If a `~matplotlib.ticker.Formatter` instance already, the input
1046-
argument is simply returned.
1046+
* If a `~matplotlib.ticker.Formatter` instance already,
1047+
a `copy.copy` of the instance is returned.
10471048
* If ``False``, a `~matplotlib.ticker.NullFormatter` is used, and if
10481049
``True``, the default `~proplot.ticker.AutoFormatter` is used.
10491050
* If a function, the labels will be generated using this function.
@@ -1142,7 +1143,7 @@ def Formatter(formatter, *args, date=False, index=False, **kwargs):
11421143
):
11431144
formatter, *args = *formatter, *args
11441145
if isinstance(formatter, mticker.Formatter):
1145-
return formatter
1146+
return copy.copy(formatter)
11461147
if isinstance(formatter, str):
11471148
if re.search(r'{x(:.+)?}', formatter): # str.format
11481149
formatter = mticker.StrMethodFormatter(formatter, *args, **kwargs)
@@ -1177,10 +1178,10 @@ def Scale(scale, *args, **kwargs):
11771178
Parameters
11781179
----------
11791180
scale : `~matplotlib.scale.ScaleBase`, str, or tuple
1180-
The axis scale specification. If a `~matplotlib.scale.ScaleBase`
1181-
instance already, the input argument is simply returned. Otherwise,
1182-
`scale` should be a string corresponding to one of the
1183-
"registered" axis scales or axis scale presets (see below table).
1181+
The axis scale specification. If a `~matplotlib.scale.ScaleBase` instance
1182+
already, a `copy.copy` of the instance is returned. Otherwise, `scale`
1183+
should be a string corresponding to one of the "registered" axis scales
1184+
or axis scale presets (see below table).
11841185
11851186
If `scale` is a list or tuple and the first element is a
11861187
"registered" scale name, subsequent elements are passed to the
@@ -1241,7 +1242,7 @@ def Scale(scale, *args, **kwargs):
12411242
if np.iterable(scale) and not isinstance(scale, str):
12421243
scale, *args = *scale, *args
12431244
if isinstance(scale, mscale.ScaleBase):
1244-
return scale
1245+
return copy.copy(scale)
12451246
if not isinstance(scale, str):
12461247
raise ValueError(f'Invalid scale name {scale!r}. Must be string.')
12471248
scale = scale.lower()

proplot/internals/guides.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,12 @@ def _flush_guide_kw(obj, name, kwargs):
4343
"""
4444
# NOTE: Here we *do* want to overwrite properties in dictionary. Indicates
4545
# updating kwargs during parsing (probably only relevant for ax.parametric).
46-
# WARNING: Absolutely *critical* to clear the dictionary after applied from
47-
# the object. Otherwise e.g. use same DiscreteLocator for two colorbars.
46+
# NOTE: Previously had problems reusing same keyword arguments for more than one
47+
# colorbar() because locator or formatter axis would get reset. Old solution was
48+
# to delete the _guide_kw but that destroyed default behavior. New solution is
49+
# to keep _guide_kw but have constructor functions return shallow copies.
4850
opts = getattr(obj, f'_{name}_kw', None)
4951
if opts:
50-
delattr(obj, f'_{name}_kw')
5152
_update_kw(kwargs, overwrite=False, **opts)
5253
if isinstance(obj, (tuple, list, np.ndarray)):
5354
for member in obj: # possibly iterate over matplotlib tuple/list subclasses

0 commit comments

Comments
 (0)