Skip to content

ENH: Add screen-proportional mutation_aspect to FancyBboxPatch - #32205

Open
Muhtasim-Munif-Fahim wants to merge 1 commit into
matplotlib:mainfrom
Muhtasim-Munif-Fahim:enh/round-boxstyle-mutation-aspect
Open

ENH: Add screen-proportional mutation_aspect to FancyBboxPatch#32205
Muhtasim-Munif-Fahim wants to merge 1 commit into
matplotlib:mainfrom
Muhtasim-Munif-Fahim:enh/round-boxstyle-mutation-aspect

Conversation

@Muhtasim-Munif-Fahim

Copy link
Copy Markdown

PR summary

What problem existed

FancyBboxPatch requires a numeric mutation_aspect to compensate for a non-unit axes aspect ratio. In a plot with aspect="auto" (e.g. a typical bar chart), the rounding of BoxStyle("Round", ...) is drawn as an ellipse on screen, not a circle. The only way to get isotropic rounding was the private workaround mutation_aspect=1/ax._get_aspect_ratio(), which is also computed too early (before layout) and therefore stale by draw time.

How it was reproduced

import matplotlib.pyplot as plt
from matplotlib.patches import FancyBboxPatch, BoxStyle

def add_bar(ax, x, y, w, h, mutation_aspect=1):
    patch = FancyBboxPatch(
        (x, y), w, h,
        boxstyle=BoxStyle("Round", pad=0, rounding_size=w / 2),
        linewidth=0, facecolor="C0",
        mutation_aspect=mutation_aspect,
    )
    ax.add_patch(patch)

fig, ax = plt.subplots(figsize=(10, 5))
x, y, w, h = 0.3, 0, 0.18, 1
add_bar(ax, x, y, w, h)
ax.autoscale_view()
fig.canvas.draw()

What caused it

FancyBboxPatch.get_path() applies mutation_aspect in data coordinates only. When the axes display scaling differs between x and y (aspect != 1), a data-space circle is drawn as an on-screen ellipse. There was no public way to opt in to resolving the aspect ratio from the axes.

What changed

FancyBboxPatch.mutation_aspect now additionally accepts the string "screen-proportional". At draw time the patch resolves it from the owning axes using public API (get_window_extent, axis transforms), so the box is scaled like the data on screen and the rounding renders circular regardless of the axes aspect ratio. set_mutation_aspect validates the new value.

Why this approach

The issue proposed an opt-in mode; discussion suggested a name that is more specific than a generic "auto". The resolution is deferred to draw time so the layout (and thus the display scaling) is final, fixing the stale-value problem of the private-API workaround. All existing numeric behavior is unchanged.

How it was tested

  • python -m pytest lib/matplotlib/tests/test_patches.py -k "mutation_aspect" -v → 1 passed
  • python -m pytest lib/matplotlib/tests/test_patches.py → 73 passed, 11 skipped (pre-existing skips)
  • Added tests: display-space circular corner check with a non-unit-aspect axes, fallback to 1 without an Axes, and ValueError on invalid values.

Risks / limitations

  • Without an attached Axes, "screen-proportional" falls back to an aspect of 1 (documented in the new tests).
  • The resolved aspect is a snapshot at draw time; it updates when the figure is redrawn after a resize.

Related issue

Closes #31175

Add opt-in "screen-proportional" mode to FancyBboxPatch.mutation_aspect
that resolves the display-space aspect ratio from the axes at draw time.
Rounded corners of Round/other boxstyles then render circular on screen
regardless of the axes aspect ratio, without requiring the private
ax._get_aspect_ratio() workaround.

Closes matplotlib#31175.
@melissawm melissawm added ai-contribution PRs that are AI generated without a human in the loop status: autoclose candidate PRs that are not yet ready for review and may be automatically closed in two weeks labels Aug 12, 2026
@github-actions

Copy link
Copy Markdown

⏰ This pull request might be automatically closed in two weeks from now.

Thank you for your contribution to Matplotlib and for the effort you have put into this PR. This pull request does not yet meet the quality and clarity standards needed for an effective review. Project maintainers have limited time for code reviews, and our goal is to prioritize well-prepared contributions to keep Matplotlib maintainable.

Matplotlib maintainers cannot provide one-to-one guidance on this PR. However, if you ask focused, well-researched questions, a community member may be willing to help. 💬

To increase the chance of a productive review:

As the author, you are responsible for driving this PR, which entails doing necessary background research as well as presenting its context and your thought process. If you are a new contributor, or do not know how to fulfill these requirements, we recommend that you familiarize yourself with Matplotlib's development conventions or engage with the community via our Discourse or one of our meetings before submitting code.

If you substantially improve this PR within two weeks, leave a comment and a team member may remove the status: autoclose candidate label and the PR stays open. Cosmetic changes or incomplete fixes will not be sufficient. Maintainers will assess improvements on their own schedule. Please do not ping (@) maintainers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-contribution PRs that are AI generated without a human in the loop status: autoclose candidate PRs that are not yet ready for review and may be automatically closed in two weeks

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[ENH]: mutation_aspect for Round BoxStyle type

2 participants