From c818093bf9be12ad66097ffb0deebbc5b9c1b940 Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Thu, 19 Dec 2024 15:53:07 +0100 Subject: [PATCH 1/3] DOC: Explain parameters linthresh and linscale of symlog scale Closes #29335 via addressing https://github.com/matplotlib/matplotlib/issues/29335#issuecomment-2548980673. --- galleries/examples/scales/symlog_demo.py | 92 ++++++++++++++++++++++-- 1 file changed, 85 insertions(+), 7 deletions(-) diff --git a/galleries/examples/scales/symlog_demo.py b/galleries/examples/scales/symlog_demo.py index e50be0d0c8a8..ff24860b4210 100644 --- a/galleries/examples/scales/symlog_demo.py +++ b/galleries/examples/scales/symlog_demo.py @@ -1,7 +1,12 @@ """ -=========== -Symlog Demo -=========== +============ +Symlog scale +============ + +The symmetric logarithmic scale is an extension of the logarithmic scale that +also covers negative values. As with the logarithmic scale, it is particularly +useful for numerical data that spans a broad range of values, especially when there +are significant differences between the magnitudes of the numbers involved. Example use of symlog (symmetric log) axis scaling. """ @@ -34,12 +39,85 @@ plt.show() # %% -# It should be noted that the coordinate transform used by ``symlog`` -# has a discontinuous gradient at the transition between its linear -# and logarithmic regions. The ``asinh`` axis scale is an alternative -# technique that may avoid visual artifacts caused by these discontinuities. +# Linear threshold +# ---------------- +# Since each decade on a logarithmic scale covers the same amount of visual space +# and there are infinitely many decades between a given number and zero, the symlog +# scale must deviate from logarithmic mapping in a small range (-x0, x0), so that +# that range is mapped to a finite visual space. +# +# The symlog scale achieves this by defining a parameter *linthresh* and switching +# to a linear mapping in the region *(-linthresh, linthresh)*. + + +def format_axes(ax, title=None): + """A helper function to better visualize properties of the symlog scale.""" + ax.xaxis.get_minor_locator().set_params(subs=[2, 3, 4, 5, 6, 7, 8, 9]) + ax.grid() + ax.xaxis.grid(which='minor') # minor grid on too + linthresh = ax.xaxis.get_transform().linthresh + linscale = ax.xaxis.get_transform().linscale + ax.axvspan(-linthresh, linthresh, color='0.9') + if title: + ax.set_title(title.format(linthresh=linthresh, linscale=linscale)) + + +x = np.linspace(-60, 60, 201) +y = np.linspace(0, 100.0, 201) + +fig, (ax1, ax2) = plt.subplots(nrows=2, layout="constrained") + +ax1.plot(x, y) +ax1.set_xscale('symlog', linthresh=1) +format_axes(ax1, title='Linear region: linthresh={linthresh}') + +ax2.plot(x, y) +ax2.set_xscale('symlog', linthresh=5) +format_axes(ax2, title='Linear region: linthresh={linthresh}') # %% +# Generally, *linthresh* should be chosen so that no or only a few +# data points are in the linear region. As a rule of thumb, +# :math:`linthresh \approx \mathrm{min} |x|`. +# +# +# Linear scale +# ------------ +# Additionally, the *linscale* parameter determines how much visual space should be +# used for the linear range. More precisely, it defines the ratio of visual space +# of the region (0, linthresh) relative to one decade. + +fig, (ax1, ax2) = plt.subplots(nrows=2, layout="constrained") + +ax1.plot(x, y) +ax1.set_xscale('symlog', linthresh=1) +format_axes(ax1, title='Linear region: linthresh={linthresh}, linscale={linscale}') + +ax2.plot(x, y) +ax2.set_xscale('symlog', linthresh=1, linscale=0.1) +format_axes(ax2, title='Linear region: linthresh={linthresh}, linscale={linscale}') + +# %% +# The suitable value for linscale depends on the dynamic range of data. As most data +# will be outside the linear region, you typically the linear region only to cover +# a small fraction of the visual area. +# +# Limitations and alternatives +# ---------------------------- +# The coordinate transform used by ``symlog`` has a discontinuous gradient at the +# transition between its linear and logarithmic regions. Depending on data and +# scaling, this will be more or less obvious in the plot. + +fig, ax = plt.subplots() +ax.plot(x, y) +ax.set_xscale('symlog', linscale=0.05) +format_axes(ax, title="Discontinuous gradient at linear/log transition") + +# %% +# The ``asinh`` axis scale is an alternative transformation that supports a wide +# dynamic range with a smooth gradient and thus may avoid such visual artifacts. +# See :doc:`/gallery/scales/asinh_demo`. +# # # .. admonition:: References # From 70382ad7c4191e791dc57b5f0f3bed9c522bc809 Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Sat, 21 Dec 2024 00:37:14 +0100 Subject: [PATCH 2/3] Update galleries/examples/scales/symlog_demo.py Co-authored-by: Greg Lucas --- galleries/examples/scales/symlog_demo.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/galleries/examples/scales/symlog_demo.py b/galleries/examples/scales/symlog_demo.py index ff24860b4210..c00a22c73768 100644 --- a/galleries/examples/scales/symlog_demo.py +++ b/galleries/examples/scales/symlog_demo.py @@ -43,11 +43,8 @@ # ---------------- # Since each decade on a logarithmic scale covers the same amount of visual space # and there are infinitely many decades between a given number and zero, the symlog -# scale must deviate from logarithmic mapping in a small range (-x0, x0), so that -# that range is mapped to a finite visual space. -# -# The symlog scale achieves this by defining a parameter *linthresh* and switching -# to a linear mapping in the region *(-linthresh, linthresh)*. +# scale must deviate from logarithmic mapping in a small range *(-linthresh, linthresh)*, so that +# the range is mapped to a finite visual space. def format_axes(ax, title=None): From 6694a9c136c4f5adf1cc72ecf8807c6771d21262 Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Sat, 21 Dec 2024 01:32:51 +0100 Subject: [PATCH 3/3] Apply suggestions from code review --- galleries/examples/scales/symlog_demo.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/galleries/examples/scales/symlog_demo.py b/galleries/examples/scales/symlog_demo.py index c00a22c73768..47742b853cc9 100644 --- a/galleries/examples/scales/symlog_demo.py +++ b/galleries/examples/scales/symlog_demo.py @@ -43,8 +43,8 @@ # ---------------- # Since each decade on a logarithmic scale covers the same amount of visual space # and there are infinitely many decades between a given number and zero, the symlog -# scale must deviate from logarithmic mapping in a small range *(-linthresh, linthresh)*, so that -# the range is mapped to a finite visual space. +# scale must deviate from logarithmic mapping in a small range +# *(-linthresh, linthresh)*, so that the range is mapped to a finite visual space. def format_axes(ax, title=None): pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy