layout: modularity_weighted_layout silently DELETES edges with a dangling endpoint (inner merge), KeyErrors on an edge column named like _node, and emits no positions
Los mantenedores suelen responder en 1 día
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 4/5
- Tiempo estimado
- 3-5 días
- Aptitud para principiantes
- 48/100
- Tipo de issue
- Error
- Claridad
- Bien especificado
- Estado de actividad
- Tranquilo
- Área
- data-visualization
Línea de trabajo
Start in graphistry/layout/modularity_weighted/modularity_weighted.py, especially the merges at lines 101–104 and edge assignments at 107–116; compare sibling layout validation behavior. Reproduce the dangling-endpoint and edge-column collision cases in tests, and check the documented position contract in docs/source/gfql/spec/llm_guide.md. Done means the edge cases and layout contract are handled consistently, with tests covering the behavior.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Found by the 2026-08 layouts/viz amplification probe. Repros on master @ 42b4f7f7d, pandas 2.3.3 / py3.12.
modularity_weighted_layout() rewrites the caller's edge frame through two unqualified .merge() calls. Because merge defaults to how='inner', edges are silently deleted; because the merge keys are not disambiguated, a benign column name in the edge frame turns into a KeyError.
graphistry/layout/modularity_weighted/modularity_weighted.py:101-104:
101: edges = (g._edges
102: .merge(g._nodes[[community_col, g._node]], left_on=g._source, right_on=g._node)
.rename(columns={community_col: 'source_community'}).drop(columns=[g._node])
103: .merge(g._nodes[[community_col, g._node]], left_on=g._destination, right_on=g._node)
.rename(columns={community_col: 'destination_community'}).drop(columns=[g._node])
104: )
and the result is bound as the graph's edges at :116.
Defect 1 (silent-wrong): edges whose endpoint is missing from _nodes are deleted without a word
import pandas as pd, graphistry
e = pd.DataFrame({'s': ['a','b','z'], 'd': ['b','a','a']}) # 'z' is not in _nodes
n = pd.DataFrame({'id': ['a','b'], 'comm': [0, 1]})
out = graphistry.edges(e,'s','d').nodes(n,'id').modularity_weighted_layout(community_col='comm')
print(len(e), '->', len(out._edges))
Observed: 3 -> 2 — the z->a edge is gone, no warning, no error.
Expected: either all 3 edges preserved (with a null/cross_community_weight community), or a typed decline naming the dangling endpoint.
This is the mirror image of the #1944 shape: there a node survived while its edges were dropped; here an edge is dropped while both frames look fine. Note the sibling layouts do reject the same graph loudly — layout_igraph('fr') and group_in_a_box_layout() both raise ValueError: Some vertices in the edge DataFrame are missing from vertices DataFrame. So this is also a surface divergence: three layouts, same input, one silently mutilates it.
The inverse also holds and is untested: duplicate ids in _nodes make the same inner merge fan out each edge into multiple rows.
Defect 2 (bare-crash): an edge column that shares the node-id column name
import pandas as pd, graphistry
e = pd.DataFrame({'s': ['a','b'], 'd': ['b','a'], 'id': [10, 11]}) # edges carry their own 'id'
n = pd.DataFrame({'id': ['a','b'], 'comm': [0, 1]})
graphistry.edges(e,'s','d').nodes(n,'id').modularity_weighted_layout(community_col='comm')
Observed: KeyError: "['id'] not found in axis" — the merge emitted id_x/id_y, so drop(columns=[g._node]) at :102 cannot find id.
Expected: a suffix-safe merge, or a typed error naming the collision.
An id column on edges is entirely ordinary (it is what g.edges(df, 's', 'd', 'id') binds), so this is a routine input.
Defect 3 (contract): the "layout" produces no positions
Despite the name and its listing under Layouts in docs/source/gfql/spec/llm_guide.md:548, the function only sets layout_settings(edge_influence=...) and an edge weight column (:96, :107-116). It emits no x/y at all:
out = g.modularity_weighted_layout()
'x' in out._nodes # False
Every other entry in that list writes x/y. Either the docs/schema_effects should say "edge weights + settings only, positions come from the server", or the function should produce positions. As it stands, g.modularity_weighted_layout() followed by a local position read silently yields nothing.
Defect 4 (minor): silent overwrites and bare asserts on user data
:107-113assign(weight=..., same_community=...)overwrites an existing userweightcolumn and injects a permanentsame_communityboolean into the caller's edge table;:116rebindsedge_weight='weight'.:98-99assert 'source_community' not in g._edges/'destination_community'— a user edge frame that already has either column gets a bareAssertionError(and underpython -Othe check vanishes and:102-103then produce duplicate column names).:91raise ValueError(f'Unsupported engine: {engine}')prints the abstract argument rather thanengine_concrete, soengine='auto'reportsUnsupported engine: EngineAbstract.AUTO.
Category
Defect 1: silent-wrong + surface-divergence. Defect 2: bare-crash on valid input. Defect 3: docs/contract divergence. Defect 4: bare asserts on user data.
Not exercised
cuDF arm not run (cugraph not installed here). By inspection :106-108 same_community.map({True: ..., False: ...}) is a pandas-dict-map form that cuDF handles unreliably for booleans and polars does not have at all — INDICATIVE, static only. Polars is covered separately in the engine-parity report.
- Lenguaje dominante
- Python
- Estrellas
- 2.6k
- Forks
- 229
- Merge medio
- 1 d 5 h
- PR fusionados (30 d)
- 100
Preparar el entorno
- Sin Dockerfile ni archivo de Docker Compose
- Tiene una plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de graphistry/pygraphistry
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 62/100
graphistry/pygraphistry#2171 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
graphistry/pygraphistry#1965 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 65/100
graphistry/pygraphistry#1208 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
graphistry/pygraphistry#966 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
graphistry/pygraphistry#824 ·
Los mantenedores suelen responder en 1 día
Todos los issues de graphistry/pygraphistry
Issues similares
-
area:scripts area:tests bug priority:later
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
Ikalus1988/MisakaNet#4358 ·
Los mantenedores suelen responder en 1 día
-
Discovered ports from service discovery are never propagated to modules in Module.load()Posiblemente ocupada @vishalmore90 la tomó hoy. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 70/100
OWASP/Nettacker#1828 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 88/100
aws-samples/sample-per-model-bedrock#708 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
-
[Performance] Bound resolve_api_hashes raw fallback reads to the 1 MiB region actually scannedAbierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
sjkim1127/Reversecore_MCP#365 ·
Los mantenedores suelen responder en 1 día