From 309c93c2e71a7ef8d70deaf1f4d0c6adc77a0472 Mon Sep 17 00:00:00 2001 From: Michael Welter Date: Sun, 26 Aug 2012 10:10:46 +0200 Subject: [PATCH 1/8] fixed: compare_images for older numpy versions. added: backend_pdf allows numpy.float32 in pdfRepr --- lib/matplotlib/backends/backend_pdf.py | 2 +- lib/matplotlib/testing/compare.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/matplotlib/backends/backend_pdf.py b/lib/matplotlib/backends/backend_pdf.py index 4cd830829eff..7acaddd3b874 100644 --- a/lib/matplotlib/backends/backend_pdf.py +++ b/lib/matplotlib/backends/backend_pdf.py @@ -139,7 +139,7 @@ def pdfRepr(obj): # Floats. PDF does not have exponential notation (1.0e-10) so we # need to use %f with some precision. Perhaps the precision # should adapt to the magnitude of the number? - elif isinstance(obj, float): + elif isinstance(obj, (float, np.float32)): if not np.isfinite(obj): raise ValueError("Can only output finite numbers in PDF") r = ("%.10f" % obj).encode('ascii') diff --git a/lib/matplotlib/testing/compare.py b/lib/matplotlib/testing/compare.py index abd4f4f7a953..8563147a9c46 100644 --- a/lib/matplotlib/testing/compare.py +++ b/lib/matplotlib/testing/compare.py @@ -308,8 +308,8 @@ def compare_images( expected, actual, tol, in_decorator=False ): h1p = expectedImage[:,:,i] h2p = actualImage[:,:,i] - h1h = np.histogram(h1p, bins=bins)[0] - h2h = np.histogram(h2p, bins=bins)[0] + h1h = np.histogram(h1p, bins=ns)[0] + h2h = np.histogram(h2p, bins=ns)[0] rms += np.sum(np.power((h1h-h2h), 2)) From cb1aa376c8aa0e7d977174b53fd72b7fd6badfb5 Mon Sep 17 00:00:00 2001 From: Michael Welter Date: Sun, 26 Aug 2012 17:18:08 +0200 Subject: [PATCH 2/8] fix: dpi setting should work now for rasterization in svg backend --- lib/matplotlib/backends/backend_svg.py | 33 ++++++++++++++++---------- lib/matplotlib/tests/test_image.py | 27 +++++++++++++++++++++ 2 files changed, 48 insertions(+), 12 deletions(-) diff --git a/lib/matplotlib/backends/backend_svg.py b/lib/matplotlib/backends/backend_svg.py index 0b9b7ab51701..f1c709c8a164 100644 --- a/lib/matplotlib/backends/backend_svg.py +++ b/lib/matplotlib/backends/backend_svg.py @@ -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): 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']: @@ -733,6 +734,11 @@ def draw_gouraud_triangles(self, gc, triangles_array, colors_array, def option_scale_image(self): return True + + 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): attrib = {} clipid = self._get_clip(gc) @@ -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: @@ -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) 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) 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) diff --git a/lib/matplotlib/tests/test_image.py b/lib/matplotlib/tests/test_image.py index 4556013bc4cb..d11a0c94ad8f 100644 --- a/lib/matplotlib/tests/test_image.py +++ b/lib/matplotlib/tests/test_image.py @@ -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) +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 + # 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 + + + if __name__=='__main__': import nose nose.runmodule(argv=['-s','--with-doctest'], exit=False) From 868f4114806bc9d3b4de2a0cd9b8399d6a036337 Mon Sep 17 00:00:00 2001 From: Michael Welter Date: Wed, 3 Oct 2012 18:26:56 +0200 Subject: [PATCH 3/8] update for my patch --- lib/matplotlib/backends/backend_svg.py | 31 ++++++++++++++++---------- lib/matplotlib/tests/test_image.py | 27 ++++++++++++++++++++++ 2 files changed, 46 insertions(+), 12 deletions(-) diff --git a/lib/matplotlib/backends/backend_svg.py b/lib/matplotlib/backends/backend_svg.py index 0b9b7ab51701..2024b56b8e55 100644 --- a/lib/matplotlib/backends/backend_svg.py +++ b/lib/matplotlib/backends/backend_svg.py @@ -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): 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']: @@ -733,6 +734,9 @@ def draw_gouraud_triangles(self, gc, triangles_array, colors_array, def option_scale_image(self): return True + 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): attrib = {} clipid = self._get_clip(gc) @@ -755,6 +759,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: @@ -1113,25 +1128,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) 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) 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) diff --git a/lib/matplotlib/tests/test_image.py b/lib/matplotlib/tests/test_image.py index 4556013bc4cb..d11a0c94ad8f 100644 --- a/lib/matplotlib/tests/test_image.py +++ b/lib/matplotlib/tests/test_image.py @@ -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) +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 + # 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 + + + if __name__=='__main__': import nose nose.runmodule(argv=['-s','--with-doctest'], exit=False) From 98ab64e0085e10b1e3770340106742413fdfde38 Mon Sep 17 00:00:00 2001 From: Michael Welter Date: Wed, 3 Oct 2012 19:15:48 +0200 Subject: [PATCH 4/8] update for my patch --- lib/matplotlib/tests/test_image.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/matplotlib/tests/test_image.py b/lib/matplotlib/tests/test_image.py index d11a0c94ad8f..7c0d7fd19e19 100644 --- a/lib/matplotlib/tests/test_image.py +++ b/lib/matplotlib/tests/test_image.py @@ -160,13 +160,12 @@ 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) 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 + # Instead of high-res rasterization i use low-res. Therefore the fact that the # resolution is non-standard is is easily checked by image_comparison. import numpy as np import matplotlib.pyplot as plt From f56a45567039b9587a39022936596a267282ef59 Mon Sep 17 00:00:00 2001 From: Michael Welter Date: Sat, 4 May 2013 11:21:16 +0200 Subject: [PATCH 5/8] api change --- lib/matplotlib/backends/backend_svg.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/matplotlib/backends/backend_svg.py b/lib/matplotlib/backends/backend_svg.py index 2024b56b8e55..ddddcbd1299b 100644 --- a/lib/matplotlib/backends/backend_svg.py +++ b/lib/matplotlib/backends/backend_svg.py @@ -244,7 +244,7 @@ class RendererSVG(RendererBase): FONT_SCALE = 100.0 fontd = maxdict(50) - def __init__(self, width, height, image_dpi, svgwriter, basename=None): + def __init__(self, width, height, svgwriter, basename=None, image_dpi=72): self.width = width self.height = height self.writer = XMLWriter(svgwriter) @@ -1134,11 +1134,11 @@ def _print_svg(self, filename, svgwriter, fh_to_close=None, **kwargs): w, h = width*72, height*72 if rcParams['svg.image_noscale']: - renderer = RendererSVG(w, h, image_dpi, svgwriter, filename) + renderer = RendererSVG(w, h, svgwriter, filename, image_dpi) else: _bbox_inches_restore = kwargs.pop("bbox_inches_restore", None) renderer = MixedModeRenderer(self.figure, - width, height, image_dpi, RendererSVG(w, h, image_dpi, svgwriter, filename), + width, height, image_dpi, RendererSVG(w, h, svgwriter, filename, image_dpi), bbox_inches_restore=_bbox_inches_restore) self.figure.draw(renderer) From c610462cc45af3de3d2a7cd0fdcb098e343cc47f Mon Sep 17 00:00:00 2001 From: Michael Welter Date: Fri, 17 May 2013 10:04:41 +0200 Subject: [PATCH 6/8] added test result images --- .../test_image/rasterize_10dpi.pdf | Bin 0 -> 3157 bytes .../test_image/rasterize_10dpi.svg | 598 ++++++++++++++++++ 2 files changed, 598 insertions(+) create mode 100644 lib/matplotlib/tests/baseline_images/test_image/rasterize_10dpi.pdf create mode 100644 lib/matplotlib/tests/baseline_images/test_image/rasterize_10dpi.svg diff --git a/lib/matplotlib/tests/baseline_images/test_image/rasterize_10dpi.pdf b/lib/matplotlib/tests/baseline_images/test_image/rasterize_10dpi.pdf new file mode 100644 index 0000000000000000000000000000000000000000..3904df03ad42b7f76b0fcbcedffea97da76d7682 GIT binary patch literal 3157 zcmb7`dsq`!8i#{)ml9~LSYcHvM`#4RWHL!e0C`X$1Od5}fPw-Nl7R$6CMLsG3qHEG zwnA&6utgCC=?cijS`ksuR>dysqR5J%2*~3u1z|zU0tM0RnS=lmwwL@fnQzW~^WDyS zezX7{e;rC^Q)y+7z?n-_6fgiD6-#w-0Z34?0t1M3L z#pFWASuce6N5x_y0&q2J;0pwSDdoU{yrm)mN?ats2(SaX;_;z-EQtV!R~&TfHg$EM zx_W_dfOsSko&rKhV1TW4Adm>fQh5yEXx;O1IRRLj|1;sB3~10L;Hkvp6@W~|T>uas zmLL^jfu8VV@GeLxl&cg%B_r&OOcXcImg%1dAvQ)$u6HA3|coGbqbk9UNfXgI9 z48&A;yix?qLY5&==ZCBm{3eVKI#B^9&9j*p$$MRhe5nl92q1hJOq7R-a4~#y3nq^t zBmgCwp{ccsP-4P3YEoWyj<5U?!}Q>o>p{Ph-sj$LZ!g@~G}yd0WnbY2yH)nhz7;#Y zt!Y{Jwq$0T(Z4B1Wn0HOD~oue zDg;XqG*z!ih+kh3EcqaqUQ2%~Ie3q4+Sa1#;?;P>Upi|`>xN@L-{%(4Sy)<|9G)^< zI(o$+H&&j_t@OboS~|08Lh39>Tf?u7tiE*P<=&rL4*ERwpm)<#94?mC6m*v+SN&~e zo6(xuZZm-ODIrG>$vv(xi*l-<98l*_44RuA z&$D}+T-ukkKIXR@_$Gio-4>FCx4!_+5ARrTZz#(}HR&NM&F)_oSC@O5y*d;&5LsXo zTKe8w#@T&MiEgUhCu{s91qsAv^OyI}n;kuD*ck6-Qgv#CQc|+4w;{4*@Uwj1o83hT zqQwyz7YZjH`L)~czE&S?FxZi2c`oDAuzKUA$No^0s8afhZr8KT?>)5ps;%LZMK}5A z8OMUCZy%4!{rsd#S#aKwZ$gjk8T;?^AI0gV{aHP>-*Yn4o-+Kef6Vnw#Zz~UMo5oi zm75b6+CH`qwhpzt%l96cSgP7VoM@g5z5n;vSI!Y#wa<^cu+xmLc5SONUe^CKeeq9> z50{@9%0FzwUv+F-hfP7`KFce9MF*O~EF~3-w->(`{DZFZ~ix_h4u4)agDZWK)xb8;H})kg|1C`N-8J=rg9L~YvJN6(h* z=f}C;%wwOc&73G(zo%k%ppW==!9c~A_XCy|sTO>V#H5$4_IEIBSgh{M}I6;5{Ovc}-tp6_#_Lsdm!nt2?oulK7h1RZ}3->^2S2 z*eo5~NV-hz)S2x|(n!xpGEUD(f=bUw!g0!oc%cB*0u}LM0#pxXvp$7vlZqh|xFlC( zxKf}HiXbVpO!HI4?k&6)GZ#k0LZc*ARCGG8#JT$fYAV;wB|j0hrPq zk5k}s5`~T=^QSo^irlzB2HZ})SYnts*{xQqS$p3wQ>USnPtF{)rd;ZK$8??o>uSW} z=<2JeNUrJYla9y_4`LczC|3BGIogLbvZ7N&puVwo}eZub9uq}0L zVnj`&sXaV44In#TAtBGYZuV?2GbEu;rtU(aaJF(A=1D|%_MaeDv8loGKW#@C0~6mV{=MPN?svGX%?8#sAG;lI zqqjVzDOqFQ$OdEHh{xL-gSPg5kz=(e|5#tXKzgEs!ux@Hi*mQZ<0q5lEzV}d@PD>s zj;!6+s}}qbq@?9_@3p!<5%5v!(nBAbUc6yYtlaeDJmu5r02Jlw24Qyj-0^t0?@)mF zK(s;Wp^-L$r0md6uU3!EaEUov`nW^EKuB>pkJL|gJZB~YWugoQ3w2^SvAJs)Oj`!S z)?OpZ#PK4iKnAF3Z8ldT^M(_ywhLMfEWFr`NSd-pqVPDYy)we97c`G6-ZMs Y*ih|>AXE~X7Be{xj#L`W!=F$6AJPz4s{jB1 literal 0 HcmV?d00001 diff --git a/lib/matplotlib/tests/baseline_images/test_image/rasterize_10dpi.svg b/lib/matplotlib/tests/baseline_images/test_image/rasterize_10dpi.svg new file mode 100644 index 000000000000..38027d48922d --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_image/rasterize_10dpi.svg @@ -0,0 +1,598 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From dc0a8197c4103b35ca44009fabc0feca6a1e2280 Mon Sep 17 00:00:00 2001 From: Michael Welter Date: Fri, 17 May 2013 10:46:19 +0200 Subject: [PATCH 7/8] added note to whats_new.rst --- doc/users/whats_new.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/users/whats_new.rst b/doc/users/whats_new.rst index a6fce09ef9ff..126a776746c5 100644 --- a/doc/users/whats_new.rst +++ b/doc/users/whats_new.rst @@ -841,3 +841,7 @@ Here are the 0.98.4 notes from the CHANGELOG:: off automatically when infs or NaNs are present. Also masked arrays are now converted to arrays with NaNs for consistent handling of masks and NaNs - MGD and EF + + Added support for arbitrary rasterization resolutions to the SVG + backend. - MW + \ No newline at end of file From d6f49317539b7ace8dc558da25aac0da3799ec30 Mon Sep 17 00:00:00 2001 From: Michael Welter Date: Fri, 17 May 2013 11:17:56 +0200 Subject: [PATCH 8/8] added a note to changelog --- CHANGELOG | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index c4155dd34267..4e4782c14671 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,11 @@ +2013-05-18 Added support for arbitrary rasterization resolutions to the + SVG backend. Previously the resolution was hard coded to 72 + dpi. Now the backend class takes a image_dpi argument for + its constructor, adjusts the image bounding box accordingly + and forwards a magnification factor to the image renderer. + The code and results now resemble those of the PDF backend. + - MW + 2012-08-11 Fix path-closing bug in patches.Polygon, so that regardless of whether the path is the initial one or was subsequently set by set_xy(), get_xy() will return a closed path if and