-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Add asinh axis scaling (*smooth* symmetric logscale) #21178
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
39 commits
Select commit
Hold shift + click to select a range
7ec127a
Grafted prototype arcsinh axis-scaling from stand-alone script
rwpenney 15ff4ec
Tidied various baseclass references
rwpenney 9680432
Added more documentation and apx_tick_count parameter
rwpenney 3f69788
Added demo script for asinh axis scaling
rwpenney dd4f4d8
Tidied various flake8 transgressions
rwpenney 1ec0b22
Improved documentation of asinh transformation and parameter naming
rwpenney 2b0d588
Moved AsinhLocator into ticker.py and extracted AsinhScale nested tra…
rwpenney 2002cb3
Added set_params() method to AsinhLocator
rwpenney 070d984
Patched asinh-transforms test numpy namespace
rwpenney 8495f7b
Fixed and refactored various AsinhScale tests
rwpenney 279c38b
Added tests for Asinh tick locations and improved handling of zero-st…
rwpenney 76d9b42
Improved overview documentation
rwpenney 8143153
Improved testing of locator edge-cases, and patched constrained_layou…
rwpenney 800ef38
Minor corrections to documentation
rwpenney 0ad43a5
Improved handling of data ranges almost symmetrical about zero
rwpenney ba597de
Added AutoLocator for minor ticks and further tweaks of zero-crossing…
rwpenney 80f2600
Patched flake8 slip-ups
rwpenney 65eff09
Reworked AsinhLocator to allow rounding on arbitrary number base
rwpenney 8168e56
Improved minor-tick location for common number bases and widened test…
rwpenney 0249861
Added cross-references between symlog and asinh demo pages
rwpenney 9fd8b0c
Added AsinhNorm for colorscale support
rwpenney 8d7c2ad
Fixed SymlogNorm demo to actually use positive & negative values
rwpenney ae57d8d
Further refinements to documentation and test coverage
rwpenney b01d03c
Reworked SymLogNorm demonstration, and added comparision with AsinhNorm
rwpenney e0dcff7
Tweaked flake8 issues
rwpenney 3d92406
Apply suggestions from code review by greglucas
rwpenney 7bec3f4
Patched tick-generation on pan/zoom & misc. tidying
rwpenney 97693e8
Patched overzealous zero edge-case in ticker
rwpenney a1af12c
Apply suggestions from code review
rwpenney 4b23326
Merge branch 'main' into feature/asinh-scale
rwpenney 555bac1
Patched unit-test for default base in AsinhLocator
rwpenney 545faf2
Merge branch 'main' into feature/asinh-scale
rwpenney a2b210d
Added documentation comments forewarning of possible API changes
rwpenney 8a258cf
Apply suggestions from code review
rwpenney 5a03297
Update examples/scales/asinh_demo.py
rwpenney de30538
Minor repair of duplicate "experimental" annotation
rwpenney 3e487a6
Merge branch 'main' into feature/asinh-scale
rwpenney c64d0c4
Tweaked indendation etc. following review by @QuLogic
rwpenney e43cbfd
Patched various 79-character section breaks in documentation
rwpenney File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,6 +21,7 @@ Classes | |
:toctree: _as_gen/ | ||
:template: autosummary.rst | ||
|
||
AsinhNorm | ||
BoundaryNorm | ||
Colormap | ||
CenteredNorm | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
New axis scale ``asinh`` (experimental) | ||
--------------------------------------- | ||
|
||
The new ``asinh`` axis scale offers an alternative to ``symlog`` that | ||
smoothly transitions between the quasi-linear and asymptotically logarithmic | ||
regions of the scale. This is based on an arcsinh transformation that | ||
allows plotting both positive and negative values that span many orders | ||
of magnitude. | ||
QuLogic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
.. plot:: | ||
|
||
import matplotlib.pyplot as plt | ||
import numpy as np | ||
|
||
fig, (ax0, ax1) = plt.subplots(1, 2, sharex=True) | ||
x = np.linspace(-3, 6, 100) | ||
|
||
ax0.plot(x, x) | ||
ax0.set_yscale('symlog') | ||
ax0.grid() | ||
ax0.set_title('symlog') | ||
|
||
ax1.plot(x, x) | ||
ax1.set_yscale('asinh') | ||
ax1.grid() | ||
ax1.set_title(r'$sinh^{-1}$') | ||
|
||
for p in (-2, 2): | ||
for ax in (ax0, ax1): | ||
c = plt.Circle((p, p), radius=0.5, fill=False, | ||
color='red', alpha=0.8, lw=3) | ||
ax.add_patch(c) |
78 changes: 60 additions & 18 deletions
78
examples/images_contours_and_fields/colormap_normalizations_symlognorm.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,42 +1,84 @@ | ||
""" | ||
================================== | ||
Colormap Normalizations Symlognorm | ||
Colormap Normalizations SymLogNorm | ||
================================== | ||
|
||
Demonstration of using norm to map colormaps onto data in non-linear ways. | ||
|
||
.. redirect-from:: /gallery/userdemo/colormap_normalization_symlognorm | ||
""" | ||
|
||
############################################################################### | ||
# Synthetic dataset consisting of two humps, one negative and one positive, | ||
# the positive with 8-times the amplitude. | ||
# Linearly, the negative hump is almost invisible, | ||
# and it is very difficult to see any detail of its profile. | ||
# With the logarithmic scaling applied to both positive and negative values, | ||
# it is much easier to see the shape of each hump. | ||
# | ||
# See `~.colors.SymLogNorm`. | ||
|
||
import numpy as np | ||
import matplotlib.pyplot as plt | ||
import matplotlib.colors as colors | ||
|
||
""" | ||
SymLogNorm: two humps, one negative and one positive, The positive | ||
with 5-times the amplitude. Linearly, you cannot see detail in the | ||
negative hump. Here we logarithmically scale the positive and | ||
negative data separately. | ||
|
||
Note that colorbar labels do not come out looking very good. | ||
""" | ||
def rbf(x, y): | ||
return 1.0 / (1 + 5 * ((x ** 2) + (y ** 2))) | ||
|
||
N = 100 | ||
N = 200 | ||
gain = 8 | ||
X, Y = np.mgrid[-3:3:complex(0, N), -2:2:complex(0, N)] | ||
Z1 = np.exp(-X**2 - Y**2) | ||
Z2 = np.exp(-(X - 1)**2 - (Y - 1)**2) | ||
Z = (Z1 - Z2) * 2 | ||
Z1 = rbf(X + 0.5, Y + 0.5) | ||
Z2 = rbf(X - 0.5, Y - 0.5) | ||
Z = gain * Z1 - Z2 | ||
|
||
shadeopts = {'cmap': 'PRGn', 'shading': 'gouraud'} | ||
colormap = 'PRGn' | ||
lnrwidth = 0.5 | ||
|
||
fig, ax = plt.subplots(2, 1) | ||
fig, ax = plt.subplots(2, 1, sharex=True, sharey=True) | ||
|
||
pcm = ax[0].pcolormesh(X, Y, Z, | ||
norm=colors.SymLogNorm(linthresh=0.03, linscale=0.03, | ||
vmin=-1.0, vmax=1.0, base=10), | ||
cmap='RdBu_r', shading='nearest') | ||
norm=colors.SymLogNorm(linthresh=lnrwidth, linscale=1, | ||
vmin=-gain, vmax=gain, base=10), | ||
**shadeopts) | ||
fig.colorbar(pcm, ax=ax[0], extend='both') | ||
ax[0].text(-2.5, 1.5, 'symlog') | ||
|
||
pcm = ax[1].pcolormesh(X, Y, Z, cmap='RdBu_r', vmin=-np.max(Z), | ||
shading='nearest') | ||
pcm = ax[1].pcolormesh(X, Y, Z, vmin=-gain, vmax=gain, | ||
**shadeopts) | ||
fig.colorbar(pcm, ax=ax[1], extend='both') | ||
ax[1].text(-2.5, 1.5, 'linear') | ||
|
||
|
||
############################################################################### | ||
# In order to find the best visualization for any particular dataset, | ||
# it may be necessary to experiment with multiple different color scales. | ||
# As well as the `~.colors.SymLogNorm` scaling, there is also | ||
# the option of using `~.colors.AsinhNorm` (experimental), which has a smoother | ||
# transition between the linear and logarithmic regions of the transformation | ||
# applied to the data values, "Z". | ||
# In the plots below, it may be possible to see contour-like artifacts | ||
# around each hump despite there being no sharp features | ||
# in the dataset itself. The ``asinh`` scaling shows a smoother shading | ||
# of each hump. | ||
|
||
fig, ax = plt.subplots(2, 1, sharex=True, sharey=True) | ||
|
||
pcm = ax[0].pcolormesh(X, Y, Z, | ||
norm=colors.SymLogNorm(linthresh=lnrwidth, linscale=1, | ||
vmin=-gain, vmax=gain, base=10), | ||
**shadeopts) | ||
fig.colorbar(pcm, ax=ax[0], extend='both') | ||
ax[0].text(-2.5, 1.5, 'symlog') | ||
|
||
pcm = ax[1].pcolormesh(X, Y, Z, | ||
norm=colors.AsinhNorm(linear_width=lnrwidth, | ||
vmin=-gain, vmax=gain), | ||
**shadeopts) | ||
fig.colorbar(pcm, ax=ax[1], extend='both') | ||
ax[1].text(-2.5, 1.5, 'asinh') | ||
|
||
|
||
plt.show() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
""" | ||
============ | ||
Asinh Demo | ||
============ | ||
rwpenney marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
Illustration of the `asinh <.scale.AsinhScale>` axis scaling, | ||
which uses the transformation | ||
|
||
.. math:: | ||
|
||
a \\rightarrow a_0 \\sinh^{-1} (a / a_0) | ||
|
||
For coordinate values close to zero (i.e. much smaller than | ||
the "linear width" :math:`a_0`), this leaves values essentially unchanged: | ||
|
||
.. math:: | ||
|
||
a \\rightarrow a + {\\cal O}(a^3) | ||
|
||
but for larger values (i.e. :math:`|a| \\gg a_0`, this is asymptotically | ||
|
||
.. math:: | ||
|
||
a \\rightarrow a_0 \\, {\\rm sgn}(a) \\ln |a| + {\\cal O}(1) | ||
|
||
As with the `symlog <.scale.SymmetricalLogScale>` scaling, | ||
this allows one to plot quantities | ||
that cover a very wide dynamic range that includes both positive | ||
and negative values. However, ``symlog`` involves a transformation | ||
that has discontinuities in its gradient because it is built | ||
from *separate* linear and logarithmic transformations. | ||
The ``asinh`` scaling uses a transformation that is smooth | ||
for all (finite) values, which is both mathematically cleaner | ||
and reduces visual artifacts associated with an abrupt | ||
transition between linear and logarithmic regions of the plot. | ||
|
||
rwpenney marked this conversation as resolved.
Show resolved
Hide resolved
|
||
.. note:: | ||
`.scale.AsinhScale` is experimental, and the API may change. | ||
|
||
See `~.scale.AsinhScale`, `~.scale.SymmetricalLogScale`. | ||
""" | ||
|
||
import numpy as np | ||
import matplotlib.pyplot as plt | ||
|
||
# Prepare sample values for variations on y=x graph: | ||
x = np.linspace(-3, 6, 500) | ||
|
||
############################################################################### | ||
# Compare "symlog" and "asinh" behaviour on sample y=x graph, | ||
# where there is a discontinuous gradient in "symlog" near y=2: | ||
fig1 = plt.figure() | ||
ax0, ax1 = fig1.subplots(1, 2, sharex=True) | ||
|
||
ax0.plot(x, x) | ||
ax0.set_yscale('symlog') | ||
ax0.grid() | ||
ax0.set_title('symlog') | ||
|
||
ax1.plot(x, x) | ||
ax1.set_yscale('asinh') | ||
ax1.grid() | ||
ax1.set_title('asinh') | ||
|
||
|
||
############################################################################### | ||
# Compare "asinh" graphs with different scale parameter "linear_width": | ||
fig2 = plt.figure(constrained_layout=True) | ||
axs = fig2.subplots(1, 3, sharex=True) | ||
rwpenney marked this conversation as resolved.
Show resolved
Hide resolved
|
||
for ax, (a0, base) in zip(axs, ((0.2, 2), (1.0, 0), (5.0, 10))): | ||
ax.set_title('linear_width={:.3g}'.format(a0)) | ||
ax.plot(x, x, label='y=x') | ||
ax.plot(x, 10*x, label='y=10x') | ||
ax.plot(x, 100*x, label='y=100x') | ||
ax.set_yscale('asinh', linear_width=a0, base=base) | ||
ax.grid() | ||
ax.legend(loc='best', fontsize='small') | ||
|
||
|
||
############################################################################### | ||
# Compare "symlog" and "asinh" scalings | ||
rwpenney marked this conversation as resolved.
Show resolved
Hide resolved
|
||
# on 2D Cauchy-distributed random numbers, | ||
# where one may be able to see more subtle artifacts near y=2 | ||
# due to the gradient-discontinuity in "symlog": | ||
fig3 = plt.figure() | ||
ax = fig3.subplots(1, 1) | ||
r = 3 * np.tan(np.random.uniform(-np.pi / 2.02, np.pi / 2.02, | ||
size=(5000,))) | ||
th = np.random.uniform(0, 2*np.pi, size=r.shape) | ||
|
||
ax.scatter(r * np.cos(th), r * np.sin(th), s=4, alpha=0.5) | ||
ax.set_xscale('asinh') | ||
ax.set_yscale('symlog') | ||
ax.set_xlabel('asinh') | ||
ax.set_ylabel('symlog') | ||
ax.set_title('2D Cauchy random deviates') | ||
ax.set_xlim(-50, 50) | ||
ax.set_ylim(-50, 50) | ||
ax.grid() | ||
|
||
plt.show() | ||
|
||
############################################################################### | ||
# | ||
# .. admonition:: References | ||
# | ||
# - `matplotlib.scale.AsinhScale` | ||
# - `matplotlib.ticker.AsinhLocator` | ||
# - `matplotlib.scale.SymmetricalLogScale` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.