Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Svg rasterize resolution fix #1185

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
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
fix: dpi setting should work now for rasterization in svg backend
  • Loading branch information
Michael Welter committed Aug 26, 2012
commit cb1aa376c8aa0e7d977174b53fd72b7fd6badfb5
33 changes: 21 additions & 12 deletions lib/matplotlib/backends/backend_svg.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,10 +244,11 @@ class RendererSVG(RendererBase):
FONT_SCALE = 100.0
fontd = maxdict(50)

def __init__(self, width, height, svgwriter, basename=None):
def __init__(self, width, height, image_dpi, svgwriter, basename=None):
Copy link
Member

Choose a reason for hiding this comment

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

Just noticed this. This changes the API of this class. Backends are used by other projects and are not considered to be internal-only, IMO. It would be better to put image_dpi at the end of the call signature with a None (or whatever default value that makes sense).

Copy link
Member

Choose a reason for hiding this comment

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

This API change still needs to be addressed.

self.width = width
self.height = height
self.writer = XMLWriter(svgwriter)
self.image_dpi = image_dpi # the actual dpi we want to rasterize stuff with

self._groupd = {}
if not rcParams['svg.image_inline']:
Expand Down Expand Up @@ -733,6 +734,11 @@ def draw_gouraud_triangles(self, gc, triangles_array, colors_array,
def option_scale_image(self):
return True

Copy link
Member

Choose a reason for hiding this comment

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

Nitpick: Only need a single new line between methods.

Copy link
Author

Choose a reason for hiding this comment

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

ok


def get_image_magnification(self):
return self.image_dpi/72.0


def draw_image(self, gc, x, y, im, dx=None, dy=None, transform=None):
Copy link
Member

Choose a reason for hiding this comment

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

@mwelter - I don't know how much you've invested in checking out the details of this signature but it is worth noting that all backends have it, except for the backend_bases.py superclass. Would you be willing to submit a PR which adds the necessary signature updates to backend_bases.py along with the necessary keyword documentation?

I promise that PR wont take 8 months to merge 😉

Copy link
Author

Choose a reason for hiding this comment

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

Nah, sorry. I happly contribute what i have done. But at the moment i am not willing to look into more stuff.

attrib = {}
clipid = self._get_clip(gc)
Expand All @@ -755,6 +761,17 @@ def draw_image(self, gc, x, y, im, dx=None, dy=None, transform=None):
im.resize(numcols, numrows)

h,w = im.get_size_out()

if dx is None:
w = 72.0*w/self.image_dpi
else:
w = dx

if dy is None:
h = 72.0*h/self.image_dpi
else:
h = dy

oid = getattr(im, '_gid', None)
url = getattr(im, '_url', None)
if url is not None:
Expand Down Expand Up @@ -1113,25 +1130,17 @@ def print_svgz(self, filename, *args, **kwargs):

def _print_svg(self, filename, svgwriter, fh_to_close=None, **kwargs):
try:
image_dpi = kwargs.pop("dpi", 72)
Copy link
Member

Choose a reason for hiding this comment

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

What's the difference between this image_dpi and self.image_dpi?

Copy link
Author

Choose a reason for hiding this comment

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

This code is in a different class. From here image_dpi gets passed to the backends constructor.

self.figure.set_dpi(72.0)
width, height = self.figure.get_size_inches()
w, h = width*72, height*72

if rcParams['svg.image_noscale']:
renderer = RendererSVG(w, h, svgwriter, filename)
renderer = RendererSVG(w, h, image_dpi, svgwriter, filename)
Copy link
Member

Choose a reason for hiding this comment

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

API change needs to be fixed here

else:
# setting mixed renderer dpi other than 72 results in
# incorrect size of the rasterized image. It seems that the
# svg internally uses fixed dpi of 72 and seems to cause
# the problem. I hope someone who knows the svg backends
# take a look at this problem. Meanwhile, the dpi
# parameter is ignored and image_dpi is fixed at 72. - JJL

#image_dpi = kwargs.pop("dpi", 72)
image_dpi = 72
_bbox_inches_restore = kwargs.pop("bbox_inches_restore", None)
renderer = MixedModeRenderer(self.figure,
width, height, image_dpi, RendererSVG(w, h, svgwriter, filename),
width, height, image_dpi, RendererSVG(w, h, image_dpi, svgwriter, filename),
bbox_inches_restore=_bbox_inches_restore)

self.figure.draw(renderer)
Expand Down
27 changes: 27 additions & 0 deletions lib/matplotlib/tests/test_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,33 @@ def test_no_interpolation_origin():
ax = fig.add_subplot(212)
ax.imshow(np.arange(100).reshape((2, 50)), interpolation='none')


@image_comparison(baseline_images=['rasterize_10dpi'], extensions=['pdf','svg'], tol=1.5e-3, remove_text=True)
Copy link
Member

Choose a reason for hiding this comment

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

Line width is probably longer than 80 chars. Please wrap the line.

def test_rasterize_dpi():
# This test should check rasterized rendering with high output resolution.
# It plots a rasterized line and a normal image with implot. So it will catch
# when images end up in the wrong place in case of non-standard dpi setting.
# Instead of high-res rasterization i use low-res. Therefor the fact that the
Copy link
Member

Choose a reason for hiding this comment

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

Typo. Therefor -> Therefore. (if your interested, therefor is a proper word, but would not be correct in this case: http://walkinthewords.blogspot.co.uk/2009/04/therefor-vs-therefore.html)

# resolution is non-standard is is easily checked by image_comparison.
import numpy as np
import matplotlib.pyplot as plt

img = np.asarray([[1, 2], [3, 4]])

fig, axes = plt.subplots(1, 3, figsize = (3, 1))

axes[0].imshow(img)

axes[1].plot([0,1],[0,1], linewidth=20., rasterized=True)
axes[1].set(xlim = (0,1), ylim = (-1, 2))

axes[2].plot([0,1],[0,1], linewidth=20.)
axes[2].set(xlim = (0,1), ylim = (-1, 2))

rcParams['savefig.dpi'] = 10
Copy link
Member

Choose a reason for hiding this comment

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

Unless I am mistaken, this is going to have a side effect on subsequent tests. Perhaps the image comparison decorator should accept a dictionary of overwriting rc params...

Copy link
Author

Choose a reason for hiding this comment

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

Oddly enough it actually doesn't show any side effects. It would surely show in the images. Some good old debugging through print statements also shows that apparently changes to rcParams don't carry over to the next test.
Correct me if i am wrong though. My guess is that the testing framework reloads everything from scratch for each test.

Copy link
Author

Choose a reason for hiding this comment

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

p.s. we already have

@image_comparison(baseline_images=['interp_nearest_vs_none'],
                  extensions=['pdf', 'svg'], remove_text=True)
def test_interp_nearest_vs_none():
    'Test the effect of "nearest" and "none" interpolation'
    # Setting dpi to something really small makes the difference very
    # visible. This works fine with pdf, since the dpi setting doesn't
    # affect anything but images, but the agg output becomes unusably
    # small.
    rcParams['savefig.dpi'] = 3
    X = np.array([[[218, 165, 32], [122, 103, 238]],
                  [[127, 255, 0], [255, 99, 71]]], dtype=np.uint8)
    fig = plt.figure()
    ax1 = fig.add_subplot(121)
    ax1.imshow(X, interpolation='none')
    ax1.set_title('interpolation none')
    ax2 = fig.add_subplot(122)
    ax2.imshow(X, interpolation='nearest')
    ax2.set_title('interpolation nearest')

So, hopefully everything is alright.

Copy link
Member

Choose a reason for hiding this comment

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

Thanks @mwelter - I was mistaken 😄




if __name__=='__main__':
import nose
nose.runmodule(argv=['-s','--with-doctest'], exit=False)