Skip to content

ENH: Added sharex/sharey string support to subplot_mosaic - #32437

Open
nillohitroy wants to merge 3 commits into
matplotlib:mainfrom
nillohitroy:subplot_mosaic-share-issue-18305
Open

nillohitroy wants to merge 3 commits into
matplotlib:mainfrom
nillohitroy:subplot_mosaic-share-issue-18305

Conversation

@nillohitroy

@nillohitroy nillohitroy commented Oct 4, 2026 •

Copy link
Copy Markdown

PR summary

This PR implements string arguments ('all', 'row', 'col') and boolean True/False for sharex and sharey in subplot_mosaic() for #18305 .

To handle complex and nested layouts, the axes are grouped based on their specific GridSpec and exact rowspan/colspan coordinates. Axes only share a row or column if their spans are identical.
For example, consider a layout where C and D span both rows:

ABCD
EFCD

If sharey='row' is passed, the code forms three isolated sharing groups based on their vertical spans:

  • [A, B] (Row 0)
  • [E, F] (Row 1)
  • [C, D] (Spanning Rows 0 and 1)

Once the groups are isolated, the logic designates the first axis in each list as the parent and calls standard .sharex(parent) or .sharey(parent) on the remaining children in that specific group.

Important Note: Relying on Matplotlib's global ax._label_outer_xaxis() or ax._label_outer_yaxis() inadvertently hid tick labels for inner subplots if they formed their own isolated sharing group. For this very reason, I implemented a custom logic which calculates label visibility dynamically per group. For example, in an X-axis sharing group, it calculates the physical bottom edge by finding the max() of rowspan.stop across just the group's members. It then loops through that group and applies ax.tick_params(labelbottom=False) to any axis sitting above that localized bottom edge.

AI Disclosure

I have used Generative AI to understand the codebase (specifically the code for the issue), setting up of the environment (installing packages and dependencies required), the intent of the issue and to get to the center of the problem. It is also important to mention that AI was used to understand the requirements of the maintainers and how #32239 failed and what to avoid while coding.

Verification

I have tested the code for a local matplotlib development build, running it on my system and creating a sample plot for a sample data. Also, I have written some test cases for the same by trying to incorporate as many test cases as possible (5), all of which successfully passed.

I would be happy for any feedback regarding any portion of the code!!

PR quality check

  • Use an expressive title, e.g. "Fix title font property precedence"
  • New and changed code is tested
  • [/] Plotting related features are demonstrated in an example
  • [/ ] New features and API changes have release notes
  • [/ ] Documentation complies with general and docstring guidelines

Copilot AI balanced review requested due to automatic review settings October 4, 2026 14:48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions

github-actions Bot commented Oct 4, 2026

Copy link
Copy Markdown

Thank you for opening your first PR into Matplotlib!

If you have not heard from us in a week or so, please leave a new comment below and that should bring it to our attention. Most of our reviewers are volunteers and sometimes things fall through the cracks. We also ask that you please finish addressing any review comments on this PR and wait for it to be merged (or closed) before opening a new one, as it can be a valuable learning experience to go through the review process.

You can also join us on discourse chat for real-time discussion.

For details on testing, writing docs, and our review process, please see the developer guide.
Please let us know if (and how) you use AI, it will help us give you better feedback on your PR.

We strive to be a welcoming and open project. Please follow our Code of Conduct.

@nillohitroy

Copy link
Copy Markdown
Author

Dear Maintainers,
I have seen how diligently you guys work and how mentally constraining reviewing each line of the code is. Though this issue is a 'good first issue' and not as complex (and may be not as important) as compared to the other bug fixes that the contributors are providing. I would be obliged if you could review my code and give me necessary feedback to improve it as much as possible.

@iccir

iccir commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

Assuming that I'm talking to an actual human: this PR is currently failing to pass the Linting and MyPy Stubtest checks. The AppVeyor build failure is somewhat expected as AppVeyor has been flaky recently.

Generally, you will want to make sure that all checks pass on any PR that you open to a repository. You need to get at least Linting and the stub test to pass first.

@nillohitroy

Copy link
Copy Markdown
Author

Assuming that I'm talking to an actual human: this PR is currently failing to pass the Linting and MyPy Stubtest checks. The AppVeyor build failure is somewhat expected as AppVeyor has been flaky recently.

Generally, you will want to make sure that all checks pass on any PR that you open to a repository. You need to get at least Linting and the stub test to pass first.

Thank you sir.. on it..

@github-actions github-actions Bot added topic: geometry manager LayoutEngine, Constrained layout, Tight layout topic: rcparams Documentation: devdocs files in doc/devel labels Oct 7, 2026
@nillohitroy

Copy link
Copy Markdown
Author

Hi @iccir
I think I have screwed up in some way. Thing is, I have done a pull request and merged the code, so instead of just 1 commit, there is 11 commits and also some failed tests (of other developers). I have checked my tests (linting and all) and everything is successful. My question is: will everything work or do I have to open a new pull request?
Sorry for any trouble I have caused.

@rcomer

rcomer commented Oct 7, 2026 •

Copy link
Copy Markdown
Member

I think a rebase should sort that out. Assuming you have set the upstream remote as described here, try this:

Make a backup branch in case something else goes wrong

git branch my-backup-branch 

Rebase on the upstream branch

git fetch upstream
git rebase upstream/main

git push will then fail, but you can

git push --force-with-lease

@iccir

iccir commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

Hey, it happens - git can be tricky :)

It looks like you made two commits:
c278400
a14df4f

I'd do something like the following:

git diff \
    c278400dee9b6758ce74f0eab9b5cbc085b595ee^ \
    a14df4f320b0b13ebdf7fc34cf4d356e5f0f67ea > \
    /someplace/safe/changes.patch

Then I'd follow @rcomer's instructions above. You can always reapply the patch with:

git apply /someplace/safe/changes.patch

@nillohitroy
nillohitroy force-pushed the subplot_mosaic-share-issue-18305 branch from 4f25789 to 1416ea3 Compare October 8, 2026 01:04
@github-actions github-actions Bot removed topic: geometry manager LayoutEngine, Constrained layout, Tight layout topic: rcparams Documentation: devdocs files in doc/devel labels Oct 8, 2026
@nillohitroy

nillohitroy commented Oct 8, 2026 •

Copy link
Copy Markdown
Author

Hi @rcomer @iccir
Thank you for being so kind and helpful. I have solved the issue with the merge request.
However, as shown, there is a failing test with Mac OS and I don't have a MAC so I really don't know what the issue is.

@iccir

iccir commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

If you get a test failure that you don't understand, there are several possibilities:

  1. The test failure is caused by a specific version of Python. For example, we could see Python 3.12 failing across several different operating systems.
  2. The test failure is caused by a specific platform. We could see all macOS builders fail, for example.
  3. A test failure on a specific version of Python and a specific platform. You would see a single test failure, as in this case.

More commonly, however, #3 can indicate that something is wrong with the Continuous Integration (CI) system.

You can often look at other pull requests to see if they are having similar issues. Python 3.12 on macOS 15 has been failing all day - here's another example with the same error.

So, it's probably not an error in your code!

@nillohitroy

Copy link
Copy Markdown
Author

If you get a test failure that you don't understand, there are several possibilities:

  1. The test failure is caused by a specific version of Python. For example, we could see Python 3.12 failing across several different operating systems.
  2. The test failure is caused by a specific platform. We could see all macOS builders fail, for example.
  3. A test failure on a specific version of Python and a specific platform. You would see a single test failure, as in this case.

More commonly, however, #3 can indicate that something is wrong with the Continuous Integration (CI) system.

You can often look at other pull requests to see if they are having similar issues. Python 3.12 on macOS 15 has been failing all day - here's another example with the same error.

So, it's probably not an error in your code!

I also have the same view as you. It is showing that the test is failing only in macos-15 (macos26 is running successfully). Also, I have tested the code locally as well, so I'm pretty confident about it. My request is if you could review my code so as to ensure if there are other major issues or this code can be merged to the repo..

@nillohitroy

Copy link
Copy Markdown
Author

Hi @rcomer
Sorry to disturb you like this. But is it possible for you to review my code?

@nillohitroy
nillohitroy requested a balanced review from Copilot October 12, 2026 15:32

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Fix nested-layout label visibility by comparing physical positions and update the public documentation.

3 open findings

🧠 Review effort: Lite

