[BUG]: NaT inside a datetime64 array serializes as the string "NaT" instead of null
Maintainer antworten meist innerhalb von 3 Tagen
Bewertung
- Schwierigkeit
- 2/5
- Geschätzter Aufwand
- 1-3 Stunden
- Anfängerfreundlichkeit
- 82/100
- Issue-Typ
- Bug
- Klarheit
- Klar beschrieben
- Aktivitätsstatus
- Aktiv
- Bereich
- backend, data-visualization
Rechercherichtung
Lies plotly/_plotly_utils/utils.py im Umfeld von encode_as_numpy und plotly/io/_json.py im Umfeld von clean_to_json_compatible; beide Pfade konvertieren derzeit datetime64-Arrays mit numpy.datetime_as_string. Füge den datetime64-Fall neben test_pandas_json_encoding in tests/test_optional/test_utils/test_utils.py hinzu und prüfe anschließend beide JSON-Engines und Roundtrips. Fertig ist die Aufgabe, wenn NaT-Arrayelemente als null serialisiert werden und beim Roundtrip null bleiben.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Beschreibung
Description
At 38374ac, a NaT inside a datetime64 array serializes as the string "NaT" on both engines. The same missing value as a list element or a scalar becomes null, and from_json reads the string back as data.
$ python -I repro.py # 38374ac, pandas 3.0.6, numpy 2.5.4, orjson 3.13.0
stored : ndarray datetime64[us]
json series -> ['2020-01-01T00:00:00.000000', 'NaT']
json list -> ['2020-01-01T00:00:00', None]
json scalar -> null
json round -> ['2020-01-01T00:00:00.000000', 'NaT']
orjson series -> ['2020-01-01T00:00:00.000000', 'NaT']
orjson list -> ['2020-01-01T00:00:00', None]
orjson scalar -> null
orjson round -> ['2020-01-01T00:00:00.000000', 'NaT']
plotly.js happens to draw a gap for the string, so a chart looks right. Anything else that reads the figure JSON, such as Dash figure State, gets a string where null belongs.
Screenshots/Video
None: the defect is in the serialized JSON, quoted above.
Steps to reproduce
import json
import pandas as pd
import plotly.graph_objects as go
import plotly.io as pio
from plotly.io._json import to_json_plotly
series = pd.Series(pd.to_datetime(["2020-01-01", None]))
fig = go.Figure(go.Scatter(x=series))
print("stored :", type(fig.data[0].x).__name__, fig.data[0].x.dtype)
fig2 = go.Figure(go.Scatter(x=[pd.Timestamp("2020-01-01"), pd.NaT]))
for e in ("json", "orjson"):
print(e, "series ->", json.loads(pio.to_json(fig, engine=e))["data"][0]["x"])
print(e, "list ->", json.loads(pio.to_json(fig2, engine=e))["data"][0]["x"])
print(e, "scalar ->", to_json_plotly(pd.NaT, engine=e))
print(e, "round ->", list(pio.from_json(pio.to_json(fig, engine=e), engine=e).data[0].x))
Notes
contract: tests/test_optional/test_utils/test_utils.py:276 already asserts null for pd.NaT inside an object-dtype Series, and :291 asserts "[null]" for [pd.NaT]. The datetime64 dtype of that same Series breaks the promise. The scalar case is tests/test_io/test_to_from_plotly_json.py:265.
The json engine (the auto fallback when orjson is absent) goes through encode_as_numpy at _plotly_utils/utils.py:297, and orjson goes through clean_to_json_compatible at plotly/io/_json.py:517. Both call datetime_as_string unfiltered:
- return numpy.datetime_as_string(obj).tolist()
+ return [
+ None if s == "NaT" else s
+ for s in numpy.datetime_as_string(obj).tolist()
+ ]
$ python -I repro.py | grep -E "series|round" # filter at utils.py:297 only
json series -> ['2020-01-01T00:00:00.000000', None]
json round -> ['2020-01-01T00:00:00.000000', None]
orjson series -> ['2020-01-01T00:00:00.000000', 'NaT']
orjson round -> ['2020-01-01T00:00:00.000000', 'NaT']
$ python -I repro.py | grep -E "series|round" # same filter at _json.py:517 too
json series -> ['2020-01-01T00:00:00.000000', None]
json round -> ['2020-01-01T00:00:00.000000', None]
orjson series -> ['2020-01-01T00:00:00.000000', None]
orjson round -> ['2020-01-01T00:00:00.000000', None]
# reverted: all four lines print 'NaT' again
No CODEOWNERS entry covers these paths. @camdecoster, would you take a PR with the filter at both sites and a datetime64 case next to test_pandas_json_encoding?
- Vorherrschende Sprache
- Python
- Sterne
- 18.9k
- Forks
- 2.9k
- Ø Merge
- 5 T. 1 Std.
- Gemergte PRs (30 T.)
- 14
Entwicklungsumgebung
- Kein Dockerfile und keine Docker-Compose-Datei
- Hat eine Pull-Request-Vorlage
- Beitragsleitfaden lesen
Erste Schritte
- Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
- Forken Sie das Repository und arbeiten Sie in einem Branch.
- Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.
Mehr aus plotly/plotly.py
-
to_typed_array_spec encodes bdata in host byte order; plotly.js always decodes it as little-endianEvtl. vergeben @Vikram12301 hat das vor 1 Tag übernommen. Offen
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 79/100
Maintainer antworten meist innerhalb von 3 Tagen
-
[BUG]: Integer and string properties reject NumPy scalarsEvtl. vergeben @RaphaelFakhri hat das vor 4 Tagen übernommen. Offenbug P3 size: 1
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 70/100
plotly/plotly.py#5827 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 3 Tagen
-
[BUG]: Single-color requests raise ZeroDivisionError in palette helpersEvtl. vergeben @MokiMeow hat das vor 13 Tagen übernommen. Offenbug P3 size: 1
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 82/100
plotly/plotly.py#5805 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 3 Tagen
-
[BUG]: Unnecessary `UserWarning` when using `fig.write_image()` with `kaleido.start_sync_server()`Evtl. vergeben @jayzhou2309 hat das vor 21 Tagen übernommen. Offenbug P3 size: 1
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 74/100
plotly/plotly.py#5786 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 3 Tagen
-
P3 size: 1 task
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 65/100
plotly/plotly.py#5769 · 1 Reaktion ·
Maintainer antworten meist innerhalb von 3 Tagen
Alle Issues in plotly/plotly.py
Ähnliche Issues
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 76/100
aws-samples/sample-per-model-bedrock#464 ·
Maintainer antworten meist innerhalb von 1 Tag
-
lesson-submission pending-review
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 67/100
Ikalus1988/MisakaNet#3789 ·
Maintainer antworten meist innerhalb von 1 Tag
-
Python Volcengine provider returns failures instead of raising themEvtl. vergeben @Ricardo-M-L hat das heute übernommen. Offen
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 79/100
agent-infra/sandbox#248 ·
-
[Bug] cloud JSON directory loading assumes a Key field in fsspec listingsEvtl. vergeben @Ricardo-M-L hat das heute übernommen. Offen
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 88/100
hiyouga/LlamaFactory#10910 ·
Maintainer antworten meist innerhalb von 1 Tag
-
Bundled uv is never updated and trusts the compromised eMudhra certificatesEvtl. vergeben @FabienDanieau hat das heute übernommen. Offenbug
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 76/100