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

Đang mở
#1,963 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

Chưa có ai nhận issue này.

Đánh giá

Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức phù hợp với người mới
48/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Ít trao đổi
Công nghệ
pandas, python
Lĩnh vực
data-visualization

Hướng nghiên cứu

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.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

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-113 assign(weight=..., same_community=...) overwrites an existing user weight column and injects a permanent same_community boolean into the caller's edge table; :116 rebinds edge_weight='weight'.
  • :98-99 assert 'source_community' not in g._edges / 'destination_community' — a user edge frame that already has either column gets a bare AssertionError (and under python -O the check vanishes and :102-103 then produce duplicate column names).
  • :91 raise ValueError(f'Unsupported engine: {engine}') prints the abstract argument rather than engine_concrete, so engine='auto' reports Unsupported 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.

Ngôn ngữ chính
Python
Star
2.6k
Fork
229
Merge trung bình
1 ngày 5 giờ
Pull request đã merge (30 ngày)
99

Chuẩn bị môi trường

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của graphistry/pygraphistry

Tất cả issue của graphistry/pygraphistry

Issue tương tự

Thêm issue về Python

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.