8000 `savefig` has sideeffects · Issue #6899 · matplotlib/matplotlib · GitHub
[go: up one dir, main page]

Skip to content

savefig has sideeffects #6899

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
Kojoley opened this issue Aug 3, 2016 · 4 comments
Closed

savefig has sideeffects #6899

Kojoley opened this issue Aug 3, 2016 · 4 comments
Milestone

Comments

@Kojoley
Copy link
Member
Kojoley commented Aug 3, 2016

In my investigation of image comparison fails with pytest and xdist plugin I have discovered strange behavior. By changing the extensions order of the image comparison tests you will receive different output (and of course test failures).

I made extensions shuffle like this and got these results. From the log you can see that mostly affected are legend tests on svg backend. So any baseline image from the tests with legend call is spoiled by pdf backend, except the legend + tightbox.

I tried to compare figure state before and after savefig call but run into issue #6870.

Here is the way to reproduce the problem. You can compare output of the snippet with baseline images of matplotlib.tests.test_legend.test_legend_auto1 test, if you want.

# python savefig_sideeffects.py svg svg pdf svg
# diff -u 0.svg 1.svg
# diff -u 1.svg 3.svg
# SOURCE_DATE_EPOCH=0 python savefig_sideeffects.py pdf pdf svg pdf

import numpy as np
import matplotlib
matplotlib.use('agg')
import matplotlib.pylab as plt


# matplotlib.testing.decorators.ImageComparisonTest.remove_text
def remove_text(figure):
    from matplotlib import ticker
    figure.suptitle("")
    for ax in figure.get_axes():
        ax.set_title("")
        ax.xaxis.set_major_formatter(ticker.NullFormatter())
        ax.xaxis.set_minor_formatter(ticker.NullFormatter())
        ax.yaxis.set_major_formatter(ticker.NullFormatter())
        ax.yaxis.set_minor_formatter(ticker.NullFormatter())
        try:
            ax.zaxis.set_major_formatter(ticker.NullFormatter())
            ax.zaxis.set_minor_formatter(ticker.NullFormatter())
        except AttributeError:
            pass


# matplotlib.tests.test_legend.test_legend_auto1
def test_legend_auto1():
    'Test automatic legend placement'
    fig = plt.figure()
    ax = fig.add_subplot(111)
    x = np.arange(100)
    ax.plot(x, 50 - x, 'o', label='y=1')
    ax.plot(x, x - 50, 'o', label='y=-1')
    ax.legend(loc=0)
    return fig


def prepare():
    import matplotlib.testing
    matplotlib._init_tests()

    # matplotlib.testing.decorators.ImageComparisonTest.setup_class
    matplotlib.testing.setup()
    matplotlib.style.use('classic')
    matplotlib.testing.set_font_settings_for_testing()

    fig = test_legend_auto1()

    remove_text(fig)

    return fig


def test(exts):
    fig = prepare()

    # this will stick svg path ids with the same values
    matplotlib.rc('svg', hashsalt='asdf')

    for p in enumerate(exts):
        fig.savefig('%d.%s' % p)


if __name__ == '__main__':
    import sys
    test(sys.argv[1:])

This is the demonstration of the issue, where savefig with pdf backend has sideeffect on the next savefig with svg backend:

>python savefig_sideeffects.py svg svg pdf svg

>diff -u 0.svg 1.svg

>diff -u 1.svg 3.svg
--- 1.svg       2016-08-04 00:29:52.429050200 +0300
+++ 3.svg       2016-08-04 00:29:52.537061000 +0300
@@ -462,18 +462,18 @@
    </g>
    <g id="legend_1">
     <g id="patch_7">
-     <path d="M 424.413 239.2965
-L 511.2 239.2965
-L 511.2 192.7035
-L 424.413 192.7035
+     <path d="M 424.469375 239.25225
+L 511.2 239.25225
+L 511.2 192.74775
+L 424.469375 192.74775
 z
 " style="fill:#ffffff;stroke:#000000;stroke-linejoin:miter;"/>
     </g>
     <g id="line2d_29"/>
     <g id="line2d_30">
      <g>
-      <use style="fill:#0000ff;stroke:#000000;stroke-width:0.5;" x="434.493" xlink:href="#mb9df33688a" y="204.36525"/>
-      <use style="fill:#0000ff;stroke:#000000;stroke-width:0.5;" x="454.653" xlink:href="#mb9df33688a" y="204.36525"/>
+      <use style="fill:#0000ff;stroke:#000000;stroke-width:0.5;" x="434.549375" xlink:href="#mb9df33688a" y="204.4095"/>
+      <use style="fill:#0000ff;stroke:#000000;stroke-width:0.5;" x="454.709375" xlink:href="#mb9df33688a" y="204.4095"/>
      </g>
     </g>
     <g id="text_1">
@@ -520,7 +520,7 @@
 z
 " id="DejaVuSans-31"/>
      </defs>
-     <g transform="translate(470.493 209.40525)scale(0.144 -0.144)">
+     <g transform="translate(470.549375 209.4495)scale(0.144 -0.144)">
       <use xlink:href="#DejaVuSans-79"/>
       <use x="59.179688" xlink:href="#DejaVuSans-3d"/>
       <use x="142.96875" xlink:href="#DejaVuSans-31"/>
@@ -529,8 +529,8 @@
     <g id="line2d_31"/>
     <g id="line2d_32">
      <g>
-      <use style="fill:#008000;stroke:#000000;stroke-width:0.5;" x="434.493" xlink:href="#m3d71661f95" y="225.50175"/>
-      <use style="fill:#008000;stroke:#000000;stroke-width:0.5;" x="454.653" xlink:href="#m3d71661f95" y="225.50175"/>
+      <use style="fill:#008000;stroke:#000000;stroke-width:0.5;" x="434.549375" xlink:href="#m3d71661f95" y="225.546"/>
+      <use style="fill:#008000;stroke:#000000;stroke-width:0.5;" x="454.709375" xlink:href="#m3d71661f95" y="225.546"/>
      </g>
     </g>
     <g id="text_2">
@@ -543,7 +543,7 @@
 z
 " id="DejaVuSans-2d"/>
      </defs>
-     <g transform="translate(470.493 230.54175)scale(0.144 -0.144)">
+     <g transform="translate(470.549375 230.586)scale(0.144 -0.144)">
       <use xlink:href="#DejaVuSans-79"/>
       <use x="59.179688" xlink:href="#DejaVuSans-3d"/>
       <use x="142.96875" xlink:href="#DejaVuSans-2d"/>

Same happens to pdf after svg.

By accident, while fixing issue #6870, it seems that I have fixed this too. Test above now passes but there are 505 SVG baseline images affected and need update. I will open PR for this soon.

@tacaswell
Copy link
Member

.... what?

Impressive work tracking this down.

@dopplershift
Copy link
Contributor

😱

@jrbrodie77
Copy link

I was just getting ready to create an issue with test cases. I'm seeing savefig side effects with 2.0.0b4

Is this fix in that version?

@Kojoley
Copy link
Member Author
Kojoley commented Sep 22, 2016

No, the issue is still open. It is a complex problem and I have not updated the ticket with my findings because fixing it reveals other bugs. In the current state it affects only automatic legend placement and the difference is about 0.3-0.5px, so it is not a major for the most of the user.
Currently I have only a workaround but it requires regeneration of ~700 baseline images what is a no-go until I fully understand the roots of the problem.

@QuLogic QuLogic modified the milestones: 2.0 (style change major release), 2.0.1 (next bug fix release) Dec 7, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants
0