-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Simplify logic for determining image comparison directories #5858
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
Simplify logic for determining image comparison directories #5858
Conversation
… it only creates one figure and plots the data twice into it.
On a mostly unrelated note, the |
I do not understand why that test image changed. It looks like the image comparison decorator is promoting the test to be test function to be a test class which probably explains why it does not look like a method hanging off of the parent test class for nose to find. |
Good point about about the test function being promoted to a class. I'll have a think whether this is easily fixable (but if so will submit it in a separate PR). The test image only changed ever so slightly, and the reason for this is because the test plotted the exact same data twice into the same figure. This resulted in slightly thicker lines surrounding the points than if the points had only been plotted once (not sure if this is a bug, but it's the way that matplotlib currently behaves). Below is an example of a "failed diff" image ( |
Btw, here is a standalone code snippet to reproduce the issue which resulted in the change of the test image: import matplotlib.pyplot as plt
xvals = [1, 2, 3, 4]
yvals = [1, 3, 2, 2.5]
fig, ax = plt.subplots()
ax.set_xlim(0, 5)
ax.set_ylim(0, 4)
ax.plot(xvals, yvals, 'o', color='blue')
fig.savefig('plot_1.png')
ax.plot(xvals, yvals, 'o', color='blue')
fig.savefig('plot_2.png') If you have
|
That makes perfect sense. Looks like another case where we were passing before due high tolerances and then re-generated slightly wrong images. |
The pdf probably changed too, but we just rasterize it at too low of a DPI to tell in the comparison tests, can you also include that one as well? Also, it amuses me that you can see the paths removed from the svg. |
I've added the PDF as well as you suggested. There is a Travis failure but it seems unrelated. Might be worth re-starting the Travis build to be sure? |
Looks like ipython blew up exiting from the doc build. Restarted, will merge when it passes. |
The IPython readonly thing is a known issue in Ipython and should be fixed in the next release ipython/ipython#8850 We are starting to see linkchecker complain about the link to _static/CHANGELOG recently but I am not really sure why |
@@ -200,7 +205,16 @@ def remove_text(figure): | |||
def test(self): | |||
baseline_dir, result_dir = _image_directories(self._func) | |||
|
|||
for fignum, baseline in zip(plt.get_fignums(), self._baseline_images): | |||
for fignum, baseline in zip_longest(plt.get_fignums(), self._baseline_images): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than using izip_longest
, couldn't you just check that the lengths of plt.get_fignums()
and self._baseline_images
are the same before the loop? That we we don't do a bunch of work only to fail later. (And if either of those is an iterator, they are certainly very short iterators so the cost of doing list()
on them should be negligible).
I understand the image changes here -- but I'm struggling to find why this PR made those changes. I know we are reusing the same image file name there, which has been the source of some race conditions / nondeterminacy in the past... Also, I agree that nothing in matplotlib is using nested subdirectories of tests, but are we sure third party tools that use the matplotlib testing infrastructure don't? |
Got it -- I understand why the test needed to be updated now (because there was a mismatch between the number of figures and the number of filenames listed). That aspect of this now makes sense to me. |
Restarted the Docs test on Travis which failed due to the IPython Traitlets issue fixed earlier in the week by IPython 4.0.3 |
@mdboom Many thanks for the comments, and apologies for the long silence. Currently being swamped with things so it will take a bit more time before I can tackle them. I agree with the inline comments you made and will re-work the PR to address them. Regarding the use of I'd also be interested in @pelson's comments, or anyone else's who needs the more flexible behaviour. (I checked the cartopy code and it doesn't use |
Hi @maxalbert. I've not really had much of a chance to look at the changes proposed here, but the original changes to the image comparison capability were indeed done to aid cartopy. Unfortunately, either the release was too slow, or it didn't quite fit the purpose (I can't remember which) which meant that cartopy has it own image testing capability based off of the image_comparison decorator (https://github.com/SciTools/cartopy/blob/master/lib/cartopy/tests/mpl/__init__.py#L32). This test class should be more widely applicable beyond cartopy, and could happily be pulled out into its own package if you're interested... Cheers, |
Thanks for the explanation @pelson! Do I understand correctly that cartopy re-implements the functionality rather than builds on top of matplotlib's It would be great to separate out cartopy's image comparison functionality into a separate package, but I personally won't have time to look into doing this in the next couple of months. I'll certainly keep it in mind for the longer term, though. |
ggplot also has it's own testing infrastructure based on mpl, but also only uses the default paths andthe only thing it imports from It also has a which is used like this:
It needs the setup per test file, but on the other hand the failing asserts point to the line number... |
Looks like this needs a big 'ol rebase. |
This can now be made as simple as
(now that we're using pytest, we can't directly run the test modules from outside of pytest anyways). |
I'm closing as likely obsolete. Feel free to re-open if more work will go into this! |
I took another look at the logic in
_image_directories
(because it still didn't work for my use case) and realised that pretty much nothing in there is used with the current test directory structure in matplotlib, but it imposes fairly arbitrary constraints which make re-using the@image_comparison
decorator in third-party projects very hard and fragile.The way the image comparison tests are laid out in matplotlib is that all the baseline images are contained in
lib/matplotlib/tests/baseline_images/
, and this folder contains a bunch of sub-directories corresponding to the individual test files inlib/matplotlib/tests/
. Most of the logic in_image_directories
tries to be clever about guessing the correct path to the baseline image in case the tests live in nested directory hierarchies, but this is not used at all.So I decided to remove all that logic, which makes the helper function much simpler and more explicit. The way it works now is as follows. If there is a test file called
/path/to/test_dir/test_script.py
then the baseline directory for the tests in this file will assumed to be/path/to/test_dir/baseline_images/test_script/
and the result directory will be/path/to/test_dir/result_images/test_script/
. This is exactly the way it currently works in matplotlib so no other changes were needed.I also added a couple of safety checks to make sure that the number of figures created in each test equals the number of baseline images provided. This actually exposed a minor bug in one of the tests which would draw twice into the same figure (rather than two different figures). This is now also fixed.