Skip to content

Commit 1f3b3c3

Browse files
authored
Fix PDF bloat for off-axis scatter with per-point colors
1 parent f95d761 commit 1f3b3c3

1 file changed

Lines changed: 23 additions & 20 deletions

File tree

lib/matplotlib/backends/backend_pdf.py

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2104,25 +2104,28 @@ def draw_path_collection(self, gc, master_transform, paths, all_transforms,
21042104

21052105
padding = np.max(linewidths)
21062106
path_codes = []
2107-
2108-
# Calculate maximum marker extent for conservative bounds checking.
2109-
# We need to account for marker size, not just position.
2110-
max_marker_extent = 0
2107+
path_extents = []
21112108
for i, (path, transform) in enumerate(self._iter_collection_raw_paths(
21122109
master_transform, paths, all_transforms)):
2113-
if len(path.vertices):
2114-
# Get the bounding box of the transformed marker path.
2115-
# Use get_extents() which is more efficient than transforming
2116-
# all vertices, and add padding for stroke width.
2117-
bbox = path.get_extents(transform)
2118-
max_marker_extent = max(max_marker_extent,
2119-
bbox.width / 2, bbox.height / 2)
21202110
name = self.file.pathCollectionObject(
21212111
gc, path, transform, padding, filled, stroked)
21222112
path_codes.append(name)
2113+
# Compute the extent of each marker path to enable per-marker
2114+
# bounds checking. This allows us to skip markers that are
2115+
# completely outside the visible canvas while preserving markers
2116+
# that are partially visible.
2117+
if len(path.vertices):
2118+
bbox = path.get_extents(transform)
2119+
# Store half-width and half-height for efficient bounds checking
2120+
path_extents.append((bbox.width / 2, bbox.height / 2))
2121+
else:
2122+
path_extents.append((0, 0))
2123+
2124+
# Create a mapping from path_id to extent for efficient lookup
2125+
path_extent_map = dict(zip(path_codes, path_extents))
21232126

2124-
# Add padding for stroke width.
2125-
max_marker_extent += padding
2127+
canvas_width = self.file.width * 72
2128+
canvas_height = self.file.height * 72
21262129

21272130
output = self.file.output
21282131
output(*self.gc.push())
@@ -2132,13 +2135,13 @@ def draw_path_collection(self, gc, master_transform, paths, all_transforms,
21322135
facecolors, edgecolors, linewidths, linestyles,
21332136
antialiaseds, urls, offset_position, hatchcolors=hatchcolors):
21342137

2135-
# Skip markers outside visible canvas bounds to reduce PDF size.
2136-
# Add max_marker_extent margin to account for marker size - a marker
2137-
# may be partially visible even if its center is outside the canvas.
2138-
canvas_width = self.file.width * 72
2139-
canvas_height = self.file.height * 72
2140-
if not (-max_marker_extent <= xo <= canvas_width + max_marker_extent
2141-
and -max_marker_extent <= yo <= canvas_height + max_marker_extent):
2138+
# Skip markers completely outside visible canvas bounds to reduce
2139+
# PDF file size. Use per-marker extents to handle large markers
2140+
# correctly: only skip if the marker's bounding box doesn't
2141+
# intersect the canvas at all.
2142+
extent_x, extent_y = path_extent_map[path_id]
2143+
if not (-extent_x <= xo <= canvas_width + extent_x
2144+
and -extent_y <= yo <= canvas_height + extent_y):
21422145
continue
21432146

21442147
self.check_gc(gc0, rgbFace)

0 commit comments

Comments
 (0)