Created some prose documentation about best practices - #11657
WeatherGod wants to merge 1 commit into
Conversation
|
My thinking is that this "Best Practices" document should merely be a summary. Meanwhile, documents like the style guide should be much more detailed and in-depth. Also, the section for the function design might not make sense to be in a "style" guide now that we would have this best practices guide. |
| fig.clear() | ||
|
|
||
| Now, only one figure object is ever made, and it is cleaned of any plots | ||
| at each iteration, so the memory usage will not grow. |
There was a problem hiding this comment.
... or just call plt.close("all") at the end of the loop. This avoids having to factor out figure creation from the main loop.
There was a problem hiding this comment.
👍 for close. It's more clear and (currently) even faster.
%%timeit
fig = plt.figure()
for i in range(50):
plt.plot([1, 3, 2])
plt.savefig('test.png')
fig.clear()
3.12 s ± 53.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%%timeit
for i in range(50):
plt.figure()
plt.plot([1, 3, 2])
plt.savefig('test.png')
plt.close()
2.75 s ± 27.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
It's also a good general reminder, not only with looping: Close your pyplot figures when your done.
There was a problem hiding this comment.
What prompted me to make this document was when someone came to me with a script that was growing in memory significantly and they did something like this. I don't remember if they were calling plt.close() or not, but recycling the figure definitely solves that problem.
| Now you want to make this plot for each of your data files. One might just | ||
| put the above code into a for-loop over all of your filenames. However, you | ||
| will eventually encounter a warning ``More than X figures hae been opened.``. | ||
| With enough looping, Python can eventually run out of memory, and calling |
There was a problem hiding this comment.
Proposed rewording:
With enough looping, Python can eventually run out of memory because the
pyplotfigure manger keeps a reference to every created figure.
| fig.clear() | ||
|
|
||
| Now, only one figure object is ever made, and it is cleaned of any plots | ||
| at each iteration, so the memory usage will not grow. |
There was a problem hiding this comment.
👍 for close. It's more clear and (currently) even faster.
%%timeit
fig = plt.figure()
for i in range(50):
plt.plot([1, 3, 2])
plt.savefig('test.png')
fig.clear()
3.12 s ± 53.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%%timeit
for i in range(50):
plt.figure()
plt.plot([1, 3, 2])
plt.savefig('test.png')
plt.close()
2.75 s ± 27.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
It's also a good general reminder, not only with looping: Close your pyplot figures when your done.
| For nontrivial plots, it may make sense to create your own plotting | ||
| functions for easy reuse. Here are some guidelines: | ||
|
|
||
| * Have an ``ax`` positional argument as the first argument. |
There was a problem hiding this comment.
This pattern should be discussed.
IMO ax as the first positional argument is not a good choice. I would rather use something like:
def my_plotter(data1, data2, ax=None, param_dict=None):
if ax is None:
ax = plt.gca()
...
Usage patterns:
my_plotter(data1, data2) # similar to pyplot
my_plotter(data1, data2, ax=ax)
See also #9111
There was a problem hiding this comment.
This definitely should be discussed, because there is some discussion of a new interface that would have this pattern as the default for all plotting functions. ping @tacaswell @efiring

PR Summary
Add a "best practices" guide, and added a couple entries to it based on questions asked by attendees at SciPy.
PR Checklist