Skip to content

Fix: preserve original Figure DPI in pickle to prevent HiDPI doubling (macOSX)#32

Open
emerson-gray wants to merge 1 commit intomatplotlib__matplotlib-23476from
fix/dpi-pickle-original
Open

Fix: preserve original Figure DPI in pickle to prevent HiDPI doubling (macOSX)#32
emerson-gray wants to merge 1 commit intomatplotlib__matplotlib-23476from
fix/dpi-pickle-original

Conversation

@emerson-gray
Copy link

Problem

  • On HiDPI backends (e.g., macOSX on Retina), FigureCanvasBase scales Figure.dpi by device pixel ratio (DPR) based on figure._original_dpi. On unpickle, FigureCanvasBase(self) sets figure._original_dpi from the current (possibly scaled) dpi. When the backend applies DPR again, dpi is multiplied again, doubling on each pickle/unpickle cycle.

Root cause

  • Figure.getstate persists the runtime _dpi (which may be scaled), not the baseline, unscaled dpi. This breaks the invariant that _original_dpi should reflect the figure's baseline dpi before DPR.

Fix

  • In Figure.getstate, persist the unscaled dpi by setting state["_dpi"] = getattr(self, "_original_dpi", self._dpi) before returning. This ensures unpickled figures start from baseline dpi, and DPR is applied exactly once.

Tests

  • Add test_hidpi_pickle_unpickle_does_not_double_dpi to tests/test_pickle.py that emulates DPR=2 via fig.canvas._set_device_pixel_ratio(2) and verifies dpi remains stable (200) across repeated pickle/unpickle cycles.

Compatibility and risk

  • Non-HiDPI backends (DPR=1) are unaffected because _original_dpi == _dpi.
  • Older pickles created before this change will continue to load as before; they may still reflect the previously scaled dpi. The change only affects newly created pickles by making them future-proof against cumulative scaling.

Target

  • Base branch: matplotlib__matplotlib-23476

@emerson-gray emerson-gray requested a review from a team December 24, 2025 20:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant