|
1 | 1 | """
|
2 |
| -=========== |
3 |
| -Symlog Demo |
4 |
| -=========== |
| 2 | +============ |
| 3 | +Symlog scale |
| 4 | +============ |
| 5 | +
|
| 6 | +The symmetric logarithmic scale is an extension of the logarithmic scale that |
| 7 | +also covers negative values. As with the logarithmic scale, it is particularly |
| 8 | +useful for numerical data that spans a broad range of values, especially when there |
| 9 | +are significant differences between the magnitudes of the numbers involved. |
5 | 10 |
|
6 | 11 | Example use of symlog (symmetric log) axis scaling.
|
7 | 12 | """
|
|
34 | 39 | plt.show()
|
35 | 40 |
|
36 | 41 | # %%
|
37 |
| -# It should be noted that the coordinate transform used by ``symlog`` |
38 |
| -# has a discontinuous gradient at the transition between its linear |
39 |
| -# and logarithmic regions. The ``asinh`` axis scale is an alternative |
40 |
| -# technique that may avoid visual artifacts caused by these discontinuities. |
| 42 | +# Linear threshold |
| 43 | +# ---------------- |
| 44 | +# Since each decade on a logarithmic scale covers the same amount of visual space |
| 45 | +# and there are infinitely many decades between a given number and zero, the symlog |
| 46 | +# scale must deviate from logarithmic mapping in a small range |
| 47 | +# *(-linthresh, linthresh)*, so that the range is mapped to a finite visual space. |
| 48 | + |
| 49 | + |
| 50 | +def format_axes(ax, title=None): |
| 51 | + """A helper function to better visualize properties of the symlog scale.""" |
| 52 | + ax.xaxis.get_minor_locator().set_params(subs=[2, 3, 4, 5, 6, 7, 8, 9]) |
| 53 | + ax.grid() |
| 54 | + ax.xaxis.grid(which='minor') # minor grid on too |
| 55 | + linthresh = ax.xaxis.get_transform().linthresh |
| 56 | + linscale = ax.xaxis.get_transform().linscale |
| 57 | + ax.axvspan(-linthresh, linthresh, color='0.9') |
| 58 | + if title: |
| 59 | + ax.set_title(title.format(linthresh=linthresh, linscale=linscale)) |
| 60 | + |
| 61 | + |
| 62 | +x = np.linspace(-60, 60, 201) |
| 63 | +y = np.linspace(0, 100.0, 201) |
| 64 | + |
| 65 | +fig, (ax1, ax2) = plt.subplots(nrows=2, layout="constrained") |
| 66 | + |
| 67 | +ax1.plot(x, y) |
| 68 | +ax1.set_xscale('symlog', linthresh=1) |
| 69 | +format_axes(ax1, title='Linear region: linthresh={linthresh}') |
| 70 | + |
| 71 | +ax2.plot(x, y) |
| 72 | +ax2.set_xscale('symlog', linthresh=5) |
| 73 | +format_axes(ax2, title='Linear region: linthresh={linthresh}') |
| 74 | + |
| 75 | +# %% |
| 76 | +# Generally, *linthresh* should be chosen so that no or only a few |
| 77 | +# data points are in the linear region. As a rule of thumb, |
| 78 | +# :math:`linthresh \approx \mathrm{min} |x|`. |
| 79 | +# |
| 80 | +# |
| 81 | +# Linear scale |
| 82 | +# ------------ |
| 83 | +# Additionally, the *linscale* parameter determines how much visual space should be |
| 84 | +# used for the linear range. More precisely, it defines the ratio of visual space |
| 85 | +# of the region (0, linthresh) relative to one decade. |
| 86 | + |
| 87 | +fig, (ax1, ax2) = plt.subplots(nrows=2, layout="constrained") |
| 88 | + |
| 89 | +ax1.plot(x, y) |
| 90 | +ax1.set_xscale('symlog', linthresh=1) |
| 91 | +format_axes(ax1, title='Linear region: linthresh={linthresh}, linscale={linscale}') |
| 92 | + |
| 93 | +ax2.plot(x, y) |
| 94 | +ax2.set_xscale('symlog', linthresh=1, linscale=0.1) |
| 95 | +format_axes(ax2, title='Linear region: linthresh={linthresh}, linscale={linscale}') |
41 | 96 |
|
42 | 97 | # %%
|
| 98 | +# The suitable value for linscale depends on the dynamic range of data. As most data |
| 99 | +# will be outside the linear region, you typically the linear region only to cover |
| 100 | +# a small fraction of the visual area. |
| 101 | +# |
| 102 | +# Limitations and alternatives |
| 103 | +# ---------------------------- |
| 104 | +# The coordinate transform used by ``symlog`` has a discontinuous gradient at the |
| 105 | +# transition between its linear and logarithmic regions. Depending on data and |
| 106 | +# scaling, this will be more or less obvious in the plot. |
| 107 | + |
| 108 | +fig, ax = plt.subplots() |
| 109 | +ax.plot(x, y) |
| 110 | +ax.set_xscale('symlog', linscale=0.05) |
| 111 | +format_axes(ax, title="Discontinuous gradient at linear/log transition") |
| 112 | + |
| 113 | +# %% |
| 114 | +# The ``asinh`` axis scale is an alternative transformation that supports a wide |
| 115 | +# dynamic range with a smooth gradient and thus may avoid such visual artifacts. |
| 116 | +# See :doc:`/gallery/scales/asinh_demo`. |
| 117 | +# |
43 | 118 | #
|
44 | 119 | # .. admonition:: References
|
45 | 120 | #
|
|
0 commit comments