Skip to content

[ENH]: Indicating change of scale for symlog #29335

Closed

Description

@SteffenBeirle

Problem

I appreciate that matplotlib provides various scales, including symlog.
However, I see the problem that it is not quite clear in the axis labels what happens.

Proposed solution

I propose to (at least optionally) insert automatically a break (like // ) on the axis at the transitions between lin and log scales.

Activity

  1. timhoffm commented on Dec 17, 2024

    @timhoffm
    Member

    Fundamentally, I believe this is a good idea. It's a bit difficult to implement though. Conceptually, we only have the locator, which determines tick positions. We don't have any infrastructure/API to handle the additional markers. Any automatism would need architectural changes.

    A simple workaround would be a dedicated mark_symlog_linear_range() method that the user must call explicitly. It would add appropriate markers statically, but wouldn't update with a change of scale. - Possibly an example with such a function would be a good first step.

  2. SteffenBeirle commented on Dec 17, 2024

    @SteffenBeirle
    Author
  3. timhoffm commented on Dec 17, 2024

    @timhoffm
    Member

    One quick solution would be something like this:

    def mark_symlog_linear_range(axis):
        trafo =  axis.get_transform()
        if not hasattr(trafo, "linthresh"):
            raise ValueError("mark_symlog_linear_range() can only be applied to Axis with symmetrical log scale")
    
        if axis.axis_name == 'x':
            axis.axes.axvspan(-trafo.linthresh, trafo.linthresh, -0.02, 0.0, clip_on=False, color='lightgray')
        elif axis.axis_name == 'y':
            axis.axes.axhspan(-trafo.linthresh, trafo.linthresh, -0.02, 0.0, clip_on=False, color='lightgray')
        else:
            raise ValueError("mark_symlog_linear_range() only works on x-axis and y-axis")

    Which then could be used as

    import matplotlib.pyplot as plt
    import numpy as np
    
    dt = 0.01
    x = np.arange(-50.0, 50.0, dt)
    y = np.arange(0, 100.0, dt)
    
    fig, ax = plt.subplots()
    
    ax.plot(x, y)
    ax.set_xscale('symlog', linthresh=10)
    ax.grid()
    ax.set_xlim(-20, 20)
    mark_symlog_linear_range(ax.xaxis)

    image

  4. jklymak commented on Dec 17, 2024

    @jklymak
    Member

    Usually people want the linear region to be imperceptible. If folks want the split in scales to be obvious there are lots of ways to do that which will depend on the reason for making it clear. Perhaps @timhoffm example above could be added to the examples page, but I don't think we could or should provide a universal method for indicating this.

    Symlog should really be discouraged compared to asinh.

  5. timhoffm commented on Dec 17, 2024

    @timhoffm
    Member

    The linear region is a necessary deviation from the log scaling to be able to map data in a range (-x0, x0) onto a finite region. I agree with @jklymak that the linear range should typically a tiny fraction of the view range. It should be chosen to be slightly smaller than the absolute value of all “interesting data”.
    We should better explain why it is necessary and how to use it, rather than adding tooling to visualize it. This explanation should likely go into https://matplotlib.org/devdocs/gallery/scales/symlog_demo.html and be cross-linked from https://matplotlib.org/devdocs/api/scale_api.html#matplotlib.scale.SymmetricalLogScale.

  6. SteffenBeirle commented on Dec 19, 2024

    @SteffenBeirle
    Author
  7. added 6 commits that reference this issue on Dec 19, 2024
    f169951
    5835396
    adb1a20
    5a4f30a
    7311008
    c818093
  8. added a commit that references this issue on Dec 21, 2024
    109f857
  9. added this to the v3.10.0-doc milestone on Dec 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions