Skip to content

[Bug]: PDF backend culls visible hexbin cells after path collection optimization #31999

Description

@yuzie007

Bug summary

Matplotlib 3.11.0 introduced PDF backend culling for path collections to avoid very large PDFs when many colored scatter markers are outside the visible canvas (#30746). This works for scatter, but it incorrectly clips hexbin output when the hexbin offsets include negative coordinates.

Code for reproduction

import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng(19680801)
x = rng.normal(size=10_000)
y = rng.normal(size=10_000)

fig, ax = plt.subplots()
ax.hexbin(x, y, gridsize=25, edgecolors="none")
fig.savefig("hexbin.png")
fig.savefig("hexbin.pdf")

Actual outcome

The above code produces hexbin.pdf. Converting it to PNG with magick shows: Image

Expected outcome

The above happens only for the PDF backend. For the PNG format, it is rendered as expected as below. Image

Additional information

The key difference from scatter is how the collections are transformed. For scatter, the collection offsets transformed by offset_transform are the actual marker centers in canvas/display coordinates, and the marker path is centered around that offset. Therefore, checking whether the offset plus marker extent intersects the PDF canvas is valid.

For hexbin, the collection is built from one reusable hexagon path plus many offsets, but the offsets are transformed with AffineDeltaTransform(self.transData). That transform intentionally removes the translation component from transData, so the transformed offsets are displacement vectors, not full canvas-space marker centers. The missing translation is carried by the transformed prototype path. The PDF backend culling logic treated those displacement offsets as if they were absolute canvas positions, so visible hexagons with negative offsets were skipped. This makes the PDF output lose part of the hexbin plot, while raster backends such as Agg/PNG render correctly.

This issue can be fixed, with keeping the PR #30746 optimization, but by culling using the final translated path bounds rather than assuming the transformed offset alone is the marker center. This preserves the scatter PDF size optimization while correctly handling hexbin and any other path collection whose offset transform is not an absolute canvas-position transform.

Operating system

macOS Sequoia 15.6

Matplotlib Version

3.11.0

Matplotlib Backend

PDF

Python version

3.13

Jupyter version

No response

Installation

None

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions