Skip to content

Commit b997622

Browse files
committed
Major colorbar_wrapper cleanup, 1d and 2d plotting docs
1 parent d9e9f27 commit b997622

File tree

8 files changed

+126
-250
lines changed

8 files changed

+126
-250
lines changed

docs/1dplots.ipynb

Lines changed: 16 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,14 @@
3030
},
3131
"source": [
3232
"The `~proplot.wrappers.standardize_1d` wrapper used to standardize the input of a bunch of different plotting functions. \n",
33-
"`~proplot.wrappers.standardize_1d` allows you to optionally omit *x* coordinates (in which case they are inferred from the *y* coordinates) or pass 2D *y* coordinate arrays (in which case the plotting method is called with each column of the array). See the documentation for details."
33+
"`~proplot.wrappers.standardize_1d` allows you to optionally omit *x* coordinates (in which case they are inferred from the *y* coordinates) or pass 2D *y* coordinate arrays (in which case the plotting method is called with each column of the array)."
3434
]
3535
},
3636
{
3737
"cell_type": "markdown",
3838
"metadata": {},
3939
"source": [
40-
"## Pandas and xarray integration"
40+
"## Pandas and xarray"
4141
]
4242
},
4343
{
@@ -96,23 +96,7 @@
9696
"cell_type": "markdown",
9797
"metadata": {},
9898
"source": [
99-
"## On-the-fly property cycles"
100-
]
101-
},
102-
{
103-
"cell_type": "raw",
104-
"metadata": {
105-
"raw_mimetype": "text/restructuredtext"
106-
},
107-
"source": [
108-
"The `~proplot.wrappers.cycle_changer` wrapper allows you to create and apply new property cyclers on-the-fly. Just pass the `cycle` keyword argument to any supported plotting method. See :ref:`Making new color cycles` for details."
109-
]
110-
},
111-
{
112-
"cell_type": "markdown",
113-
"metadata": {},
114-
"source": [
115-
"## Easier error bars"
99+
"## On-the-fly error bars"
116100
]
117101
},
118102
{
@@ -329,38 +313,40 @@
329313
"source": [
330314
"import proplot as plot\n",
331315
"import numpy as np\n",
332-
"plot.rc.reset()\n",
333316
"N = 50\n",
334317
"cmap = 'IceFire'\n",
335318
"values = np.linspace(-N/2, N/2, N)\n",
336319
"f, axs = plot.subplots(share=0, ncols=2, wratios=(2, 1),\n",
337320
" axwidth='6cm', aspect=(2, 1))\n",
321+
"axs.format(suptitle='Parametric plots demo')\n",
322+
"# Smooth gradations\n",
338323
"ax = axs[0]\n",
339324
"state = np.random.RandomState(51423)\n",
340325
"m = ax.plot((state.rand(N) - 0.5).cumsum(), state.rand(N),\n",
341326
" cmap=cmap, values=values, lw=7, extend='both')\n",
342327
"ax.format(xlabel='xlabel', ylabel='ylabel',\n",
343-
" title='Line with smooth color gradations', titleweight='bold')\n",
328+
" title='Line with smooth gradations')\n",
344329
"ax.format(xlim=(-1, 5), ylim=(-0.2, 1.2))\n",
345330
"ax.colorbar(m, loc='b', label='parametric coordinate', locator=5)\n",
331+
"# Step gradations\n",
346332
"N = 12\n",
347333
"ax = axs[1]\n",
348-
"values = np.linspace(-N/2, N/2 - 1, N)\n",
349-
"radii = np.linspace(1, 0.2, N)\n",
350-
"angles = np.linspace(0, 4*np.pi, N)\n",
334+
"values = np.linspace(-N/2, N/2, N + 1)\n",
335+
"radii = np.linspace(1, 0.2, N + 1)\n",
336+
"angles = np.linspace(0, 4*np.pi, N + 1)\n",
351337
"x = radii*np.cos(1.4*angles)\n",
352338
"y = radii*np.sin(1.4*angles)\n",
353339
"m = ax.plot(x, y, values=values, linewidth=15, interp=False, cmap=cmap)\n",
354340
"ax.format(xlim=(-1, 1), ylim=(-1, 1), title='Step gradations',\n",
355-
" titleweight='bold', xlabel='cosine angle', ylabel='sine angle')\n",
341+
" xlabel='cosine angle', ylabel='sine angle')\n",
356342
"ax.colorbar(m, loc='b', maxn=10, label=f'parametric coordinate')"
357343
]
358344
},
359345
{
360346
"cell_type": "markdown",
361347
"metadata": {},
362348
"source": [
363-
"## Misc enhancements"
349+
"## Scatter plots"
364350
]
365351
},
366352
{
@@ -369,7 +355,7 @@
369355
"raw_mimetype": "text/restructuredtext"
370356
},
371357
"source": [
372-
"Thanks to `~proplot.wrappers.scatter_wrapper` and `~proplot.wrappers.cycle_changer`, `~matplotlib.axes.Axes.scatter` now accepts 2D arrays, just like `~matplotlib.axes.Axes.plot`, and successive calls to `~matplotlib.axes.Axes.scatter` can apply property cycle keys other than `color` -- for example, `marker` and `markersize`. `~matplotlib.axes.Axes.scatter` also now optionally accepts keywords that look like the `~matplotlib.axes.Axes.plot` keywords, which is a bit less confusing. You can also pass colormaps to `~matplotlib.axes.Axes.scatter` just as with matplotlib.\n",
358+
"Thanks to `~proplot.wrappers.scatter_wrapper` and `~proplot.wrappers.cycle_changer`, `~matplotlib.axes.Axes.scatter` now accepts 2D arrays, just like `~matplotlib.axes.Axes.plot`, and successive calls to `~matplotlib.axes.Axes.scatter` can apply property cycle keys other than `color` -- for example, `marker` and `markersize`. `~matplotlib.axes.Axes.scatter` also now optionally takes keywords that look like the `~matplotlib.axes.Axes.plot` keywords, which is a bit less confusing. You can also pass colormaps to `~matplotlib.axes.Axes.scatter` just as with matplotlib.\n",
373359
"\n",
374360
"We are also considering supporting 2D array input and property cycle iteration for more obscure matplotlib plotting commands like `~matplotlib.axes.Axes.stem`, `~matplotlib.axes.Axes.step`, `~matplotlib.axes.Axes.vlines`, and `~matplotlib.axes.Axes.hlines`. Stay tuned!"
375361
]
@@ -395,10 +381,10 @@
395381
" cycle_kw={'marker': ['x', 'o', 'x', 'o'], 'markersize': [5, 10, 20, 30]})\n",
396382
"ax = axs[1]\n",
397383
"ax.format(title='Scatter plot with cmap')\n",
398-
"data = (state.rand(2, 100) - 0.5)\n",
384+
"data = state.rand(2, 100)\n",
399385
"obj = ax.scatter(*data, color=data.sum(axis=0), size=state.rand(100), smin=3, smax=30,\n",
400-
" marker='o', cmap='dusk', colorbar='lr',\n",
401-
" colorbar_kw={'locator': 0.5, 'label': 'label'})\n",
386+
" marker='o', cmap='plum', colorbar='lr', vmin=0, vmax=2,\n",
387+
" colorbar_kw={'label': 'label', 'locator':0.5})\n",
402388
"axs.format(xlabel='xlabel', ylabel='ylabel')"
403389
]
404390
}

