GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — [MNT]: Implement `Scale.val_in_range` and refactor `_point_in_data_domain` by null-dreams · Pull Request #31306 · matplotlib/matplotlib

Conversation

@null-dreams

@null-dreams null-dreams commented Mar 14, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

Closes #31286

PR summary

Following the suggestion by @timhoffm in #31061, this PR introduces a val_in_range method to the Scale hierarchy.

  • Why is this change necessary?
    The current implementation of _point_in_data_domain relies on a "clipping side-effect." It calls limit_range_for_scale, which is intended for setting axis limits, and then compares if the output value differs from the input value to determine validity. This approach is semantically indirect and makes the logic harder to maintain.

  • What problem does it solve?

    1. API Cleanliness: It decouples the logical question "is this value valid for this scale?" from the action of clipping a value to a supported range.
    2. Code Clarity: It removes the need for Axes logic to handle scale-specific details like minpos or equality checks against clipped values.
  • What is the reasoning for this implementation?

    • Fallback Support: ScaleBase implements val_in_range using the existing limit_range_for_scale logic to ensure third-party or custom scales continue to work without modification.
    • Vectorization: Although the original issue focused on the API shift, I identified a small gap in possible performance. I designed the new val_in_range implementations to be vectorized using NumPy.
      • In common scales like LogScale and LogitScale, this replaces iterative logic/clipping with direct boolean math (e.g., val > 0).
      • This allows for high-performance domain checking on large arrays, whereas the previous approach was primarily scalar-focused.
        Update: Vectorization has been removed after review since it was not deemed necessary for the current use case and added unneeded complexity without clear benefit.

Example

import numpy as np
from matplotlib.scale import LogScale

s = LogScale(axis=None)
data = np.array([-1, 0, 1, 2])

# New API
for val in data:
    print(s.val_in_range(val), end=" ")
# Expected: False False True True

AI Disclosure

I used an AI assistant to understand the codebase structure only.

PR checklist

  • "closes #0000" is in the body of the PR description to link the related issue
  • new and changed code is tested
  • [N/A] Plotting related features are demonstrated in an example
  • [ N/A] New Features and API Changes are noted with a directive and release note
  • Documentation complies with general and docstring guidelines

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
null-dreams added 5 commits March 15, 2026 04:52
@null-dreams
scale: add ScaleBase.val_in_range for domain validation
c3df005
Introduce a val_in_range method in ScaleBase to explicitly check whether
values lie within the valid domain of a scale. The default
implementation falls back to limit_range_for_scale for compatibility
with existing scales.

Specific scales (e.g., LogScale, LogitScale) override this method with
more efficient checks.
@null-dreams
typing: add ScaleBase.val_in_range to scale.pyi
f91d2b4
@null-dreams
axis: add Axis.val_in_range to delgate the domain check
926c259
@null-dreams
typing: add Axis.val_in_range to axis.pyi
e3dc7b7
@null-dreams
axes: modify _point_in_data_domain to use the new Axis.val_in_range
6feeec1
@github-actions github-actions Bot added topic: ticks axis labels topic: transforms and scales topic: axes labels Mar 14, 2026
@github-actions

github-actions Bot commented Mar 14, 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.

You can also join us on gitter 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.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@github-actions github-actions Bot added the first-contribution label Mar 14, 2026
@github-project-automation github-project-automation Bot added this to First Time Contributors Mar 14, 2026
@null-dreams

null-dreams commented Mar 14, 2026

Copy link
Copy Markdown
Contributor Author

I would like some advice regarding implementing tests for the added function val_in_range and formatting the docstrings and documentations. Thank you.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@null-dreams null-dreams changed the title [MNT]: Implement Scale.val_in_range and refactor _point_in_data_domain [MNT]: Implement Scale.val_in_range and refactor _point_in_data_domain Mar 14, 2026
timhoffm
timhoffm reviewed Mar 15, 2026
View reviewed changes

@timhoffm timhoffm left a comment •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Your type usage is mixed up. In _pint_in_data_domain we just need a bool. You implementations return arrays. Your type stub claims bool | array return type. Since we only need single values, let's keep it simple and only implement that. We can always expand later.

