Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
"""
Return dictionaries of proplot and matplotlib settings loaded from the file.
"""
added = set()
path = os.path.expanduser(path)
kw_proplot = {}
kw_matplotlib = {}
with open(path, 'r') as fh:
for cnt, line in enumerate(fh):
# Parse line and ignore comments
stripped = line.split('#', 1)[0].strip()
if not stripped:
continue
pair = stripped.split(':', 1)
if len(pair) != 2:
warnings._warn_proplot(
f'Illegal line #{cnt + 1} in file {path!r}:\n{line!r}"'
)
continue
# Get key value pair
key, val = pair
key = key.strip()
val = val.strip()
if key in added:
warnings._warn_proplot(
f'Duplicate key {key!r} on line #{cnt + 1} in file {path!r}.'
)
added.add(key)
# *Very primitive* type conversion system for proplot settings.
# Matplotlib does this automatically.
'All files in this folder should have extension .txt.'
)
# Read data
loaded = {}
with open(path, 'r') as fh:
for cnt, line in enumerate(fh):
# Load colors from file
stripped = line.strip()
if not stripped or stripped[0] == '#':
continue
pair = tuple(
item.strip().lower() for item in line.split(':')
)
if len(pair) != 2 or not hex.match(pair[1]):
warnings._warn_proplot(
f'Illegal line #{cnt + 1} in file {path!r}:\n'
f'{line!r}\n'
f'Lines must be formatted as "name: hexcolor".'
)
continue
# Never overwrite "base" colors with xkcd colors.
# Only overwrite with user colors.
name, color = pair
if i == 0 and name in BASE_COLORS:
continue
loaded[name] = color
# Add every user color and every opencolor color and ensure XKCD
# colors are "perceptually distinct".
if i == 1:
mcolors.colorConverter.colors.update(loaded)
('markerfacecolor', markerfacecolor),
):
if value is not None:
if isinstance(value, str) or not np.iterable(value):
raise ValueError(
f'Invalid {key!r} property {value!r}. '
f'Must be list or tuple of properties.'
)
nprops = max(nprops, len(value))
props[key] = [*value] # ensure mutable list
# If args is non-empty, means we want color cycle; otherwise is black
if not args:
props['color'] = [mcolors.to_rgba('k')]
if kwargs:
warnings._warn_proplot(
f'Ignoring Cycle() keyword arg(s) {kwargs}.'
)
# Merge cycler objects
elif all(isinstance(arg, cycler.Cycler) for arg in args):
if kwargs:
warnings._warn_proplot(
f'Ignoring Cycle() keyword arg(s) {kwargs}.'
)
if len(args) == 1:
return args[0]
else:
props = {}
for arg in args:
for key, value in arg.by_key():
if key not in props:
# Translate from nodots to 'full' version
if '.' not in key:
key = rcsetup._rc_nodots.get(key, key)
# Handle deprecations
if key in rcsetup._rc_removed:
alternative, version = rcsetup._rc_removed[key]
message = f'rc setting {key!r} was removed in version {version}.'
if alternative: # provide an alternative
message = f'{message} {alternative}'
warnings._warn_proplot(warnings)
key = None
if key in rcsetup._rc_renamed:
key_new, version = rcsetup._rc_renamed[key]
warnings._warn_proplot(
f'rc setting {key!r} was renamed to {key_new} in version {version}.'
)
key = key_new
return key.lower()
.. _stere: https://proj4.org/operations/projections/stere.html
.. _tmerc: https://proj4.org/operations/projections/tmerc.html
.. _utm: https://proj4.org/operations/projections/utm.html
.. _vandg: https://proj4.org/operations/projections/vandg.html
.. _wintri: https://proj4.org/operations/projections/wintri.html
""" # noqa
# Class instances
is_crs = CRS is not object and isinstance(name, CRS)
is_basemap = Basemap is not object and isinstance(name, Basemap)
if is_crs or is_basemap:
proj = name
proj._proj_package = 'cartopy' if is_crs else 'basemap'
if basemap is not None:
kwargs['basemap'] = basemap
if kwargs:
warnings._warn_proplot(f'Ignoring Proj() keyword arg(s): {kwargs!r}.')
# Invalid
elif not isinstance(name, str):
raise ValueError(
f'Unexpected Proj() argument {name!r}. '
'Must be name, mpl_toolkits.basemap.Basemap instance, '
'or cartopy.crs.CRS instance.'
)
# Basemap
elif basemap:
# NOTE: Known issue that basemap sometimes produces backwards maps:
# https://stackoverflow.com/q/56299971/4970632
# NOTE: We set rsphere to fix non-conda installed basemap issue:
# https://github.com/matplotlib/basemap/issues/361
# NOTE: Unlike cartopy, basemap resolution is configured on
to a backup file with the suffix ``.bak``.
comment : bool, optional
Whether to comment out the default settings. Default is the
value of `user`.
description : bool, optional
Whether to include descriptions of each setting as comments.
Default is ``False``.
"""
if path is None:
path = '~'
path = os.path.abspath(os.path.expanduser(path))
if os.path.isdir(path):
path = os.path.join(path, '.proplotrc')
if os.path.isfile(path) and backup:
os.rename(path, path + '.bak')
warnings._warn_proplot(
f'Existing proplotrc file {path!r} was moved to {path + ".bak"!r}.'
)
# Generate user-specific table, ignoring non-style related
# settings that may be changed from defaults like 'backend'
rc_user = ()
if user:
# Changed settings
rcdict = {
key: value for key, value in self
if value != rcsetup._get_default_param(key)
}
# Special handling for certain settings
# TODO: For now not sure how to detect if prop cycle changed since
# we cannot load it from _cmap_database in rcsetup.
warn : bool, optional
Whether to issue warning when colors are clipped.
"""
colors = np.array(colors)
over = colors > 1
under = colors < 0
if clip:
colors[under] = 0
colors[over] = 1
else:
colors[under | over] = gray
if warn:
msg = 'Clipped' if clip else 'Invalid'
for i, name in enumerate('rgb'):
if under[:, i].any():
warnings._warn_proplot(f'{msg} {name!r} channel ( < 0).')
if over[:, i].any():
warnings._warn_proplot(f'{msg} {name!r} channel ( > 1).')
return colors
names = ('axwidth', 'axheight', 'width', 'height')
values = (axwidth, axheight, width, height)
width, height = figsize
elif width is not None or height is not None:
spec = []
if width is not None:
spec.append(f'width={width!r}')
if height is not None:
spec.append(f'height={height!r}')
spec = ', '.join(spec)
names = ('axwidth', 'axheight')
values = (axwidth, axheight)
# Raise warning
for name, value in zip(names, values):
if value is not None:
warnings._warn_proplot(
f'You specified both {spec} and {name}={value!r}. '
f'Ignoring {name!r}.'
)
# Standardized dimensions
width, height = units(width), units(height)
axwidth, axheight = units(axwidth), units(axheight)
# Standardized user input border spaces
left, right = units(left), units(right)
bottom, top = units(bottom), units(top)
# Standardized user input spaces
wspace = np.atleast_1d(units(_not_none(wspace, space)))
hspace = np.atleast_1d(units(_not_none(hspace, space)))
if len(wspace) == 1:
outside, inside = 'bottom', 'top'
if side == 'top':
outside, inside = inside, outside
ticklocation = outside
orientation = 'horizontal'
else:
outside, inside = 'left', 'right'
if side == 'right':
outside, inside = inside, outside
ticklocation = outside
orientation = 'vertical'
# Keyword args and add as child axes
orientation_user = kwargs.get('orientation', None)
if orientation_user and orientation_user != orientation:
warnings._warn_proplot(
f'Overriding input orientation={orientation_user!r}.'
)
ticklocation = _not_none(
ticklocation=kwargs.pop('ticklocation', None),
tickloc=kwargs.pop('tickloc', None),
default=ticklocation,
)
kwargs.update({
'orientation': orientation,
'ticklocation': ticklocation
})
# Inset colorbar
else:
# Default props
cbwidth, cblength = width, length
def add_subplot(self, *args, **kwargs):
# Issue warning for new users that try to call
# `~matplotlib.figure.Figure.add_subplot` manually.
if not self._authorized_add_subplot:
warnings._warn_proplot(
'Using "fig.add_subplot()" with ProPlot figures may result in '
'unexpected behavior. Please use "proplot.subplots()" instead.'
)
return super().add_subplot(*args, **kwargs)