Skip to content

Commit f169951

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

File tree

2 files changed

+83
-7
lines changed

2 files changed

+83
-7
lines changed

galleries/examples/scales/symlog_demo.py

Lines changed: 81 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,11 +39,80 @@
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+
def format_axes(ax, title=None):
53+
ax.xaxis.get_minor_locator().set_params(subs=[2, 3, 4, 5, 6, 7, 8, 9])
54+
ax.grid()
55+
ax.xaxis.grid(which='minor') # minor grid on too
56+
linthresh = ax.xaxis.get_transform().linthresh
57+
linscale = ax.xaxis.get_transform().linscale
58+
ax.axvspan(-linthresh, linthresh, color='0.9')
59+
if title:
60+
ax.set_title(title.format(linthresh=linthresh, linscale=linscale))
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 min(abs(data))`.
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}')
4196

97+
# The suitable value for linscale depends on the dynamic range of data. As most data
98+
# will be outside the linear region, you typically the linear region only to cover
99+
# a small fraction of the visual area.
100+
#
101+
# Limitations and alternatives
102+
# ----------------------------
103+
# The coordinate transform used by ``symlog`` has a discontinuous gradient at the
104+
# transition between its linear and logarithmic regions. Depending on data and
105+
# scaling, this will be more or less obvious in the plot.
106+
107+
fig, ax = plt.subplots()
108+
ax.plot(x, y)
109+
ax.set_xscale('symlog', linscale=0.05)
110+
format_axes(ax, title="Discontinuous gradient at linear/log transition")
111+
112+
# The ``asinh`` axis scale is an alternative transfromation that supports a wide
113+
# dynamic range with a smooth gradient and thus may avoid such visual artifacts.
114+
# See :doc:`/gallery/scales/assinh_demo`.
115+
#
42116
# %%
43117
#
44118
# .. admonition:: References

lib/matplotlib/scale.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,8 @@ class SymmetricalLogScale(ScaleBase):
412412
*linthresh* allows the user to specify the size of this range
413413
(-*linthresh*, *linthresh*).
414414
415+
See :doc:`/gallery/scales/symlog_demo` for a detailed description.
416+
415417
Parameters
416418
----------
417419
base : float, default: 10

0 commit comments

Comments
 (0)