Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
5b09d89
Try to pop vmin and vmax out of norm_kw
lukelbd Sep 2, 2019
a3ebbb1
Respect vmin and vmax as hard minimum/maximum
lukelbd Sep 2, 2019
ba2ce6f
Merge branch 'master' into panels-change-gridspec
lukelbd Sep 2, 2019
bad8024
Remove PanelAxes, and remove 'panels' args from subplots()! Colorbar …
lukelbd Sep 3, 2019
aa4cccf
On-the-fly figure colorbars and legends!
lukelbd Sep 3, 2019
c264999
Return axes_grid of panels, fix _panels_kwargs bug
lukelbd Sep 3, 2019
088a537
Fix axes_grid docstring
lukelbd Sep 3, 2019
bf87d3a
Minor
lukelbd Sep 3, 2019
cfe7e66
axes_grid docstring
lukelbd Sep 3, 2019
3205230
Zoom attribute change
lukelbd Sep 3, 2019
00bd9ff
Auto legend cleanup
lukelbd Sep 3, 2019
25934db
Comments
lukelbd Sep 3, 2019
73dd02c
Better 'span' fig panel aliases
lukelbd Sep 3, 2019
9254346
Add AAAS to journals; fix bug in pulling their dims
bradyrx Sep 4, 2019
32c4cc8
Move journal dictionary to top; add testing for journals
bradyrx Sep 4, 2019
7b6e4e0
Misc bugfixes and cleanup
lukelbd Sep 5, 2019
b8df9e1
Panels bugfix
lukelbd Sep 5, 2019
c67c3f8
Remove print statement
lukelbd Sep 5, 2019
5643867
Update documentation to reflect new colorbars, legends usage, add ins…
lukelbd Sep 5, 2019
4a43155
Merge pull request #31 from lukelbd/panels-change-gridspec
lukelbd Sep 5, 2019
acc905c
Remove duplicate 'Plotting wrappers' docs
lukelbd Sep 5, 2019
c2ae600
All caps constants
lukelbd Sep 6, 2019
f9c6eda
Name change fix
lukelbd Sep 6, 2019
c880ef1
Figure documentation
lukelbd Sep 6, 2019
7a611b5
_subplots_geometry cleanup
lukelbd Sep 6, 2019
43943a7
Merge pull request #30 from bradyrx/add_aaas_journals
lukelbd Sep 6, 2019
ddcc5fe
Repair dead links in wrappers.py
lukelbd Sep 6, 2019
bb3f21a
Merge branch 'master' of https://github.com/lukelbd/proplot
lukelbd Sep 6, 2019
039aea3
Demo stacked figure panels
lukelbd Sep 6, 2019
8804efc
_reassign_title bugfix, minor docs changes
lukelbd Sep 9, 2019
2b78889
Preliminary add_subplot changes
lukelbd Sep 9, 2019
695318b
Merge from master
lukelbd Sep 14, 2019
513d3e0
Fix import error
lukelbd Sep 14, 2019
ff760aa
Merge and fix docs conflicts
lukelbd Sep 18, 2019
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
Prev Previous commit
Next Next commit
Misc bugfixes and cleanup
  • Loading branch information
