layout: mercator_layout emits -inf / NaN positions for |lat| >= 90 with no validation (and the two poles are asymmetric)
I maintainer di solito rispondono entro 1 giorno
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Idoneità per principianti
- 48/100
- Tipo di issue
- Bug
- Chiarezza
- Specificata chiaramente
- Stato di attività
- Tranquilla
- Ambito
- backend, data-visualization
Direzione di ricerca
Start with graphistry/layout/mercator.py, especially lines 70–111, and compare its position checks with circle.py:362-363; reproduce the latitude cases in the issue. Check numeric-input validation and the described cuDF fallback as part of the scope. Done means invalid or non-numeric coordinates are handled deliberately, valid positions remain finite, and tests cover the reported cases.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Found by the 2026-08 layouts/viz amplification probe. Repros on master @ 42b4f7f7d, numpy 2.2.6 / pandas 2.3.3 / py3.12.
mercator_layout() applies the Mercator formula with no domain validation and writes whatever falls out — -inf, +23810, or NaN — straight into the bound x/y columns.
graphistry/layout/mercator.py:107-111:
107: lat_rad = np.radians(lat_deg)
108: lon_rad = np.radians(lon_deg)
110: x_vals = R * lon_rad
111: y_vals = R * np.log(np.tan(np.pi / 4 + lat_rad / 2))
Mercator is undefined at the poles and outside [-90, 90]; there is no clamp, no range check, and no post-assert (contrast circle.py:362-363, which does assert non-NaN positions).
Repro
import pandas as pd, graphistry
e = pd.DataFrame({'s':[0,1,2], 'd':[1,2,0]})
def run(label, lat, lon):
n = pd.DataFrame({'id':[0,1,2], 'lat':lat, 'lon':lon})
out = (graphistry.edges(e,'s','d').nodes(n,'id')
.bind(point_latitude='lat', point_longitude='lon')
.mercator_layout())
print(label, out._nodes['y'].tolist())
run('poles ', [90.0, -90.0, 0.0], [0.,0.,0.])
run('lat=200 ', [200.0, 0., 0.], [0.,0.,0.])
run('lat=NaN ', [37.7, float('nan'), 51.5], [-122.4, -74.0, -0.1])
Observed
poles [23810.77, -inf, -0.0]
lat=200 [nan, -0.0, -0.0]
lat=NaN [453.71, nan, 671.02]
Expected: a typed decline naming the out-of-domain latitude, or the standard Web-Mercator clamp to ±85.051129°, which is what every mapping library does. Whatever the choice, -inf should never reach a position column.
Note the pole case is also asymmetric: lat=+90 gives a large finite 23810.77 (floating-point tan(π/2) is finite), lat=-90 gives -inf. The two poles are not mirror images, which is a numerical artifact rather than a design decision.
Why inf/NaN in a position column is not benign
-infinx/ydestroys zoom-to-fit and any bounds computation over the node frame.- Non-finite floats do not survive JSON: #1960 documents that NaN/inf leaks a
requests.InvalidJSONErrorout of the remote path.mercator_layout()is a supported way to produce exactly that from data that looks entirely valid. |lat| > 90producingNaNwith only a numpy RuntimeWarning is a silent-wrong: bad input is accepted and turned into an unpositioned node rather than rejected.
Out-of-range latitude is not exotic — it is what you get from a lat/lon column swap, from projected coordinates mistaken for degrees, or from a sentinel value like 999.
Secondary (bare-crash): non-numeric lat/lon dies deep in numpy
n = pd.DataFrame({'id':[0,1,2], 'lat':['37.7','40.7','51.5'], 'lon':['-122.4','-74.0','-0.1']})
graphistry.edges(e,'s','d').nodes(n,'id').bind(point_latitude='lat', point_longitude='lon').mercator_layout()
Observed: TypeError: loop of ufunc does not support argument 0 of type str which has no callable radians method
Expected: a typed error at the binding check (mercator.py:70-71 already validates that the columns exist; it does not validate that they are numeric).
Secondary (dead fallback): the advertised cupy→numpy fallback cannot work
mercator.py:82-87 warns "cuDF DataFrame detected but cupy is not available. Falling back to NumPy (CPU)", then the fallback at :103-104 does g._nodes[lat_col].values — which on a cuDF frame returns a cupy array, and np.radians on a cupy array raises TypeError: Implicit conversion to a NumPy array is not allowed. The documented fallback path is unreachable-as-intended. INDICATIVE — stated from inspection; not executed, since cupy in this environment cannot load libnvrtc.so.12 and the cuDF-without-cupy combination could not be constructed.
(The polars misrouting at mercator.py:73 is filed separately in the layout engine-parity issue.)
Category
silent-wrong (non-finite and NaN positions accepted and emitted, no warning) + bare-crash on non-numeric input.
- Lingua principale
- Python
- Stelle
- 2.6k
- Fork
- 229
- Merge medio
- 1g 5h
- PR unite (30g)
- 100
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di graphistry/pygraphistry
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 62/100
graphistry/pygraphistry#2171 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
graphistry/pygraphistry#1965 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 65/100
graphistry/pygraphistry#1208 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
graphistry/pygraphistry#966 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
graphistry/pygraphistry#824 ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di graphistry/pygraphistry
Issue simili
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
Nixtla/mlforecast#823 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 65/100
microsoft/ML-For-Beginners#1061 ·
-
bot-found documentation priority: P3
Difficoltà 2/5 Meno di un'ora Idoneità per principianti 82/100
madenvel/KalinkaPlayer#503 ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 63/100
EleutherAI/lm-evaluation-harness#4508 ·
I maintainer di solito rispondono entro 1 giorno