docs/2dplots.ipynb

Lines changed: 22 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,14 @@
3030
},
3131
"source": [
3232
"The `~proplot.wrappers.standardize_2d` wrapper is used to standardize the input of a bunch of different plotting functions. \n",
33-
"It allows you to optionally omit *x* and *y* coordinates, in which case they are inffered from the data array; guesses graticule edges for `~matplotlib.axes.Axes.pcolor` and `~matplotlib.axes.Axes.pcolormesh` plots; and optionally enforces global data coverage when plotting in map projections. See the documentation for details."
33+
"It allows you to optionally omit *x* and *y* coordinates, in which case they are inffered from the data array; guesses graticule edges for `~matplotlib.axes.Axes.pcolor` and `~matplotlib.axes.Axes.pcolormesh` plots; and optionally enforces global data coverage when plotting in map projections."
3434
]
3535
},
3636
{
3737
"cell_type": "markdown",
3838
"metadata": {},
3939
"source": [
40-
"## Pandas and xarray integration"
40+
"## Pandas and xarray"
4141
]
4242
},
4343
{
@@ -98,23 +98,7 @@
9898
"cell_type": "markdown",
9999
"metadata": {},
100100
"source": [
101-
"## On-the-fly colormaps"
102-
]
103-
},
104-
{
105-
"cell_type": "raw",
106-
"metadata": {
107-
"raw_mimetype": "text/restructuredtext"
108-
},
109-
"source": [
110-
"The `~proplot.wrappers.cmap_changer` wrapper allows you to create and apply new colormaps on-the-fly. Just pass the `cmap` keyword argument to any supported plotting method. See :ref:`Making new colormaps` for details. This wrapper also implements the features described in :ref:`Colormap levels`, :ref:`Colormap normalizers`, and :ref:`Pcolor and contour labels` below."
111-
]
112-
},
113-
{
114-
"cell_type": "markdown",
115-
"metadata": {},
116-
"source": [
117-
"## Colormap levels"
101+
"## Discrete colormap levels"
118102
]
119103
},
120104
{
@@ -141,12 +125,9 @@
141125
"state = np.random.RandomState(51423)\n",
142126
"data = (state.normal(0, 1, size=(33, 33))).cumsum(axis=0).cumsum(axis=1)\n",
143127
"axs.format(suptitle='Pcolor with levels demo')\n",
144-
"ax = axs[0]\n",
145-
"ax.pcolor(data, cmap=cmap, N=200, symmetric=True, colorbar='l')\n",
146-
"ax.format(title='Ambiguous values', yformatter='null')\n",
147-
"ax = axs[1]\n",
148-
"ax.pcolor(data, cmap=cmap, N=10, symmetric=True, colorbar='r')\n",
149-
"ax.format(title='Discernible levels')"
128+
"for ax, n, mode, side in zip(axs, (200, 10), ('Ambiguous', 'Discernible'), 'lr'):\n",
129+
" ax.pcolor(data, cmap=cmap, N=n, symmetric=True, colorbar=side)\n",
130+
" ax.format(title=f'{mode} values', yformatter='null')"
150131
]
151132
},
152133
{
@@ -179,8 +160,8 @@
179160
"data = (20*(state.rand(20, 20) - 0.4).cumsum(axis=0).cumsum(axis=1)) % 360\n",
180161
"# Show cyclic colorbar with distinct end colors\n",
181162
"ax = axs[0]\n",
182-
"ax.pcolormesh(data, levels=levels, cmap='phase',\n",
183-
" extend='neither', colorbar='b')\n",
163+
"ax.pcolormesh(data, levels=levels, cmap='phase', extend='neither',\n",
164+
" colorbar='b', colorbar_kw={'locator': 90})\n",
184165
"ax.format(title='cyclic colormap\\nwith distinct end colors')\n",
185166
"# Show colorbars with different extend values\n",
186167
"for ax, extend in zip(axs[1:], ('min', 'max', 'neither', 'both')):\n",
@@ -193,7 +174,7 @@
193174
"cell_type": "markdown",
194175
"metadata": {},
195176
"source": [
196-
"## Colormap normalizers"
177+
"## Colormap normalization"
197178
]
198179
},
199180
{
@@ -202,7 +183,11 @@
202183
"raw_mimetype": "text/restructuredtext"
203184
},
204185
"source": [
205-
"If you pass unevenly spaced `levels` to a plotting command, the `~proplot.styletools.LinearSegmentedNorm` normalizer is applied by default. This results in even color gradations across *indices* of the level list, no matter their spacing. To use an arbitrary colormap normalizer, just pass `norm` and optionally `norm_kw` to a command wrapped by `~proplot.wrappers.cmap_changer`. These arguments are passed to the `~proplot.styletools.Norm` constructor."
186+
"If you pass unevenly spaced `levels` to a plotting command, the `~proplot.styletools.LinearSegmentedNorm` normalizer is applied by default. This results in even color gradations across *indices* of the level list, no matter their spacing. \n",
187+
"\n",
188+
"There is a new `~proplot.styletools.MidpointNorm` class that warps your colormap so that its midpoint lies on some central data value, no matter the minimum and maximum colormap colors.\n",
189+
"\n",
190+
"To use an arbitrary colormap normalizer, just pass `norm` and optionally `norm_kw` to a command wrapped by `~proplot.wrappers.cmap_changer`. These arguments are passed to the `~proplot.styletools.Norm` constructor."
206191
]
207192
},
208193
{
@@ -213,6 +198,7 @@
213198
"source": [
214199
"import proplot as plot\n",
215200
"import numpy as np\n",
201+
"# Linear segmented norm\n",
216202
"f, axs = plot.subplots(ncols=2, axwidth=2.5, aspect=1.5)\n",
217203
"state = np.random.RandomState(51423)\n",
218204
"data = 10**(2*state.rand(20, 20).cumsum(axis=0)/7)\n",
@@ -221,36 +207,17 @@
221207
" m = axs[i].contourf(data, levels=ticks, extend='both',\n",
222208
" cmap='Mako', norm=norm, colorbar='b')\n",
223209
" axs[i].format(title=title)\n",
224-
"axs.format(suptitle='Level normalizers demo')"
225-
]
226-
},
227-
{
228-
"cell_type": "raw",
229-
"metadata": {
230-
"raw_mimetype": "text/restructuredtext"
231-
},
232-
"source": [
233-
"Finally, there is a new `~proplot.styletools.MidpointNorm` class that warps your colormap so that its midpoint lies on some central data value, no matter the minimum and maximum colormap colors. Again, to use an arbitrary colormap normalizer, just pass `norm` and optionally `norm_kw` to a command wrapped by `~proplot.wrappers.cmap_changer`. These arguments are passed to the `~proplot.styletools.Norm` constructor."
234-
]
235-
},
236-
{
237-
"cell_type": "code",
238-
"execution_count": null,
239-
"metadata": {},
240-
"outputs": [],
241-
"source": [
242-
"import proplot as plot\n",
243-
"import numpy as np\n",
244-
"state = np.random.RandomState(51423)\n",
210+
"axs.format(suptitle='Level normalizers demo')\n",
211+
"# Midpoint norm\n",
245212
"data1 = (state.rand(20, 20) - 0.43).cumsum(axis=0)\n",
246213
"data2 = (state.rand(20, 20) - 0.57).cumsum(axis=0)\n",
247214
"f, axs = plot.subplots(ncols=2, axwidth=2.5, aspect=1.5)\n",
248215
"cmap = plot.Colormap('Moisture', cut=0.1)\n",
249216
"axs.format(suptitle='Midpoint normalizer demo')\n",
250-
"axs[0].contourf(data1, norm='midpoint', cmap=cmap, colorbar='b')\n",
251-
"axs[0].format(title='Skewed positive data')\n",
252-
"axs[1].contourf(data2, norm='midpoint', cmap=cmap, colorbar='b')\n",
253-
"axs[1].format(title='Skewed negative data')"
217+
"for ax, data, mode in zip(axs, (data1, data2), ('positive', 'negative')):\n",
218+
" m = ax.contourf(data, norm='midpoint', cmap=cmap)\n",
219+
" ax.colorbar(m, loc='b', locator=1, minorlocator=0.25)\n",
220+
" ax.format(title=f'Skewed {mode} data')"
254221
]
255222
},
256223
{
@@ -305,7 +272,7 @@
305272
"cell_type": "markdown",
306273
"metadata": {},
307274
"source": [
308-
"## Heatmaps and covariance matrices"
275+
"## Heatmap plots"
309276
]
310277
},
311278
{

docs/colorbars_legends.ipynb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@
139139
"for abc, color in zip('ABCDEF', cycle):\n",
140140
" h = axs[2:].plot(state.rand(10), lw=3, color=color, label=f'line {abc}')\n",
141141
" hs.extend(h[0])\n",
142-
"f.colorbar(m[0], length=0.8, label='colorbar label', loc='b', col=1)\n",
142+
"f.colorbar(m[0], length=0.8, label='colorbar label', loc='b', col=1, locator=5)\n",
143143
"f.colorbar(m[0], label='colorbar label', loc='l')\n",
144144
"f.legend(hs, ncols=2, center=True, frame=False, loc='b', col=2)\n",
145145
"f.legend(hs, ncols=1, label='legend label', frame=False, loc='r')\n",

proplot/axes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2313,7 +2313,7 @@ class generated by `plot.CutoffScaleFactory('cutoff', 0.5, 2)`.
23132313
raise ValueError(
23142314
f'Invalid {x} spine location {spineloc!r}.'
23152315
f' Options are '
2316-
', '.join(map(
2316+
+ ', '.join(map(
23172317
repr, (*sides, 'both', 'neither')
23182318
)) + '.'
23192319
)

proplot/axistools.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ def Locator(locator, *args, **kwargs):
122122
if locator not in locators:
123123
raise ValueError(
124124
f'Unknown locator {locator!r}. Options are '
125-
', '.join(map(repr, locators.keys())) + '.')
125+
+ ', '.join(map(repr, locators.keys())) + '.')
126126
locator = locators[locator](*args, **kwargs)
127127
elif isinstance(locator, Number): # scalar variable
128128
locator = mticker.MultipleLocator(locator, *args, **kwargs)
@@ -256,7 +256,7 @@ def Formatter(formatter, *args, date=False, **kwargs):
256256
if formatter not in formatters:
257257
raise ValueError(
258258
f'Unknown formatter {formatter!r}. Options are '
259-
', '.join(map(repr, formatters.keys())) + '.')
259+
+ ', '.join(map(repr, formatters.keys())) + '.')
260260
formatter = formatters[formatter](*args, **kwargs)
261261
elif callable(formatter):
262262
formatter = mticker.FuncFormatter(formatter, *args, **kwargs)
@@ -337,7 +337,7 @@ def Scale(scale, *args, **kwargs):
337337
else:
338338
raise ValueError(
339339
f'Unknown scale or preset {scale!r}. Options are '
340-
', '.join(map(repr, list(scales) + list(SCALE_PRESETS))) + '.')
340+
+ ', '.join(map(repr, list(scales) + list(SCALE_PRESETS))) + '.')
341341
axis = _dummy_axis()
342342
return scale(axis, *args, **kwargs)
343343

@@ -518,7 +518,7 @@ def _scale_factory(scale, axis, *args, **kwargs):
518518
if scale not in scales:
519519
raise ValueError(
520520
f'Unknown scale {scale!r}. Options are '
521-
', '.join(map(repr, scales.keys())) + '.')
521+
+ ', '.join(map(repr, scales.keys())) + '.')
522522
return scales[scale](axis, *args, **kwargs)
523523

524524

proplot/projs.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,8 @@ def Proj(name, basemap=False, **kwargs):
160160
'for cartopy axes.')
161161
if crs is None:
162162
raise ValueError(
163-
f'Unknown projection "{name}". Options are: '
164-
', '.join(map(repr, cartopy_projs.keys())))
163+
f'Unknown projection {name!r}. Options are: '
164+
+ ', '.join(map(repr, cartopy_projs.keys())))
165165
proj = crs(**kwargs)
166166
aspect = (np.diff(proj.x_limits) / np.diff(proj.y_limits))[0]
167167
return proj, aspect

0 commit comments

Comments
 (0)