Skip to content

Conversation

G26karthik
Copy link
Contributor

Fixes #22197

Summary

This PR adds a documentation note to the Colormap Normalization tutorial explaining how users can restore the pre-3.5 linear colorbar spacing for TwoSlopeNorm and other norms with a scale.

Changes Made

  • Added a note section after the TwoSlopeNorm example in galleries/users_explain/colors/colormapnorms.py
  • Documents that colorbars for norms with a scale use that scale by default (behavior introduced in matplotlib 3.5)
  • Explains the cb.ax.set_yscale('linear') workaround for users who prefer linear spacing

Context

Since matplotlib 3.5, colorbars for norms with a scale (like TwoSlopeNorm) display the scale in the colorbar itself, which can appear non-linear. While this is consistent with other scaled norms like LogNorm, many users expect or prefer the linear spacing behavior from versions before 3.5.

This note provides clear guidance on how to achieve linear colorbar spacing when desired, addressing a common user question documented in issue #22197.

Testing

  • Verified the note renders correctly in the documentation
  • Checked that the placement after the TwoSlopeNorm example is appropriate
  • Followed matplotlib documentation style guidelines for reStructuredText notes

Addresses matplotlib#22197 by documenting the cb.ax.set_yscale('linear')
workaround for users who prefer linear colorbar spacing instead of
the default scaled spacing introduced in matplotlib 3.5.
@github-actions github-actions bot added the Documentation: user guide files in galleries/users_explain or doc/users label Oct 6, 2025
…opeNorm

Replace note with side-by-side example showing:
- Left: Default scaled colorbar (centered at midpoint)
- Right: Linear colorbar using cb.ax.set_yscale('linear')

Addresses maintainer feedback from @jklymak to make the difference
more clear with a visual demonstration.
- Change title from 'norms with a scale' to TwoSlopeNorm-specific
- Clarify that colorbar is divided into two equal parts
- Explain screen-space vs data range difference
- Note that color-to-value mapping remains unchanged
- Address review comments from @timhoffm
- Add backticks around .TwoSlopeNorm class reference
- Use double backticks for cb.ax.set_yscale('linear') code snippet
- Fixes documentation build errors
timhoffm
timhoffm previously approved these changes Oct 7, 2025
# `~.colors.FuncNorm` to define your own. Note that this example is the same
# as `~.colors.PowerNorm` with a power of 0.5:


Copy link
Member

Choose a reason for hiding this comment

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

Unrelated change.

Suggested change

Copy link
Member

Choose a reason for hiding this comment

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

You didn't fix this

Copy link
Member

@jklymak jklymak left a comment

Choose a reason for hiding this comment

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

I think the wording could be clearer. Also please avoid the term "screen space". Screen space is completely virtual.


fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4))

# Left plot: Default scaled colorbar (centered at midpoint)
Copy link
Member

Choose a reason for hiding this comment

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

Most of this is repeated. I'd just put in a loop, and act on the last colorbar created.

Copy link
Member

Choose a reason for hiding this comment

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

If you are going to resolve a suggestion without taking it, it helps to explain why you ignored it.

G26karthik and others added 3 commits October 7, 2025 22:40
Co-authored-by: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com>
- Rewrite explanation to avoid 'screen space' term per jklymak
- Clarify that colorbars adopt their norm's scaling by default
- Better explain TwoSlopeNorm splits colormap evenly between halves
- Change tick specification to use np.arange for clarity
- Update both cb1 and cb2 to use np.arange(-500, 4001, 500)

Addresses @jklymak review comments
- Fix E501: Break long line (line 289) to stay under 88 character limit
- Fix E302: Add missing blank line before function definition

All ruff checks now pass.
@G26karthik
Copy link
Contributor Author

Thank you both @timhoffm and @jklymak for your thorough reviews and excellent suggestions! 🙏

I've addressed all the feedback:

@timhoffm's suggestions:
✅ Changed title to "Using a linear scale on the colormap"
✅ Rewrote explanation to be TwoSlopeNorm-specific
✅ Clarified equal-part division with different scaling
✅ Explained color-to-value mapping preservation

@jklymak's suggestions:
✅ Improved wording clarity and removed "screen space" reference
✅ Changed tick examples to np.arange(-500, 4001, 500) for clearer spacing
✅ Fixed all linting errors (E501, E302)

The documentation now provides clear, specific guidance with better examples. All CI checks should pass now. Thank you for helping improve this! 🎉