Comment thread lib/matplotlib/figure.py Outdated
Comment on lines +2337 to +2340
bottom_edge = max(ax.get_subplotspec().rowspan.stop for ax in group)
for ax in group:
if ax.get_subplotspec().rowspan.stop < bottom_edge:
ax.tick_params(labelbottom=False)
Comment thread lib/matplotlib/figure.py Outdated
Comment on lines +2120 to +2128
# Custom Validation Function to check for booleans and strings.
def _validate_share_param(param_name, value):
if type(value) is bool:
return value
if value in ["all", "row", "col"]:
return value
raise ValueError(
f"{param_name} must be True, False, 'all', 'row', or 'col'"
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As suggested by AI: Please update the documentation. In particular, clearly define how "col" and "row" work.

Comment thread lib/matplotlib/pyplot.py Outdated
Comment on lines +1899 to +1900
sharex: bool | Literal["all", "row", "col"] = ...,
sharey: bool | Literal["all", "row", "col"] = ...,
@rcomer

rcomer commented Oct 13, 2026

Copy link
Copy Markdown
Member

I'm sorry but I do not think I will be able to review this any time soon.

@nillohitroy

Copy link
Copy Markdown
Author

I'm sorry but I do not think I will be able to review this any time soon.

I appreciate your efforts and I can understand it. I will figure it out in some way..

@nillohitroy

Copy link
Copy Markdown
Author

Hi @iccir
Is it possible for you to review this PR? If so, can you please help me out?

Comment thread lib/matplotlib/figure.py Outdated
Comment on lines +2120 to +2128
# Custom Validation Function to check for booleans and strings.
def _validate_share_param(param_name, value):
if type(value) is bool:
return value
if value in ["all", "row", "col"]:
return value
raise ValueError(
f"{param_name} must be True, False, 'all', 'row', or 'col'"
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As suggested by AI: Please update the documentation. In particular, clearly define how "col" and "row" work.

Comment thread lib/matplotlib/figure.py Outdated
Comment on lines +2290 to +2298
# Asymmetrical/Directional Implementation that needs to be changed
# ax0 = next(iter(ret.values()))
# for ax in ret.values():
# if sharex:
# ax.sharex(ax0)
# ax._label_outer_xaxis(skip_non_rectangular_axes=True)
# if sharey:
# ax.sharey(ax0)
# ax._label_outer_yaxis(skip_non_rectangular_axes=True)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the puropse of this comment?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forgot to remove this comment - a mistake from my end. I will fix this along with other issues you have mentioned. Thank you for taking out time and reviewing my PR.

Comment thread lib/matplotlib/figure.py Outdated
@@ -2277,14 +2287,67 @@ def _do_layout(gs, mosaic, unique_ids, nested):
rows, cols = mosaic.shape
gs = self.add_gridspec(rows, cols, **gridspec_kw)
ret = _do_layout(gs, mosaic, *_identify_keys_and_nested(mosaic))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ret = _do_layout(gs, mosaic, *_identify_keys_and_nested(mosaic))
ax_dict = _do_layout(gs, mosaic, *_identify_keys_and_nested(mosaic))

Since there is now a lot of code between definition and final usage as return ret, the operational name is not good enough anymore and instead we should use a semantic name.

Comment thread lib/matplotlib/figure.py Outdated
# ax._label_outer_yaxis(skip_non_rectangular_axes=True)

# Symmetric Sharing
def _apply_sharing(ret_dict, share_val, axis_name):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def _apply_sharing(ret_dict, share_val, axis_name):
def _apply_sharing(ax_dict, share_val, axis_name):

Comment thread lib/matplotlib/figure.py
# ax.sharey(ax0)
# ax._label_outer_yaxis(skip_non_rectangular_axes=True)

# Symmetric Sharing

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Symmetric Sharing

That comment does not tell much. Please write a proper docstring.

Comment thread lib/matplotlib/figure.pyi
self,
mosaic: str,
*,
sharex: bool = ...,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not clear whether we want "all" as synonym for True. On the one hand it's unnecessarily redundant, on the other hand it's consistent with subplots. I'm slightly inclined towards the narrower API. Others may have stronger opinions.

But if we support "all", we also must "none".

Comment thread lib/matplotlib/figure.py Outdated
def _validate_share_param(param_name, value):
if type(value) is bool:
return value
if value in ["all", "row", "col"]:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we support "all", we should normalize it here to True, so that the following code does not have to check for both.

@nillohitroy

Copy link
Copy Markdown
Author

@timhoffm
I have made the changes as mentioned in the review. Please check if the changes made are correct and again thank you for your valuable feedback.

This branch has not been deployed

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants