Skip to content

Add clf kwarg to plt.figure() #7023

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

Merged
merged 2 commits into from
Jan 29, 2017
Merged

Add clf kwarg to plt.figure() #7023

merged 2 commits into from
Jan 29, 2017

Conversation

DietBru
Copy link
Contributor

@DietBru DietBru commented Sep 4, 2016

Adds the keyword clf=False to plt.figure(). It clears the content of an already existing figure (being referenced by the num kwarg).

The original motivation is stated in #6285. Another view would be: Instead of writing
fg = plt.figure(num=10); fg.clf(), one can write fg = plt.figure(num=10, clf=True). The clf() is needed when the script is called repeatedly (with different parameters) in an interactive interpreter.

The discussion if this is api bloat or not can be continued here. From a user perspective, it changes

fg = plt.figure(num=10)
fg.clf()
fg, axx = plt.subplots(3, 3, num=10)

to

fg, axx = plt.subplots(3, 3, num=10, clf=True)

which is imho much more readable.
Closes #6285.

@@ -557,6 +564,9 @@ def make_active(event):
if _INSTALL_FIG_OBSERVER:
fig.stale_callback = _auto_draw_if_interactive

if clf and len(figManager.canvas.figure.axes) > 0:
figManager.canvas.figure.clear()
Copy link
Member

Choose a reason for hiding this comment

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

Without committing myself yet as to whether the PR as a whole is a good idea, I think that the clearing should be unconditional, not based on whether there are axes objects. Otherwise, it is only a partial clearing of the figure.

@tacaswell
Copy link
Member

I thought the suggestion was to put this flag on Figure.subplots.

@tacaswell tacaswell added this to the 2.1 (next point release) milestone Sep 4, 2016
@efiring
Copy link
Member

efiring commented Sep 4, 2016

