Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

POC: Add validation of converters to formatters#25766

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Draft
ksunden wants to merge3 commits intomatplotlib:main
base:main
Choose a base branch
Loading
fromksunden:converter_formatter_validate

Conversation

ksunden
Copy link
Member

PR Summary

This is an alternative implementation of#25662, validating in the opposite direction
Closes#24951

In#25662, the converter holds reference to what formatters are valid.
Here, The formatter holds reference to what converters are valid.

Another difference in implementation is that the validators raise rather than return
boolean.

With respect to the original report (#24951), with current main of nc-time-axis there is
no change in behavior (no warning, produces incorrect dates). With the change proposed
inSciTools/nc-time-axis#127, it errors on validation. Their provided formatters will
provide no validation, but also will not fail
(until they implement the validator method)

ping@spencerkclark for nc-time-axis's stake in this

It is pretty minimal and easy, but tests currently fail because of the jpl_units EpochConverter.
EpochConverter does not inherit from DateConverter, butis compatible (the inverse of current main of nc-time-axis).

Since we are pretty strict about not changing the jpl units, I'm looking for some other ideas...

A couple ideas:

  • Useconverter.axis_info, and automatically allow the type returned from that (for maj or min).
    • This would work for at leastmost of the tests, but is still a bit fragile
    • e.g. jpl's EpochConverter returns AutoDateFormatter, but would still be valid withDateFormatter orConciseDateFormatter, but that can't be teased out from axis_info
  • Find a test forDateFormatters which does not rely onisinstance
    • This is hard if because the formatter cares about attributes of the output of converters, not their internal representation
    • Could do something liketry: assert converter.convert(datetime.date(...), ...) == ...; except: raise ...
      • (may not want to actually useassert forpython -O reasons, but same idea)
  • Only warn, rather than error, and adjust the tests to expect that warning.
    • Has the advantage of not actually changing behavior/not preventing people from doing things

PR Checklist

Linked Issue

  • Added "closes #0000" in the PR description to link it to the original issue.

Documentation and Tests

  • Has pytest style unit tests (andpytest passes)
  • Documentation is sphinx and numpydoc compliant (the docs shouldbuild without error).
  • New plotting related features are documented with examples.

Release Notes

  • New features are marked with a.. versionadded:: directive in the docstring and documented indoc/users/next_whats_new/
  • API changes are marked with a.. versionchanged:: directive in the docstring and documented indoc/api/next_api_changes/
  • Release notes conform with instructions innext_whats_new/README.rst ornext_api_changes/README.rst

@ksunden
Copy link
MemberAuthor

The idea of "just see if you can convert a datetime" doesn't work because the JPL units don't takein datetime objects, but rather their own units (in hindsight, this is actually pretty obvious)... they just output something that is compatible with the DateFormatters...

I also think that warning on actually compatible combinations is still rather unacceptable, while less bad than erroring.

axisinfo is actually a pretty interesting way of resolving it... my original thought was to somehow make it so thatany converter that provides axisinfo of a particular formatter would work, but that breaks down with the inheritance structure of mpl.dates formatters.... but if we instead do this only for date converters (and of course, other formatters could do similar things):

defvalidate_converter(self,converter):ifnotisinstance(converter.axisinfo(None,None).majfmt, (DateFormatter,AutoDateFormatter)):_api.warn_external(f"Expected a DateConverter for DateFormatter, got{type(converter)}"            )

Modulo perhaps some tweaks like paying attention to either minor or major formatter, or the error message text, this actually passes tests, including JPL units related tests.

But it still relies on passing insomething to the "unit" field ofaxisinfo (I just passed None, as for our internal converters the units field is actually unused for this purpose.

nc-time-axis will error on that call (either with or without breaking inheritance), which is kind of right (they are incompatible), but also kind of not (precludes a more informative error, and a valid converter could be made which does not acceptNone as a unit), and thus is probably indicative that perhaps this is still too fragile.

Adding a call toconverter.default_units runs into similar problems of any particular value ofx not being valid as an input for all converters (and reintroduces at least a subset of errors for jpl units).

So I've gone down a number of paths here and it is feeling like a bit of a stalemate, not sure how to draw the lines to include only the things we want to include, and feeling like perhaps an assertive runtime check is not necessisarily what we actually want.

@ksunden
Copy link
MemberAuthor

Okay I've gone down the path of using axis info, though caching the value in a private variable instead of recomputing from the converter in the validator.

Axis info is passed every time the validator is called, though of course a given validator may ignore it.

In addition, a new field has been added to AxisInfo, called"description" (though opinions on a better name are welcome) This is used to opt-in tonot warning formpl.dates.DateFormatter in a way that is independent of class hierarchy. Currently it does a specific string equality check, but that could be relaxed to substring check or a delimited check (e.g.; separated descriptors) or something of the like.

As for behavior of downstream:

  • nc-time-axis (correctly) warns onboth main and the branch that breaks the subclass hierarchy, meaning that change is not necessary (though may still be warranted, given it isn't actually benefiting from inheritance)
  • Pandas' DatetimeConverter, which is compatible with mpl formatters warns currently (which causes test failures both there and a single failure here where we import pandas(so only if pandas is installed))
    • it is a warning not an error, but warnings are set to fail tests
    • It is relatively easy to patch pandas to work:
diff --git a/pandas/plotting/_matplotlib/converter.py b/pandas/plotting/_matplotlib/converter.pyindex 9b0fe99e2d..3b8adaddaf 100644--- a/pandas/plotting/_matplotlib/converter.py+++ b/pandas/plotting/_matplotlib/converter.py@@ -337,7 +337,8 @@ class DatetimeConverter(mdates.DateConverter):         datemax = pydt.date(2010, 1, 1)          return munits.AxisInfo(-            majloc=majloc, majfmt=majfmt, label="", default_limits=(datemin, datemax)+            majloc=majloc, majfmt=majfmt, label="", default_limits=(datemin, datemax),+            description="days since matplotlib epoch"         )

(Though would probably need to version-gate mpl until they bump the minver of mpl)

Currently I minimally add to the included jpl units EpochConverter to opt in to the date formatter.

In looking into this I discovered that the jpl units Epoch class/converter are actually incorrect in a couple of ways, most notably an off by one error that has seemingly been around since the beginning.

All of our examples pass indatetime objects, which get converted usingmpl.dates.date2num and so are actually correct internally, but get an off by one applied in the convert step. But I suspect the original intention was for other constructors of those units to have the old origin. This interpretation is supported by comments and constants in these files. They are now treated as offsets from "1969-12-31T00:00" due to the off by 1 error.

The image tests of the jpl units are all actually incorrect (at least where dates are shown).

e.g.:

@image_comparison(['axvspan_epoch'])
deftest_axvspan_epoch():
importmatplotlib.testing.jpl_unitsasunits
units.register()
# generate some data
t0=units.Epoch("ET",dt=datetime.datetime(2009,1,20))
tf=units.Epoch("ET",dt=datetime.datetime(2009,1,21))
dt=units.Duration("ET",units.day.convert("sec"))
ax=plt.gca()
ax.axvspan(t0,tf,facecolor="blue",alpha=0.25)
ax.set_xlim(t0-5.0*dt,tf+5.0*dt)

This I would expect to have a vspan for the day of the 20th, but the image shows a vspan for the day of the 21st:

image

@story645
Copy link
Member

I have a possibly ridiculous question, but is this and the approach in#25662 mutually exclusive? I'm not totally following, but it seems like you're kinda trying to solve different but related problems with each of these approaches, and I'm wondering if different downstreams will need the validation in different places. Granted, I also really like your idea of registering formatters with convertors.

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers
No reviews
Assignees
No one assigned
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

[Bug]: Matplotlib date formatter and cftime and pandas incompatible ?
2 participants
@ksunden@story645

[8]ページ先頭

©2009-2025 Movatter.jp