Skip to content

Commit c818093

Browse files
committed
DOC: Explain parameters linthresh and linscale of symlog scale
Closes matplotlib#29335 via addressing matplotlib#29335 (comment).
1 parent f8900ea commit c818093

File tree

1 file changed

+85
-7
lines changed

1 file changed

+85
-7
lines changed

galleries/examples/scales/symlog_demo.py

Lines changed: 85 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
"""
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.
510
611
Example use of symlog (symmetric log) axis scaling.
712
"""
@@ -34,12 +39,85 @@
3439
plt.show()
3540

3641
# %%
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 (-x0, x0), so that
47+
# that range is mapped to a finite visual space.
48+
#
49+
# The symlog scale achieves this by defining a parameter *linthresh* and switching
50+
# to a linear mapping in the region *(-linthresh, linthresh)*.
51+
52+
53+
def format_axes(ax, title=None):
54+
"""A helper function to better visualize properties of the symlog scale."""
55+
ax.xaxis.get_minor_locator().set_params(subs=[2, 3, 4, 5, 6, 7, 8, 9])
56+
ax.grid()
57+
ax.xaxis.grid(which='minor') # minor grid on too
58+
linthresh = ax.xaxis.get_transform().linthresh
59+
linscale = ax.xaxis.get_transform().linscale
60+
ax.axvspan(-linthresh, linthresh, color='0.9')
61+
if title:
62+
ax.set_title(title.format(linthresh=linthresh, linscale=linscale))
63+
64+
65+
x = np.linspace(-60, 60, 201)
66+
y = np.linspace(0, 100.0, 201)
67+
68+
fig, (ax1, ax2) = plt.subplots(nrows=2, layout="constrained")
69+
70+
ax1.plot(x, y)
71+
ax1.set_xscale('symlog', linthresh=1)
72+
format_axes(ax1, title='Linear region: linthresh={linthresh}')
73+
74+
ax2.plot(x, y)
75+
ax2.set_xscale('symlog', linthresh=5)
76+
format_axes(ax2, title='Linear region: linthresh={linthresh}')
4177

4278
# %%
79+
# Generally, *linthresh* should be chosen so that no or only a few
80+
# data points are in the linear region. As a rule of thumb,
81+
# :math:`linthresh \approx \mathrm{min} |x|`.
82+
#
83+
#
84+
# Linear scale
85+
# ------------
86+
# Additionally, the *linscale* parameter determines how much visual space should be
87+
# used for the linear range. More precisely, it defines the ratio of visual space
88+
# of the region (0, linthresh) relative to one decade.
89+
90+
fig, (ax1, ax2) = plt.subplots(nrows=2, layout="constrained")
91+
92+
ax1.plot(x, y)
93+
ax1.set_xscale('symlog', linthresh=1)
94+
format_axes(ax1, title='Linear region: linthresh={linthresh}, linscale={linscale}')
95+
96+
ax2.plot(x, y)
97+
ax2.set_xscale('symlog', linthresh=1, linscale=0.1)
98+
format_axes(ax2, title='Linear region: linthresh={linthresh}, linscale={linscale}')
99+
100+
# %%
101+
# The suitable value for linscale depends on the dynamic range of data. As most data
102+
# will be outside the linear region, you typically the linear region only to cover
103+
# a small fraction of the visual area.
104+
#
105+
# Limitations and alternatives
106+
# ----------------------------
107+
# The coordinate transform used by ``symlog`` has a discontinuous gradient at the
108+
# transition between its linear and logarithmic regions. Depending on data and
109+
# scaling, this will be more or less obvious in the plot.
110+
111+
fig, ax = plt.subplots()
112+
ax.plot(x, y)
113+
ax.set_xscale('symlog', linscale=0.05)
114+
format_axes(ax, title="Discontinuous gradient at linear/log transition")
115+
116+
# %%
117+
# The ``asinh`` axis scale is an alternative transformation that supports a wide
118+
# dynamic range with a smooth gradient and thus may avoid such visual artifacts.
119+
# See :doc:`/gallery/scales/asinh_demo`.
120+
#
43121
#
44122
# .. admonition:: References
45123
#

0 commit comments

Comments
 (0)