G26karthik and others added 4 commits October 7, 2025 23:06
The set_ticks() method expects a 1D array with shape (N,), but wrapping
np.arange() in square brackets creates a list containing an array with
shape (1, N). This fixes the ValueError by passing the array directly.
Co-authored-by: Jody Klymak <jklymak@gmail.com>
Precommit linter expects only one blank line before # %% markers.
The end-of-file-fixer precommit hook requires files to end
with exactly one newline, not multiple.
# `~.colors.FuncNorm` to define your own. Note that this example is the same
# as `~.colors.PowerNorm` with a power of 0.5:


Copy link
Member

Choose a reason for hiding this comment

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

You didn't fix this


fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4))

# Left plot: Default scaled colorbar (centered at midpoint)
Copy link
Member

Choose a reason for hiding this comment

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

If you are going to resolve a suggestion without taking it, it helps to explain why you ignored it.

G26karthik and others added 2 commits October 8, 2025 01:22
Co-authored-by: Jody Klymak <jklymak@gmail.com>
- Replace repeated code blocks with a loop as suggested by jklymak
- Iterate over both axes with corresponding titles
- Act on the last colorbar (cb) to set linear scale for right plot
- Reduces code duplication and improves maintainability
@G26karthik
Copy link
Contributor Author

Hi @jklymak,

You're absolutely right, and I apologize for the confusion. I initially marked the conversation as resolved after addressing the grammar suggestion without implementing the loop refactoring you requested.

I've now refactored the code to use a loop as you suggested in commit c8a0930. The changes include:

  • Removed the repetitive code blocks for the left and right plots
  • Implemented a loop that iterates over both axes with their corresponding titles
  • Act on the last colorbar created (cb) to set the linear scale for the right plot, as you recommended

The refactored code is much cleaner and more maintainable. Thank you for pushing me to make this improvement—it's definitely better this way!

Changes:

  • Reduced code duplication (21 lines removed, 13 lines added)
  • Both plots now share the same pcolormesh, set_aspect, and set_ticks logic through the loop
  • Only the right colorbar gets cb.ax.set_yscale('linear') applied after the loop

Thank you for your patience and detailed feedback!

- Wrap long comment lines to stay within 88 character limit
- Split zip() arguments across lines for better readability
- Add blank line before section marker
- All ruff checks now pass
@timhoffm timhoffm dismissed their stale review October 7, 2025 20:13

I'll leave this to @jklymak.

Copy link
Member

@jklymak jklymak left a comment

Choose a reason for hiding this comment

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

Looks good. ~But I'm removing your extra carriage return. ~

@jklymak jklymak merged commit 6e95994 into matplotlib:main Oct 8, 2025
22 checks passed
@G26karthik
Copy link
Contributor Author

Looks good. ~But I'm removing your extra carriage return. ~

Appreciate your thorough review and for merging this in, @jklymak. I’ll make sure to avoid those extra carriage returns next time.

@G26karthik G26karthik deleted the doc-twoslopenorm-colorbar-scale branch October 8, 2025 05:47
@G26karthik
Copy link
Contributor Author

Hi! I really enjoyed contributing to this repo and plan to do more in the future. If you could add the hacktoberfest-accepted label to this PR, it’d help me a lot. Thank you! 🙏

@G26karthik G26karthik restored the doc-twoslopenorm-colorbar-scale branch October 8, 2025 05:51
@G26karthik G26karthik deleted the doc-twoslopenorm-colorbar-scale branch October 8, 2025 05:51
@timhoffm timhoffm added the hacktoberfest-accepted valid for hacktoberfest but not ready for merging label Oct 8, 2025
@jklymak
Copy link
Member

jklymak commented Oct 10, 2025

Are we participating in hacktoberfest?

@timhoffm
Copy link
Member

We’re not actively advertising, or formally taking part but I think there is no harm in putting the label on reasonable PRs on request. It is my understanding that this is enough for the PR to count - but maybe I’m wrong there.

@jklymak
Copy link
Member

jklymak commented Oct 10, 2025

Fair enough. Hacktoberfest is not always net plus for the project, so I wasnt sure we wanted to encourage.

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

Labels

Documentation: user guide files in galleries/users_explain or doc/users hacktoberfest-accepted valid for hacktoberfest but not ready for merging

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: TwoSlopeNorm behaves like CenteredNorm

3 participants