Skip to content

[MNT]: Refactor kwargs of Tick constructor  #26008

Open

Description

@anntzer

Summary

Currently, the Tick constructor smashes together kwargs specific to it, kwargs for the tickmarkers, for the labels, and for the gridline:

    def __init__(
        self, axes, loc, *,  # global
        size=None,  # tickmarker property
        width=None,  # tickmarker property
        color=None,  # global
        tickdir=None,  # tickmarker (not a property)
        pad=None,  # global
        labelsize=None,  # label property
        labelcolor=None,  # label property
        labelfontfamily=None,  # label property
        zorder=None,  # global
        gridOn=None,  # gridline (property: ~visible)
        tick1On=True,  # tick (property, but specific to each tick)
        tick2On=True,  # tick (property, but specific to each tick)
        label1On=True,  # label (property, but specific to each label)
        label2On=False,  # label (property, but specific to each label)
        major=True,  # global
        labelrotation=0,  # label property
        grid_color=None,  # grid property
        grid_linestyle=None,  # grid property
        grid_linewidth=None,  # grid property
        grid_alpha=None,  # grid property
        **kwargs,  # grid properties
    ):

The remaining kwargs are implicitly assumed to all start with "grid_" and further interpreted as grid properties (via grid_kw = {k[5:]: v for k, v in kwargs.items()}) -- note that this prefix is internally added by Axis.grid() to kwargs passed to it.

Proposed fix

We should at least check whether remaining kwargs indeed start with "grid_" and error out if that's not the case (Probably few people actually manually construct Ticks, but Tick(abcdecolor="k")) should certainly not be interpreted as Tick(grid_color="k") anyways.)

It may make sense to try to group the kwargs a bit more and not try to repeat all relevant properties in the Tick constructor, e.g. (not writing out the defaults)

def __init__(
    self, axes, loc, *,
    major, tickdir, pad, color, zorder,  # global
    tick_props, tick1On, tick2On,  # tick properties
    label_props, label1On, label2On,  # label properties
    grid_props,  # grid properties
):

(probably kwargs could be normalized in this form as soon as one populates Axis._major_tick_kw/_minor_tick_kw)

Inspired by #25910.

Activity

  1. changed the title [-][MNT]: Refactor kwargs of Tick constrctor[/-] [+][MNT]: Refactor kwargs of Tick constructor [/+] on May 30, 2023
  2. madeira-dev commented on May 30, 2023

    @madeira-dev
    Contributor

    Hi @anntzer, I read this issue and thought about a possible way to fix the first part of it, related to check if remaining kwargs are starting with "grid_".

    I thought about something like this:
    Screenshot from 2023-05-30 19-44-34

    Where right after defining grid_kw I would check for any other kwargs.

    Please let me know if this is an appropriate approach.

  3. anntzer commented on Jun 3, 2023

    @anntzer
    ContributorAuthor

    #26037 is a step in the right direction, although the "extra grouping" still needs to be considered.

  4. joooeey commented on Jun 5, 2023

    @joooeey

    The docs say xdata and ydata are allowed keyword arguments but using them raises errors when resizing or even just changing the tick format. Those can be useful, e.g. to extend a grid beyond the axes limits.

    A possible fix for this particular issue is outlined in the commit linked here.

  5. joooeey commented on Jun 5, 2023

    @joooeey

    The refactoring proposed here would also open the door for another enhancement that would allow passing more label props with set_tick_params such as the backgroundcolor which AFAIK can only be set on the individual labels right now.

  6. has2k1 commented on Aug 2, 2023

    @has2k1
    Contributor

    Axis.set_tick_params does too much and it keeps a record it uses to replay the previous settings along with any new settings. But because it is a high level method, its record gets stale when properties are changed on the artists (ticklines, labels & gridlines) directly.

    import matplotlib.pyplot as plt
    
    fig, ax = plt.subplots()
    ax.scatter([1, 2, 3], [1, 2, 3])
    
    # Make the xaxis ticklines red and thick
    for t in ax.xaxis.get_major_ticks():
        t.tick1line.set(markeredgecolor="red", markeredgewidth=5)
    
    # Make the xaxis ticklines longer
    ax.xaxis.set_tick_params(size=8)  # Undoes the markedgewidth!

    set_tick_params

  7. timhoffm commented on Aug 2, 2023

    @timhoffm
    Member

    Axis.set_tick_params does too much and it keeps a record it uses to replay the previous settings along with any new settings. But because it is a high level method, its record gets stale when properties are changed on the artists (ticklines, labels & gridlines) directly.

    I would phrase this differently: set_tick_params defines Axis-wide defaults for ticks. These are applied to all current Tick instances and used for future ticks (e.g. you may need new instances when you rescale). If you go on a lower level and change individual Ticks, you can create a discrepancy between the global default and the actual value. In general any further global operation may overwrite your low-level tick settings. We cannot give a universal guarantee to keep individual tick instances around or maintain their properties when further manipulating the figure. You should see individual tick operations as a last resort for fine-tuning.

    As for the specific case, changing markeredgewidth seems unnecessary. I have not looked into the details. It may be possible to fix that, but this way of working is fragile by design. I've created #26436 to document this better.

  8. has2k1 commented on Aug 4, 2023

    @has2k1
    Contributor

    As for the specific case, changing markeredgewidth seems unnecessary. I have not looked into the details. It may be possible to fix that, but this way of working is fragile by design.

    Yes it is fragile, but I have a theming system where I want access to more properties on the artists than set_tick_params allows. But I also use it because some properties e.g. tick direction are not conveniently composed to be set directly.

  9. timhoffm commented on Aug 4, 2023

    @timhoffm
    Member

    For your case, I suggest to do as much as possible via tick_params and only afterwards change individual ticks properties that cannot be configured otherwise. For example, your code above can do everything in tick_params:

    ax.xaxis.set_tick_params(color="red", width=5, size=8)
    

    Also, what are the parameters, you are missing in tick_params? We are fundamentally open to extend it.

  10. joooeey commented on Aug 16, 2023

    @joooeey

    I think tick_params should simply support all parameters accepted by labels, ticks, and gridlines. This is necessary because there is no alternative to achieve the same functionality for interactive plots. For parameters that can be passed to both labels and ticks, it should be possible to pass them individually (and perhaps also together as with the color kwarg).

    If this was a new method, I'd want an API with three separate methods or one where you can pass three dictionaries. But one has to work with the mess that is there. Perhaps phasing out set_tick_params() and replacing with format_ticklines(), format_ticklabels(), and format_grid() is an option.

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

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions