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

Skip to content

Commit 3a9a738

Browse files
committed
Added the rcParams 'pdf.combine_images', 'svg.combine_images', and
'ps.combine_images' to permit users to decide whether they want the vector graphics backend to combine all images within a set of axes into a single image. (If images do not get combined, users can open vector graphics files in Adobe Illustrator or Inkscape and edit each image individually.) Also changed 'renderer.option_nocomposite' to the clearer name 'renderer.option_combine_images'. Improved combine image tests to actually count the number of images in the vector graphics files. Also replaced the rcParams 'pdf.combine_images', 'svg.combine_images', and 'ps.combine_images' with 'vector_backends.combine_images' Corrected PEP8 coding standard violations Updated 'combine_images' tests for PS and SVG backends to hopefully make them Python 3 compatible. Fixed some PEP8 violations to leave the code cleaner than I found it. Fixed PEP8 violations introduced in my effort to fix PEP8 violations in my last commit. Changed the rcParam option name from 'vector_graphics.combine_images' to 'image.combine_images', and updated the matplotlibrc.template. Update the backend tests with the new rcParam name 'image.combine_images' Added the rcParams 'pdf.combine_images', 'svg.combine_images', and 'ps.combine_images' to permit users to decide whether they want the vector graphics backend to combine all images within a set of axes into a single image. (If images do not get combined, users can open vector graphics files in Adobe Illustrator or Inkscape and edit each image individually.) Also changed 'renderer.option_nocomposite' to the clearer name 'renderer.option_combine_images'. Improved combine image tests to actually count the number of images in the vector graphics files. Also replaced the rcParams 'pdf.combine_images', 'svg.combine_images', and 'ps.combine_images' with 'vector_backends.combine_images' Corrected PEP8 coding standard violations Updated 'combine_images' tests for PS and SVG backends to hopefully make them Python 3 compatible. Fixed some PEP8 violations to leave the code cleaner than I found it. Fixed PEP8 violations introduced in my effort to fix PEP8 violations in my last commit. Changed the rcParam option name from 'vector_graphics.combine_images' to 'image.combine_images', and updated the matplotlibrc.template. Update the backend tests with the new rcParam name 'image.combine_images'
1 parent 13a8f31 commit 3a9a738

22 files changed

+153
-51
lines changed

CHANGELOG

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22
corner masking. This is controlled by the 'corner_mask' keyword
33
in plotting commands 'contour' and 'contourf'. - IMT
44

5+
2015-01-31 Added the rcParam 'image.combine_images' to permit users
6+
to decide whether they want the vector graphics backends to combine
7+
all images within a set of axes into a single image. (If images do
8+
not get combined, users can open vector graphics files in Adobe
9+
Illustrator or Inkscape and edit each image individually.) Also
10+
changed 'renderer.option_nocomposite' to the clearer name
11+
'renderer.option_combine_images'.
12+
513
2015-01-23 Text bounding boxes are now computed with advance width rather than
614
ink area. This may result in slightly different placement of text.
715

lib/matplotlib/axes/_base.py

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@
3030
import matplotlib.text as mtext
3131
import matplotlib.image as mimage
3232
from matplotlib.artist import allow_rasterization
33-
34-
3533
from matplotlib.cbook import iterable
3634

3735
rcParams = matplotlib.rcParams
@@ -1241,8 +1239,9 @@ def apply_aspect(self, position=None):
12411239
Xsize = ysize / data_ratio
12421240
Xmarg = Xsize - xr
12431241
Ymarg = Ysize - yr
1244-
xm = 0 # Setting these targets to, e.g., 0.05*xr does not seem to
1245-
# help.
1242+
# Setting these targets to, e.g., 0.05*xr does not seem to
1243+
# help.
1244+
xm = 0
12461245
ym = 0
12471246
#print 'xmin, xmax, ymin, ymax', xmin, xmax, ymin, ymax
12481247
#print 'xsize, Xsize, ysize, Ysize', xsize, Xsize, ysize, Ysize
@@ -1402,7 +1401,7 @@ def get_yticklines(self):
14021401
return cbook.silent_list('Line2D ytickline',
14031402
self.yaxis.get_ticklines())
14041403

1405-
#### Adding and tracking artists
1404+
# Adding and tracking artists
14061405

14071406
def _sci(self, im):
14081407
"""
@@ -1984,7 +1983,7 @@ def autoscale_view(self, tight=None, scalex=True, scaley=True):
19841983
y0, y1 = ylocator.view_limits(y0, y1)
19851984
self.set_ybound(y0, y1)
19861985

1987-
#### Drawing
1986+
# Drawing
19881987

19891988
@allow_rasterization
19901989
def draw(self, renderer=None, inframe=False):
@@ -2042,13 +2041,13 @@ def draw(self, renderer=None, inframe=False):
20422041
dsu = [(a.zorder, a) for a in artists
20432042
if not a.get_animated()]
20442043

2045-
# add images to dsu if the backend support compositing.
2046-
# otherwise, does the manaul compositing without adding images to dsu.
2047-
if len(self.images) <= 1 or renderer.option_image_nocomposite():
2044+
# add images to dsu if the backend supports combining images.
2045+
# otherwise, perform manual combining, without adding images to dsu.
2046+
if len(self.images) <= 1 or not renderer.option_combine_images():
20482047
dsu.extend([(im.zorder, im) for im in self.images])
2049-
_do_composite = False
2048+
_combine_images = False
20502049
else:
2051-
_do_composite = True
2050+
_combine_images = True
20522051

20532052
dsu.sort(key=itemgetter(0))
20542053

@@ -2068,8 +2067,8 @@ def draw(self, renderer=None, inframe=False):
20682067
if self.axison and self._frameon:
20692068
self.patch.draw(renderer)
20702069

2071-
if _do_composite:
2072-
# make a composite image blending alpha
2070+
if _combine_images:
2071+
# combine images, blending alpha
20732072
# list of (mimage.Image, ox, oy)
20742073

20752074
zorder_images = [(im.zorder, im) for im in self.images
@@ -2133,7 +2132,7 @@ def redraw_in_frame(self):
21332132
def get_renderer_cache(self):
21342133
return self._cachedRenderer
21352134

2136-
#### Axes rectangle characteristics
2135+
# Axes rectangle characteristics
21372136

21382137
def get_frame_on(self):
21392138
"""
@@ -2430,7 +2429,7 @@ def set_axis_bgcolor(self, color):
24302429
self._axisbg = color
24312430
self.patch.set_facecolor(color)
24322431

2433-
### data limits, ticks, tick labels, and formatting
2432+
# data limits, ticks, tick labels, and formatting
24342433

24352434
def invert_xaxis(self):
24362435
"Invert the x-axis."
@@ -3004,7 +3003,7 @@ def minorticks_off(self):
30043003
self.xaxis.set_minor_locator(mticker.NullLocator())
30053004
self.yaxis.set_minor_locator(mticker.NullLocator())
30063005

3007-
#### Interactive manipulation
3006+
# Interactive manipulation
30083007

30093008
def can_zoom(self):
30103009
"""

lib/matplotlib/backend_bases.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -527,12 +527,12 @@ def draw_image(self, gc, x, y, im):
527527
"""
528528
raise NotImplementedError
529529

530-
def option_image_nocomposite(self):
530+
def option_combine_images(self):
531531
"""
532532
override this method for renderers that do not necessarily
533-
want to rescale and composite raster images. (like SVG)
533+
want to rescale and composite raster images. (like SVG, PDF, or PS)
534534
"""
535-
return False
535+
return True
536536

537537
def option_scale_image(self):
538538
"""

lib/matplotlib/backends/backend_agg.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -322,11 +322,11 @@ def buffer_rgba(self):
322322
def clear(self):
323323
self._renderer.clear()
324324

325-
def option_image_nocomposite(self):
326-
# It is generally faster to composite each image directly to
327-
# the Figure, and there's no file size benefit to compositing
325+
def option_combine_images(self):
326+
# It is generally faster to write each image directly to
327+
# the Figure, and there's no file size benefit to combining images
328328
# with the Agg backend
329-
return True
329+
return False
330330

331331
def option_scale_image(self):
332332
"""

lib/matplotlib/backends/backend_macosx.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,8 @@ def flipy(self):
170170
def points_to_pixels(self, points):
171171
return points/72.0 * self.dpi
172172

173-
def option_image_nocomposite(self):
174-
return True
173+
def option_combine_images(self):
174+
return False
175175

176176

177177
class GraphicsContextMac(_macosx.GraphicsContext, GraphicsContextBase):

lib/matplotlib/backends/backend_mixed.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ def __init__(self, figure, width, height, dpi, vector_renderer,
4343
self._height = height
4444
self.dpi = dpi
4545

46-
assert not vector_renderer.option_image_nocomposite()
4746
self._vector_renderer = vector_renderer
4847

4948
self._raster_renderer = None
@@ -64,7 +63,7 @@ def __init__(self, figure, width, height, dpi, vector_renderer,
6463
draw_path_collection draw_quad_mesh draw_tex draw_text
6564
finalize flipy get_canvas_width_height get_image_magnification
6665
get_texmanager get_text_width_height_descent new_gc open_group
67-
option_image_nocomposite points_to_pixels strip_math
66+
option_combine_images points_to_pixels strip_math
6867
start_filter stop_filter draw_gouraud_triangle
6968
draw_gouraud_triangles option_scale_image
7069
_text2path _get_text_path_transform height width

lib/matplotlib/backends/backend_pdf.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -462,8 +462,8 @@ def __init__(self, filename):
462462
self.fontNames = {} # maps filenames to internal font names
463463
self.nextFont = 1 # next free internal font name
464464
self.dviFontInfo = {} # information on dvi fonts
465-
self.type1Descriptors = {} # differently encoded Type-1 fonts may
466-
# share the same descriptor
465+
# differently encoded Type-1 fonts may share the same descriptor
466+
self.type1Descriptors = {}
467467
self.used_characters = {}
468468

469469
self.alphaStates = {} # maps alpha values to graphics state objects
@@ -1251,8 +1251,8 @@ def imageObject(self, image):
12511251
self.images[image] = (name, ob)
12521252
return name
12531253

1254-
## These two from backend_ps.py
1255-
## TODO: alpha (SMask, p. 518 of pdf spec)
1254+
# These two from backend_ps.py
1255+
# TODO: alpha (SMask, p. 518 of pdf spec)
12561256

12571257
def _rgb(self, im):
12581258
h, w, s = im.as_rgba_str()
@@ -1475,6 +1475,7 @@ def is_date(x):
14751475

14761476
check_trapped = (lambda x: isinstance(x, Name) and
14771477
x.name in ('True', 'False', 'Unknown'))
1478+
14781479
keywords = {'Title': is_string_like,
14791480
'Author': is_string_like,
14801481
'Subject': is_string_like,
@@ -1576,6 +1577,13 @@ def option_scale_image(self):
15761577
"""
15771578
return True
15781579

1580+
def option_combine_images(self):
1581+
"""
1582+
return whether to combine multiple images on a set of axes into one
1583+
image
1584+
"""
1585+
return rcParams['image.combine_images']
1586+
15791587
def draw_image(self, gc, x, y, im, dx=None, dy=None, transform=None):
15801588
self.check_gc(gc)
15811589

lib/matplotlib/backends/backend_ps.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,13 @@ def option_scale_image(self):
451451
ps backend support arbitrary scaling of image.
452452
"""
453453
return True
454+
455+
def option_combine_images(self):
456+
"""
457+
return whether to combine multiple images on a set of axes into one
458+
image
459+
"""
460+
return rcParams['image.combine_images']
454461

455462
def _get_image_h_w_bits_command(self, im):
456463
if im.is_grayscale:

lib/matplotlib/backends/backend_svg.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -527,11 +527,15 @@ def open_group(self, s, gid=None):
527527
def close_group(self, s):
528528
self.writer.end('g')
529529

530-
def option_image_nocomposite(self):
530+
def option_combine_images(self):
531531
"""
532-
if svg.image_noscale is True, compositing multiple images into one is prohibited
532+
if svg.image_noscale is True, combining multiple images into one is
533+
prohibited
533534
"""
534-
return rcParams['svg.image_noscale']
535+
if rcParams['svg.image_noscale']:
536+
return False
537+
else:
538+
return rcParams['image.combine_images']
535539

536540
def _convert_path(self, path, transform=None, clip=None, simplify=None):
537541
if clip:

lib/matplotlib/figure.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ class Figure(Artist):
249249
250250
*suppressComposite*
251251
For multiple figure images, the figure will make composite
252-
images depending on the renderer option_image_nocomposite
252+
images depending on the renderer option_combine_images
253253
function. If suppressComposite is True|False, this will
254254
override the renderer.
255255
"""
@@ -1045,16 +1045,16 @@ def draw(self, renderer):
10451045

10461046
# override the renderer default if self.suppressComposite
10471047
# is not None
1048-
not_composite = renderer.option_image_nocomposite()
1048+
combine_images = renderer.option_combine_images()
10491049
if self.suppressComposite is not None:
1050-
not_composite = self.suppressComposite
1050+
combine_images = not self.suppressComposite
10511051

1052-
if (len(self.images) <= 1 or not_composite or
1052+
if (len(self.images) <= 1 or not combine_images or
10531053
not cbook.allequal([im.origin for im in self.images])):
10541054
for a in self.images:
10551055
dsu.append((a.get_zorder(), a, a.draw, [renderer]))
10561056
else:
1057-
# make a composite image blending alpha
1057+
# make a combined image, blending alpha
10581058
# list of (_image.Image, ox, oy)
10591059
mag = renderer.get_image_magnification()
10601060
ims = [(im.make_image(mag), im.ox, im.oy, im.get_alpha())
@@ -1067,15 +1067,15 @@ def draw(self, renderer):
10671067
im.is_grayscale = False
10681068
l, b, w, h = self.bbox.bounds
10691069

1070-
def draw_composite():
1070+
def draw_combined_image():
10711071
gc = renderer.new_gc()
10721072
gc.set_clip_rectangle(self.bbox)
10731073
gc.set_clip_path(self.get_clip_path())
10741074
renderer.draw_image(gc, l, b, im)
10751075
gc.restore()
10761076

10771077
dsu.append((self.images[0].get_zorder(), self.images[0],
1078-
draw_composite, []))
1078+
draw_combined_image, []))
10791079

10801080
# render the axes
10811081
for a in self.axes:

lib/matplotlib/rcsetup.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,9 @@ def __call__(self, s):
595595
'image.lut': [256, validate_int], # lookup table
596596
'image.origin': ['upper', six.text_type], # lookup table
597597
'image.resample': [False, validate_bool],
598+
# Force vector graphics backends to combine all images on a set of axes
599+
# into a single image
600+
'image.combine_images': [True, validate_bool],
598601

599602
# contour props
600603
'contour.negative_linestyle': ['dashed',
@@ -764,6 +767,7 @@ def __call__(self, s):
764767
# Maintain shell focus for TkAgg
765768
'tk.window_focus': [False, validate_bool],
766769
'tk.pythoninspect': [False, validate_tkpythoninspect], # obsolete
770+
767771
# Set the papersize/type
768772
'ps.papersize': ['letter', validate_ps_papersize],
769773
'ps.useafm': [False, validate_bool], # Set PYTHONINSPECT

lib/matplotlib/tests/test_backend_pdf.py

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
import os
1010

1111
import numpy as np
12-
1312
from matplotlib import cm, rcParams
13+
from matplotlib.backends.backend_pdf import PdfPages
1414
from matplotlib import pyplot as plt
1515
from matplotlib.testing.decorators import (image_comparison, knownfailureif,
1616
cleanup)
@@ -42,7 +42,6 @@ def test_type42():
4242

4343
@cleanup
4444
def test_multipage_pagecount():
45-
from matplotlib.backends.backend_pdf import PdfPages
4645
with PdfPages(io.BytesIO()) as pdf:
4746
assert pdf.get_pagecount() == 0
4847
fig = plt.figure()
@@ -58,7 +57,7 @@ def test_multipage_pagecount():
5857
def test_multipage_keep_empty():
5958
from matplotlib.backends.backend_pdf import PdfPages
6059
from tempfile import NamedTemporaryFile
61-
### test empty pdf files
60+
# test empty pdf files
6261
# test that an empty pdf is left behind with keep_empty=True (default)
6362
with NamedTemporaryFile(delete=False) as tmp:
6463
with PdfPages(tmp) as pdf:
@@ -69,7 +68,7 @@ def test_multipage_keep_empty():
6968
with PdfPages(filename, keep_empty=False) as pdf:
7069
pass
7170
assert not os.path.exists(filename)
72-
### test pdf files with content, they should never be deleted
71+
# test pdf files with content, they should never be deleted
7372
fig = plt.figure()
7473
ax = fig.add_subplot(111)
7574
ax.plot([1, 2, 3])
@@ -87,3 +86,24 @@ def test_multipage_keep_empty():
8786
pdf.savefig()
8887
assert os.path.exists(filename)
8988
os.remove(filename)
89+
90+
91+
@cleanup
92+
def test_combine_images():
93+
#Test that figures can be saved with and without combining multiple images
94+
#(on a single set of axes) into a single image.
95+
X, Y = np.meshgrid(np.arange(-5, 5, 1), np.arange(-5, 5, 1))
96+
Z = np.sin(Y ** 2)
97+
fig = plt.figure()
98+
ax = fig.add_subplot(1, 1, 1)
99+
ax.set_xlim(0, 3)
100+
ax.imshow(Z, extent=[0, 1, 0, 1])
101+
ax.imshow(Z[::-1], extent=[2, 3, 0, 1])
102+
plt.rcParams['image.combine_images'] = True
103+
with PdfPages(io.BytesIO()) as pdf:
104+
fig.savefig(pdf, format="pdf")
105+
assert len(pdf._file.images.keys()) == 1
106+
plt.rcParams['image.combine_images'] = False
107+
with PdfPages(io.BytesIO()) as pdf:
108+
fig.savefig(pdf, format="pdf")
109+
assert len(pdf._file.images.keys()) == 2

0 commit comments

Comments
 (0)