lukelbd committed Sep 5, 2019
commit 7b6e4e0bdab5bcaba43610b1659446df2f2dcdce
12 changes: 5 additions & 7 deletions proplot/axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,6 @@ def _abc(i):
class Axes(maxes.Axes):
"""Lowest-level axes subclass. Handles titles and axis
sharing. Adds several new methods and overrides existing ones."""
name = 'base'
"""The registered projection name."""
def __init__(self, *args, number=None,
sharex=None, sharey=None, sharex_level=0, sharey_level=0,
spanx=None, spany=None, alignx=None, aligny=None,
Expand Down Expand Up @@ -2097,8 +2095,8 @@ def altx(self, *args, **kwargs):
if self._altx_parent:
raise ValueError('This *is* a twin axes!')
with self.figure._unlock():
ax = self._make_twin_axes(sharey=self, projection=self.name)
ax.set_autoscaley_on(self.get_autoscaley_on()) # shared axes must have matching autoscale
ax = self._make_twin_axes(sharey=self, projection='cartesian')
# ax.set_autoscaley_on(self.get_autoscaley_on()) # shared axes must have matching autoscale
ax.grid(False)
self._altx_child = ax
ax._altx_parent = self
Expand All @@ -2117,8 +2115,8 @@ def alty(self):
if self._alty_parent:
raise ValueError('This *is* a twin axes!')
with self.figure._unlock():
ax = self._make_twin_axes(sharex=self, projection=self.name)
ax.set_autoscalex_on(self.get_autoscalex_on()) # shared axes must have matching autoscale
ax = self._make_twin_axes(sharex=self, projection='cartesian')
# ax.set_autoscalex_on(self.get_autoscalex_on()) # shared axes must have matching autoscale
ax.grid(False)
self._alty_child = ax
ax._alty_parent = self
Expand Down Expand Up @@ -3216,7 +3214,7 @@ def format(self, *, patch_kw=None, **kwargs):
BasemapAxes.format.__doc__ = _projection_format_docstring

# Register the projections
mproj.register_projection(Axes)
# TODO: Remove BasemapAxes!!! Cartopy will support gridline labels soon.
mproj.register_projection(PolarAxes)
mproj.register_projection(CartesianAxes)
mproj.register_projection(BasemapAxes)
Expand Down
2 changes: 1 addition & 1 deletion proplot/styletools.py
Original file line number Diff line number Diff line change
Expand Up @@ -1600,7 +1600,7 @@ def monochrome_cmap(color, fade, reverse=False, space='hsl', name='no_name', **k
#-----------------------------------------------------------------------------#
# Return arbitrary normalizer
#-----------------------------------------------------------------------------#
def Norm(norm, levels=None, values=None, **kwargs):
def Norm(norm, levels=None, **kwargs):
"""
Returns an arbitrary `~matplotlib.colors.Normalize` instance, used to
interpret the `norm` and `norm_kw` arguments when passed to any plotting
Expand Down
25 changes: 21 additions & 4 deletions proplot/subplots.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,23 @@ def axes_grid_iterator(*args, **kwargs):
# Mixed
raise AttributeError(f'Found mixed types for attribute {attr!r}.')

# TODO! No more putting panels, legends, colorbars on the SubplotSpec,
# put them in the margin and increase default space
# def colorbar(self, loc=None):
# """Draws a colorbar that spans axes in the selected range."""
# for ax in self:
# pass
#
# def legend(self, loc=None):
# """Draws a legend that spans axes in the selected range."""
# for ax in self:
# pass
#
# def text(self, loc=None):
# """Draws text that spans axes in the selected range."""
# for ax in self:
# pass

#-----------------------------------------------------------------------------#
# Gridspec classes
#-----------------------------------------------------------------------------#
Expand Down Expand Up @@ -1307,15 +1324,15 @@ def _update_axislabels(self, axis=None, **kwargs):
return
# Update label on this axes
axis.label.update(kwargs)
kwargs.pop('color', None)

# Defer to parent (main) axes if possible, then get the axes
# shared by that parent
# TODO: Share panels in successive stacks, but share short axes
# just like sharing long axes
ax = axis.axes
sax = getattr(ax, '_share' + x, None)
while isinstance(ax, axes.PanelAxes) and sax is not None:
ax, sax = sax, getattr(sax, '_share' + x, None)
ax = ax._panel_parent or ax
ax = getattr(ax, '_share' + x) or ax

# Apply to spanning axes and their panels
axs = [ax]
Expand All @@ -1325,7 +1342,7 @@ def _update_axislabels(self, axis=None, **kwargs):
axs = ax._get_side_axes(s)
for ax in axs:
getattr(ax, x + 'axis').label.update(kwargs) # apply to main axes
pax = getattr(ax, '_share' + x, None)
pax = getattr(ax, '_share' + x)
if pax is not None: # apply to panel?
getattr(pax, x + 'axis').label.update(kwargs)

Expand Down
54 changes: 31 additions & 23 deletions proplot/wrappers.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ def _load_objects():
_map_disabled_methods = (
# These are obvious
# TODO: Error bars? Will they work? Also bar and barh can be used w/ polar
'twinx', 'twiny',
'matshow', 'imshow', 'spy', # don't disable 'bar' or 'barh', can be used in polar plots
'hist', 'hist2d', 'boxplot', 'violinplot', 'step', 'stem',
# Look into these
Expand Down Expand Up @@ -1629,7 +1630,7 @@ def cycle_wrapper(self, func, *args,
@_expand_methods_list
def cmap_wrapper(self, func, *args, cmap=None, cmap_kw=None,
extend='neither', norm=None, norm_kw=None,
N=None, levels=None, values=None, vmin=None, vmax=None,
N=None, levels=None, values=None, centers=None, vmin=None, vmax=None,
locator=None, symmetric=False, locator_kw=None,
edgefix=None, labels=False, labels_kw=None, fmt=None, precision=2,
colorbar=False, colorbar_kw=None, panel_kw=None,
Expand Down Expand Up @@ -1659,7 +1660,7 @@ def cmap_wrapper(self, func, *args, cmap=None, cmap_kw=None,
extend : {'neither', 'min', 'max', 'both'}, optional
Where to assign unique colors to out-of-bounds data and draw
"extensions" (triangles, by default) on the colorbar.
N, levels : int or list of float, optional
levels, N : int or list of float, optional
The number of level edges, or a list of level edges. If the former,
`locator` is used to generate this many levels at "nice" intervals.
Defaults to ``rc['image.levels']``.
Expand All @@ -1668,7 +1669,7 @@ def cmap_wrapper(self, func, *args, cmap=None, cmap_kw=None,
`~matplotlib.axes.Axes.pcolormesh`, this means they now
accept the `levels` keyword arg. You can now discretize your
colors in a ``pcolor`` plot just like with ``contourf``.
values : int or list of float, optional
values, centers : int or list of float, optional
The number of level centers, or a list of level centers. If provided,
levels are inferred using `~proplot.utils.edges`. This will override
any `levels` input.
Expand Down Expand Up @@ -1771,14 +1772,16 @@ def cmap_wrapper(self, func, *args, cmap=None, cmap_kw=None,
labels_kw = labels_kw or {}
colorbar_kw = colorbar_kw or {}
panel_kw = panel_kw or {}
vmin = _notNone(vmin, norm_kw.pop('vmin', None))
vmax = _notNone(vmax, norm_kw.pop('vmax', None))
# Parse args
# Disable edgefix=True for certain keyword combos e.g. if user wants
# white lines around their pcolor mesh.
name = func.__name__
if not args:
return func(*args, **kwargs)
vmin = _notNone(vmin, norm_kw.pop('vmin', None), None, names=('vmin', 'norm_kw={"vmin":value}'))
vmax = _notNone(vmax, norm_kw.pop('vmax', None), None, names=('vmax', 'norm_kw={"vmax":value}'))
levels = _notNone(N, levels, norm_kw.pop('levels', None), rc['image.levels'], names=('N', 'levels', 'norm_kw={"levels":value}'))
values = _notNone(values, centers, None, names=('values', 'centers'))
colors = _notNone(color, colors, edgecolor, edgecolors, None, names=('color', 'colors', 'edgecolor', 'edgecolors'))
linewidths = _notNone(lw, linewidth, linewidths, None, names=('lw', 'linewidth', 'linewidths'))
linestyles = _notNone(ls, linestyle, linestyles, None, names=('ls', 'linestyle', 'linestyles'))
Expand All @@ -1798,29 +1801,34 @@ def cmap_wrapper(self, func, *args, cmap=None, cmap_kw=None,
for key,val in (('levels',levels),('values',values)):
if not np.iterable(val):
continue
if 'contour' in name and 'contourf' not in name:
continue
if len(val) < 2 or any(np.diff(val) <= 0):
raise ValueError(f'{key!r} must be monotonically increasing and at least length 2, got {val}.')

# Get level edges from level centers
# Make sure values are *averages* of encompassing levels, so that tick
# marks appear in the center of the colorbar level.
if values is not None:
if isinstance(values, Number):
levels = values + 1
elif np.iterable(values):
# Plotting command accepts a 'values' keyword arg
if name in ('cmapline',):
kwargs['values'] = values
# Try to generate levels such that a LinearSegmentedNorm will
# place values ticks right at the center of each colorbar level
if norm is None or norm in ('segments','segmented'):
levels = [values[0] - (values[1]-values[0])/2] # reasonable starting point
for i,val in enumerate(values):
levels.append(2*val - levels[-1])
if any(np.diff(levels) <= 0): # algorithm failed, default to this
levels = utils.edges(values)
# Generate levels by finding in-between points in the
# normalized numeric space
else:
norm_tmp = styletools.Norm(norm, **norm_kw)
levels = norm_tmp.inverse(utils.edges(norm_tmp(values)))
inorm = styletools.Norm(norm, **norm_kw)
levels = inorm.inverse(utils.edges(inorm(values)))
else:
raise ValueError('Unexpected values input {values!r}. Must be integer or list of numbers.')
raise ValueError(f'Unexpected input values={values!r}. Must be integer or list of numbers.')

# Data limits used for normalizer
Z = ma.masked_invalid(args[-1], copy=False)
Expand All @@ -1832,7 +1840,7 @@ def cmap_wrapper(self, func, *args, cmap=None, cmap_kw=None,
zmin, zmax = 0, 1

# Input colormap, for methods that accept a colormap and normalizer
if not name[-7:] == 'contour': # contour, tricontour, i.e. not a method where cmap is optional
if not ('contour' in name and 'contourf' not in name): # contour, tricontour, i.e. not a method where cmap is optional
cmap = _notNone(cmap, rc['image.cmap'])
if cmap is not None:
# Get colormap object
Expand All @@ -1845,22 +1853,22 @@ def cmap_wrapper(self, func, *args, cmap=None, cmap_kw=None,

# Get default normalizer
# Only use LinearSegmentedNorm if necessary, because it is slow
if norm is None and name not in ('hexbin',):
if not np.iterable(levels):
norm = 'linear'
else:
diff = np.diff(levels)
eps = diff.mean()/1e3
if (np.abs(np.diff(diff)) >= eps).any():
norm = 'segmented'
else:
if name not in ('hexbin',):
if norm is None:
if not np.iterable(levels) or len(levels) == 1:
norm = 'linear'
if norm is not None:
norm = styletools.Norm(norm, levels=levels, **norm_kw)
else:
diff = np.diff(levels)
eps = diff.mean()/1e3
if (np.abs(np.diff(diff)) >= eps).any():
norm = 'segmented'
norm_kw.setdefault('levels', levels)
else:
norm = 'linear'
norm = styletools.Norm(norm, **norm_kw)

# Get default levels
# TODO: Add kernel density plot to hexbin!
levels = _notNone(N, levels, rc['image.levels'], names=('N', 'levels'))
if isinstance(levels, Number):
# Cannot infer counts a priori, so do nothing
if name in ('hexbin',):
Expand Down