There is a potentially reasonable justification for it only in subplots, but putting it in figure automatically puts it in subplots, and makes the two more consistent. It also keeps everything at the pyplot level only, which could be viewed as good (don't make the library level more complicated) or bad (better to keep the pyplot level as consistent with the library level as possible).
I don't think it belongs at the library level because to me, Figure.subplots should be making a fresh array of subplots, period. Similarly, Figure.add_subplot should add a subplot, not return an existing one. Adding this 'clear' kwarg at the Figure level would make it more awkward to deprecate and remove the peculiar part of the add_subplot behavior.

@anntzer
Copy link
Contributor

anntzer commented Sep 7, 2016

Note that as of 2.1 you can already write

fig = plt.figure(...); fig.clf()
axs = fig.subplots(...)

Actually, thinking about it again, it's not even clear why you'd want to reuse a figure. Can't you just close whatever figure you don't care about and create a new one?
Plus, I'd say getting figures by their num is so MATLAB-ish; you could just keep a reference to the figure itself.
Anyways, still -1.

@efiring
Copy link
Member

efiring commented Sep 7, 2016

On 2016/09/06 7:06 PM, Antony Lee wrote:

Actually, thinking about it again, it's not even clear why you'd want to
reuse a figure. Can't you just close whatever figure you don't care
about and create a new one?

No, that's not at all the point. Suppose you want to cycle through
plots of a given type. You make a figure, and position and resize it on
the screen. You want to be able to leave it there while running your
script--you don't want a new one flashing up each time.

@efiring
Copy link
Member

efiring commented Sep 7, 2016

On 2016/09/06 7:06 PM, Antony Lee wrote:

Plus, I'd say getting figures by their |num| is so MATLAB-ish; you could
just keep a reference to the figure itself.

Yes, but with mpl one can also use a name in place of the number; and
the point of the pyplot interface is to make it easy for people to
transition from Matlab, and to do a quick style of interactive
computing. (I agree in preferring the approach of keeping a reference
to the figure and then calling its subplots method; maybe the addition
of that method does tip the balance away from adding the clean kwarg.)

@anntzer
Copy link
Contributor

anntzer commented Sep 7, 2016

No, that's not at all the point. Suppose you want to cycle through
plots of a given type. You make a figure, and position and resize it on
the screen. You want to be able to leave it there while running your
script--you don't want a new one flashing up each time.

Good point, didn't think about this use.

@tacaswell
Copy link
Member

I actually use the plt.figure('some name') at my day-job as part of beamline control system to manage over plotting in a reasonable way. Sometimes global state is the right answer (as painful as it is for me to type that 😜 ) and it is handy that mpl takes care of some of that state management for you.

@@ -429,6 +429,7 @@ def figure(num=None, # autoincrement if None, else integer from 1-N
facecolor=None, # defaults to rc figure.facecolor
edgecolor=None, # defaults to rc figure.edgecolor
frameon=True,
clear=False,
Copy link
Member

Choose a reason for hiding this comment

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

This needs to be the last arg to maintain back compatibility.

@@ -557,6 +564,9 @@ def make_active(event):
if _INSTALL_FIG_OBSERVER:
fig.stale_callback = _auto_draw_if_interactive

if clear:
figManager.canvas.figure.clear()
Copy link
Member

Choose a reason for hiding this comment

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

🚲 🏠 fig is a ref to the current figure that we already have just above.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The fig ref only exists if in Line 520 if figManager is None.

Copy link
Member

Choose a reason for hiding this comment

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

🐑

Copy link
Contributor Author

Choose a reason for hiding this comment

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

😄

@tacaswell
Copy link
Member

I am mostly convinced by @efiring that this should stay in pyplot and not be moved back into the object layer.

@vollbier Can you please add a 'whats_new' entry with examples of both plt.figure and plt.subplots?

@codecov-io
Copy link

codecov-io commented Dec 26, 2016

Current coverage is 62.07% (diff: 100%)

Merging #7023 into master will increase coverage by <.01%

@@             master      #7023   diff @@
==========================================
  Files           174        174          
  Lines         56021      56023     +2   
  Methods           0          0          
  Messages          0          0          
  Branches          0          0          
==========================================
+ Hits          34773      34776     +3   
+ Misses        21248      21247     -1   
  Partials          0          0          

Powered by Codecov. Last update ab98852...e249ac3

@tacaswell
Copy link
Member

Can you rebase this to and squash it to 1 or 2 commits? See http://matplotlib.org/devdocs/devel/gitwash/development_workflow.html#rebasing-a-pull-request-pr

This needs a minimal test, using @cleanup and the examples in the whats-new would be perfect (and is an obvious candidate for a pytest paramterized test.

@tacaswell tacaswell dismissed their stale review December 27, 2016 02:49

docs were added


import matplotlib.pyplot as plt

fg0 = plt.figure(num=1);
Copy link
Member

Choose a reason for hiding this comment

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

We use fig, generally.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Of course - thanks for the comments.


When the pyplot's function :func:`~matplotlib.pyplot.figure` is called
with a ``num`` parameter, a new window is only created if no existing
window with the same number exists. A new bool parameter `clear` was
Copy link
Member

Choose a reason for hiding this comment

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

number -> value

because it can be an arbitrary string.

print("fg0 is fg1: ", fg0 is fg1)
print("fg1.texts: ", [t.get_text() for t in fg1.texts])

fg2, axx = plt.subplots(2, 1, num=1, clear=True) # clear contents
Copy link
Member

Choose a reason for hiding this comment

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

ax

import matplotlib.pyplot as plt

fg0 = plt.figure(num=1);
fg0.suptitle("A fancy plot");
Copy link
Member

Choose a reason for hiding this comment

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

You can drop the semicolons as they do nothing.

# fg0 is fg2: True
# fg2.texts: []


Copy link
Member

Choose a reason for hiding this comment

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

Trim empty lines.

If False, suppress drawing the figure frame

FigureClass : class derived from matplotlib.figure.Figure
This parameter allows to optionally use a custom Figure instance.
Copy link
Member

Choose a reason for hiding this comment

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

Everything up to (and including) 'to' is kind of redundant.

@@ -462,6 +463,15 @@ def figure(num=None, # autoincrement if None, else integer from 1-N
edgecolor :
the border color. If not provided, defaults to rc figure.edgecolor

frameon : bool, optional, default: True
If False, suppress drawing the figure frame
Copy link
Member

Choose a reason for hiding this comment

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

Missing trailing period.

@tacaswell
Copy link
Member

You need to force push the rebased branch, not merge the remote branch into your local branch.

@DietBru
Copy link
Contributor Author

DietBru commented Dec 27, 2016

I hope it's correct now - github and me are not best friends yet ...

@tacaswell
Copy link
Member

Looks good 😄 👍

@@ -51,6 +51,24 @@ def test_fignum_exists():
assert_equal(plt.fignum_exists(4), False)


@cleanup
def test_clf_keyword():
# test if existing figure is cleared with figure() and subplots()
Copy link
Member

Choose a reason for hiding this comment

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

4-space indents, please.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

🐑

@NelleV NelleV merged commit 5737ce4 into matplotlib:master Jan 29, 2017
@NelleV
Copy link
Member

NelleV commented Jan 29, 2017

Thanks @vollbier for this patch! Sorry it took so long to be merged. Your PR suffered from the "it doesn't appear of the first page of reviews" effect :(

@DietBru
Copy link
Contributor Author

DietBru commented Jan 29, 2017

@NelleV I guess there's still a bit of time until the 2.1 release left - so I don't see a problem.

@DietBru DietBru deleted the figure_clf_kwarg branch January 29, 2017 22:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants