Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Unifying the Figure getter/setter interface to match its constructor #21549

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed

Conversation

stanleyjs
Copy link
Contributor

@stanleyjs stanleyjs commented Nov 5, 2021

PR Summary

Hi,
This is my first matplotlib PR. Should I base it in v3.5.x or base in main? This PR is based in main.

While building some convenience functions to automatically generate figures and/or update the parameters of passed figures, I noticed that figure.set(figsize=(w,h)) did not work, as there was no set_figsize function. I then noticed that subplotpars, figsize, and layout each lack getter/setter methods, and thus they cannot be set naively by calling .set(kwarg) or set_kwarg. This makes functions like the following difficult to write without having individual logic for every figure kwarg. It is better to have a standard interface of getters and setters.

def foo(fig=None,fig_kwargs):
    if fig is None:
        fig = plt.figure(**fig_kwargs)
    else:
         fig.set(**fig_kwargs)
    return fig 

Edit: This PR also refactors how tight_layout and constrained_layout are set. It places all of the logic inside a set_layout function, which handles passing layout as a string (eg layout = "tight"), as a bool (eg tight_layout=True), and passing in padding parameters (eg layout = "constrained", constrained_layout={"param":"val"})

PR Checklist

  • Has pytest style unit tests (and pytest passes).
  • Is Flake 8 compliant (run flake8 on changed files to check).
  • New features are documented, with examples if plot related.
  • Documentation is sphinx and numpydoc compliant (the docs should build without error).
  • Conforms to Matplotlib style conventions (install flake8-docstrings and run flake8 --docstring-convention=all).
  • New features have an entry in doc/users/next_whats_new/ (follow instructions in README.rst there).
  • API changes documented in doc/api/next_api_changes/ (follow instructions in README.rst there).

…nts. refactored layout setting. added ability to change subplotparams post hoc. added figsize getter/setter convenience function in order to match the constructor signature of figure. added tests.
Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for opening your first PR into Matplotlib!

If you have not heard from us in a while, please feel free to ping @matplotlib/developers or anyone who has commented on the PR. Most of our reviewers are volunteers and sometimes things fall through the cracks.

You can also join us on gitter for real-time discussion.

For details on testing, writing docs, and our review process, please see the developer guide

We strive to be a welcoming and open project. Please follow our Code of Conduct.

@@ -2684,6 +2888,60 @@ def get_size_inches(self):
"""
return np.array(self.bbox_inches.p1)

def set_figsize(self, w, h=None):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably just use cbook._define_aliases (see other uses in the library).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @anntzer. I made the requested change in the newest commit. Also updated the tests to match pep8.

@tacaswell tacaswell added this to the v3.6.0 milestone Nov 8, 2021
@jklymak
Copy link
Member

jklymak commented Nov 22, 2021

I'm not convinced by the motivation here. When do we want to pass a figure to a plotting method while at the same time wanting the user to be able to control layout parameters? It seems the only reason to pass a figure to a method is if we want to control the layout in our method. Can you justify this a little more?

Overall the new set_layout seems very long, and I'm not convinced we want to encourage set_layout after the figure is instantiated. In particular, colorbars need to know what layout is being used before they are created (for historical reasons, but they would be hard to remove at this point).

@tacaswell
Copy link
Member

I think the motivation here is reasonable. We already moved to a single layout kwarg (preferred over tight_layout and constrained_layout). Coupled with #20426 , I think providing a way for users to after-the-fact change the layout engine is an obvious feature (think of the case of using xarray / pandas to make most of a figure and then tweaking it up).


@stanleyjs You have taken on an ambitious project for your first PR, anything extending (let alone changing) the API tends to result in very verbose discussions (because a lot of our day-to-day pain in related to APIs that in in 20/20 hind sight were not the best). Please bear with us while we work through the process.

@jklymak
Copy link
Member

jklymak commented Nov 22, 2021

Yes but my point is that currently you cannot tweak it up after the fact if you have used a colorbar so an explicit setter will fail

@stanleyjs
Copy link
Contributor Author

Hi just wanted to bump this and see what the timeline is moving forward.

A few things.

  1. The primary motivation and concern of this PR was to increase uniformity in the API between the figure constructor and its actual setters/getters. In the current codebase, downstream figure instantiation / manipulation has to be done through special cases, as, for example, setting figsize post instantiation must be translated to set_size_inches. This is confusing.
  2. I'll admit that set_layout is a little bit long. It had four requirements:
    a) Accomodate all of the current API, which includes both modern layout and legacy tight_layout + constrained_layout.
    b) Abstract the current instantiation code into its own method
    c) Allow for subsequent modification of the layout parameters
    d) Raise the correct set of warnings for undefined behavior.
    As a result, the method suffers a bit and could be easily refined by removing support for the legacy attributes.
  3. At least in my applications, which may not be matplotlib parlance, I find myself often setting constrained or tight_layout before and after making colorbars and legends
  4. If set_layout is holding this PR up, I think we should at least push through the other new aliases.
  5. Is it worth looking into how to make colorbars in a way that works independent of the order that the layout is set? I can look into this for a separate PR.

@timhoffm
Copy link
Member

I will look into this from the API consistency point of view. But I'll take some time because I don't have much time for matplotlib currently. There are always tradeoffs between API improvements, compatibility with the existing API and redundant ways to do the same thing. Usually, you cannot have all.

@timhoffm timhoffm self-assigned this Dec 16, 2021
@jklymak
Copy link
Member

jklymak commented Dec 16, 2021

5. Is it worth looking into how to make colorbars in a way that works independent of the order that the layout is set? I can look into this for a separate PR.

I have looked into this extensively, and its certainly possible, but not in a back-compatible way.

Conversely you could use the current design, pull the colorbar out, hoist the parent axes to their original gridspec, and redo the layout (or vice versa), but that seems really brittle and not worth the bother.

I'm not convinced there is a great use case to toggle the two layout managers that would justify adding all the extra cruft needed to make this work, particularly given how poorly tight_layout works with colorbars in the first place. In my (very biased) opinion if you have colorbars you should be using constrained_layout because it was specifically designed to work around the issues with colorbars in tight_layout.

@jklymak
Copy link
Member

jklymak commented Feb 1, 2022

There have been substantive changes to figure.py that cover these layout methods. I'm still not convinced this re-arrangement is a substantial improvement, but others may have a different opinion. It has acquired the need for a rebase. I'll leave active for others to comment on. I think we were waiting for @timhoffm to weigh in.

@stanleyjs
Copy link
Contributor Author

@jklymak while I still believe that it doesn't make any sense for certain constructor arguments to not have a corresponding set_arg method, I think that is a separate thing from attempting to restructure the layout interface/construction. For that reason, I'm open to closing this, but I think a new, smaller PR would be reasonable to at least alias set_figsize to set_figsize_inches

@timhoffm
Copy link
Member

a new, smaller PR would be reasonable to at least alias set_figsize to set_figsize_inches.

We currently have

  • Figure(figsize=...)
  • Figure.get_figwidth()
  • Figure.get_figheight()

So, yes I agree that we should have set_figsize() and get_figsize(). @stanleyjs sorry for the delay in reviewing. Are you willing to open a PR for that?

@stanleyjs
Copy link
Contributor Author

@timhoffm yes. Sorry for the delay. I will try to get this on the list for this weekend.
Jay

@QuLogic QuLogic modified the milestones: v3.6.0, v3.7.0 Aug 24, 2022
@timhoffm
Copy link
Member

timhoffm commented Sep 8, 2022

@stanleyjs are you still interested in opening a PR?

@tacaswell
Copy link
Member

Thank you for your work on this @stanleyjs ! I created #24617 writing up the more limited version of this PR and am going to close this. Working code is a good articulation of requirements, but I opted to open a new issue in favor of closing this PR to make it more likely for someone else to pick up this work.

@Murad039
Copy link

Murad039 commented May 7, 2023

hmm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Development

Successfully merging this pull request may close these issues.

7 participants
Morty Proxy This is a proxified and sanitized view of the page, visit original site.