Concerning tests: Write tests for all implemented subclasses. Consider edge cases like Inf and NaN

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread lib/matplotlib/axis.py Outdated
"""
return self._scale.limit_range_for_scale(vmin, vmax, self.get_minpos())

def val_in_range(self, val):

@timhoffm timhoffm Mar 15, 2026

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

What is the motivation to expose this on the Axis?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@null-dreams null-dreams Mar 15, 2026

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

I noticed limit_range_in_scale being available in Axis class, so exposing the val_in_range seemed consistent to me. But I later forgot to implement the wrapper in _point_in_data_domain.

I have two possible approaches here:

  1. Keep the wrapper exposed in Axis and use it in the _point_in_data_domain.
  2. Remove the wrapper from Axis and keep the current _point_in_data_domain, using the _scale attribute, unchanged.

After going through other exposed apis, I feel removing the wrapper here would be fine as currently there is no other use of val_in_range except in _point_in_data_domain.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

timhoffm reacted with thumbs up emoji
All reactions
  • 👍 1 reaction
Comment thread lib/matplotlib/scale.py
Comment on lines +119 to +120
Return whether the value(s) are within the valid range for this scale.
"""

@timhoffm timhoffm Mar 15, 2026

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Suggested change
Return whether the value(s) are within the valid range for this scale.
"""
Return whether the value(s) are within the valid range for this scale.
This method is a generic implementation. Subclasses may implement
more efficent solutions for their domain.
"""

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread lib/matplotlib/scale.py
Comment on lines +211 to +213
"""
Return `True` for all values.
"""

@timhoffm timhoffm Mar 15, 2026

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

The docstring should always descripe the concept, not just the imlementation. A docstring

def some_func():
    """Return True."""
    return True

has zero information conent.

Instead do:

Suggested change
"""
Return `True` for all values.
"""
"""
Return whether the value(s) are within the valid range for this scale.
This is True for all inputs.
"""

The first sentence should be in all val_in_range docs.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@null-dreams null-dreams Mar 15, 2026

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

This was actually pretty enlightening. Kind of changed the way I thought about docstrings.
I'm making the needed changes. Thank you very much for the suggestion.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

timhoffm reacted with thumbs up emoji wyattscarpenter reacted with rocket emoji
All reactions
  • 👍 1 reaction
  • 🚀 1 reaction
null-dreams added 2 commits March 15, 2026 14:27
@null-dreams
scale: refactor val_in_range to accept scalar values and return a s…
631a52f
…ingle bool
@null-dreams
typing: refactor Scale.val_in_range to reflect the type changes
d62a69f
@null-dreams

null-dreams commented Mar 15, 2026

Copy link
Copy Markdown
Contributor Author

I've made the changes which I think should fix the type ambiguity I caused earlier. I will need a little time to implement the tests as I have never written tests before and will need to study the current tests before I can implement mine and fix all the linting error with it as well.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@null-dreams

null-dreams commented Mar 15, 2026

Copy link
Copy Markdown
Contributor Author

While working on this I noticed a couple of behaviors that I wanted to clarify.

For LinearScale, calling limit_range_for_scale with NaN values returns NaN unchanged:

Example code:

from matplotlib.scale import LinearScale

s = LinearScale(axis=None)

vmin, vmax = s.limit_range_for_scale(float('nan'), float('nan'), minpos=1e-100)
print(vmin, vmax)

which results in nan nan. This seems to indicate that limit_range_for_scale does not attempt to reject or normalize NaN for the linear scale. Is this intentional?


Similarly for LogScale, limit_range_for_scale allows +inf to pass through unchanged. As far as I know, the logarithm is defined for 0 < x < +inf, but +inf itself is not part of the domain. I just needed a small clarification on whether +inf will be allowed in val_in_range or not.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@timhoffm

timhoffm commented Mar 16, 2026

Copy link
Copy Markdown
Member

This is a difficult question. Without having looked into this, I suspect, one of the two is correct:

  • it's unintentional, but does not matter for the current use cases limit_range_for_scale
  • it's intentional, because we want non-finite values to pass through for the current use cases

Which one it is needs to be found out by looking at the current usage contexts. In either case, the behavior should be specified.

null-dreams reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@melissawm melissawm moved this to Waiting for author in First Time Contributors Mar 16, 2026
null-dreams added 2 commits March 18, 2026 16:40
@null-dreams
tests: add test cases for val_in_range for different scales
59bd52b
@null-dreams
refactor: remove 'val_in_range' from axis.py and the corressponding p…
6d03949
…yi file
@github-actions github-actions Bot removed the topic: ticks axis labels label Mar 18, 2026
@timhoffm

timhoffm commented Mar 18, 2026

Copy link
Copy Markdown
Member

Thinking about it, the primary use for val_in_range is to determine whether a value is "compatible" with the scale, e.g. whether i can draw it (under the boundary condition of properly chosen limits.
In that sense, NaN and Inf values are not compatible. I therefore propose to return False for these cases. For example LinearScale would return math.isfinite(val).

null-dreams reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

null-dreams added 2 commits March 19, 2026 01:56
@null-dreams
refactor: add finite bound check for base class and implemented classes
b78b003
@null-dreams
tests: edited test cases to fit the new requirements
3de6b1f
@null-dreams

null-dreams commented Mar 18, 2026

Copy link
Copy Markdown
Contributor Author

I have added the finite bound check for the ScaleBase as well as LinearScale, LogScale and LogitScale and also edited the tests to match the new requirements.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@melissawm melissawm moved this from Waiting for author to Needs review in First Time Contributors Mar 18, 2026
@null-dreams
null-dreams marked this pull request as ready for review March 19, 2026 03:53
timhoffm
timhoffm approved these changes Mar 19, 2026
View reviewed changes
Comment thread lib/matplotlib/scale.py Outdated
Comment on lines +434 to +437
if not math.isfinite(val):
return False
else:
return val > 0

@timhoffm timhoffm Mar 19, 2026

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Same logic, but more compact.

Suggested change
if not math.isfinite(val):
return False
else:
return val > 0
return math.isfinite(val) and val > 0

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

null-dreams reacted with thumbs up emoji
All reactions
  • 👍 1 reaction
@null-dreams
refactor: compact function body in LogScale
c35268f
QuLogic
QuLogic reviewed Mar 20, 2026
View reviewed changes
Comment thread lib/matplotlib/scale.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread lib/matplotlib/scale.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread lib/matplotlib/scale.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

@melissawm melissawm moved this from Needs review to Waiting for author in First Time Contributors Mar 20, 2026
@null-dreams
refactor: made changes as suggested by reviewer
6b820a8
@QuLogic QuLogic added this to the v3.11.0 milestone Mar 20, 2026
QuLogic
QuLogic approved these changes Mar 20, 2026
View reviewed changes
@QuLogic
QuLogic merged commit 7c94eb0 into matplotlib:main Mar 20, 2026
41 checks passed

Uh oh!

There was an error while loading. Please reload this page.

@github-project-automation github-project-automation Bot moved this from Waiting for author to Merged in First Time Contributors Mar 20, 2026
@QuLogic

QuLogic commented Mar 20, 2026

Copy link
Copy Markdown
Member

Thanks @null-dreams! Congratulations on your first PR to Matplotlib 🎉 We hope to hear from you again.

null-dreams reacted with heart emoji
All reactions
  • ❤️ 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@scottshambaugh scottshambaugh mentioned this pull request May 22, 2026
[Bug]: Corruption of 3D surface plot at log scale with negative or zero values (v3.11.0rc2) #31726
Closed
@rahulrathnavel rahulrathnavel mentioned this pull request May 22, 2026
[Bug]: Fix 3D surface corruption on non-linear scales by masking invalid values #31733
Closed
2 of 3 tasks
@thc1006 thc1006 mentioned this pull request Jul 28, 2026
[Bug]: a scalar-only custom scale silently blanks all 3D data instead of drawing it #32129
Open
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@QuLogic QuLogic QuLogic approved these changes
@timhoffm timhoffm timhoffm approved these changes

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

first-contribution topic: axes topic: transforms and scales

Projects

First Time Contributors
Status: Merged

Milestone

v3.11.0

Development

Successfully merging this pull request may close these issues.

[MNT]: Scale val_in_range method

Uh oh!

There was an error while loading. Please reload this page.

3 participants

@null-dreams @timhoffm @QuLogic
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402520 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.