Analyzes, visualizes, and explores network graphs via Gephi MCP tools. Activates on mentions of Gephi, network analysis, graph visualization, community detection, or social network analysis.
How this skill is triggered — by the user, by Claude, or both
Slash command
/gephi-network-analysis:gephiThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
*Skill version 1.9.31 — if commands or tools mentioned here seem missing, the installed plugin is outdated; see the README's Updating section.*
Skill version 1.9.31 — if commands or tools mentioned here seem missing, the installed plugin is outdated; see the README's Updating section.
You have access to 104 MCP tools (prefixed mcp__gephi-mcp__) for controlling Gephi Desktop. Use them to build, analyze, style, and export network graphs.
Always narrate what you're doing. Before each major tool call, tell the user what's about to happen in a short sentence (e.g., "Computing modularity...", "Running ForceAtlas 2 layout..."). This prevents the user from wondering what's happening during long operations.
"ForceAtlas 2" (with space and capitals), not "forceatlas2"file as the key, not pathmodularity_class and degree columns don't exist until you compute themnode.label.proportinalSize — note the typo (missing 'o'). This is Gephi's actual property name.project/new before importing — stale workspace state from prior operations can cause issues. A fresh project prevents this.edge.color: "source" colors edges individually — the plugin automatically colors each edge to match its source node's color and sets mode to ORIGINAL. This is safe and produces the watercolor halo effect.node.label.font supports multi-word names — e.g., "Courier New 12 Bold". The plugin parses everything before the first digit as the font name.viz:size values are automatically capped during import to prevent oversized nodes from hiding edges.remove_isolates, giant_component, filter_by_degree now properly refresh the preview model after modifying the graph.sync: true in gephi_run_layout — makes the call block until layout finishes. Always use this so Noverlap and Label Adjust don't start on a still-moving graph.gephi_health_check (stop if Gephi isn't running)gephi_create_project before importinggephi_import_file or build with gephi_add_nodes/gephi_add_edgesgephi_visual_qa with partition_column set. If the verdict is "none", the attribute does not match the topology and coloring by it would mislead; compute real communities with gephi_compute_modularity instead (and say so). When building demo/synthetic networks, wire real structure: preferential attachment within communities, hub-biased bridges between them, within-group edge share above 60% — never random edges with decorative group labels.edge.color set to source, edge.opacity 30-40) so edges carry community identity without noise. Exception: dense word co-occurrence graphs (text networks) — per-source edge coloring adds a second visual dimension on top of an already-high edge count and reads as busier, not clearer; use a flat neutral gray instead (see references/text-network-analysis.md).gephi_run_layout with "ForceAtlas 2" (linLogMode true, gravity 0), then run gephi_visual_qa and export a small PNG to inspect; fix every warning and adjust per references/layout-guide.md before finishing with "Noverlap" and "Label Adjust"gephi_set_preview_settings for export appearanceextent.suggested_export from gephi_visual_qa, then gephi_export_png (use file param), gephi_export_svg, etc. For interactive exploration in MCP Apps hosts (claude.ai, Claude Desktop), prefer gephi_view_graph — it renders an interactive view inline in the conversation (pass caption_column for floating cluster captions; the app offers per-node ask-Claude, ego highlighting, in-place refresh, and a time slider on dynamic graphs); use gephi_export_png for publication stills. When crafting a bespoke network diagram and the MCP App view is unavailable or unsuitable, build an interactive HTML/canvas artifact from gephi_export_gexf data (positions, colors, and sizes are baked in) instead of settling for a static PNG — reserve PNG for publication exports.When a human is watching the Gephi window while you work (teaching, demos, paired
analysis), switch to narrated pacing: announce each step and what to watch for
BEFORE doing it; use gephi_focus_view to direct their eyes (fit graph after
import/layout, center+select a cluster before discussing it); run layouts in
200-300 iteration chunks with narration between passes instead of one long blast;
pause after each visible change and invite their observations. The /teach command
codifies the full pattern. Watching the instrument operate is the pedagogy — never
do anything the viewer can't follow.
The person can point back. gephi_get_selection reads what they have selected
in the Gephi window. Whenever they use deictic words about the canvas — "these",
"this group", "the ones I selected" — read the selection FIRST and answer about
those exact nodes; never ask them to type node names. Box-drag selection is turned
on automatically at the start of a session, so just tell them they can drag a box
around nodes and the selection persists while they come back to the conversation —
no toolbar hunting. Hover highlighting is transient and does not register; the box
drag is the pointing gesture. (If a reply's rectangle_selection is false they
switched modes — the dashed-square icon in the thin left toolbar turns it back on.)
Close long sessions by naming the loop. A working session reshapes both sides; say so before ending. One or two sentences on what you now do differently because of them (a correction they made, a habit you adapted to, a reading of theirs that beat yours), and an invitation for the reverse. Where understanding matters (teaching, first analyses), test it by mutual teachback — they restate the map to you, you restate their domain to them, each side repairs the other — rather than by asking "does that make sense?"
The first turn decides the quality of everything after it. Two moves, always:
gephi_profile_graph — one call, the full quantitative picture
(size, density, degree distribution with Gini and assortativity,
components, isolates, weight distribution, modularity, clustering with its
random-graph expectation, auto-raised flags). You can absorb a dozen
simultaneous measurements better than most humans can; do it, then give a
short plain-language first reading that marries their description with the
numbers, and ask the 2-3 questions the profile raises. Three of its
numbers pick layout parameters before any render: weights.heavy_tailed
means log-transform weights (or lower edgeWeightInfluence) before a force
layout; strongly negative degree.assortativity means enable
distributedAttraction (dissuade hubs); clustering_vs_random is the
baseline-relative form of "highly clustered" — quote the ratio, never the
raw coefficient alone.The first reading is provisional by design — the goal is exploration, not conclusions. Success is measured by what the person notices next, not by how fast a verdict lands:
Then let both guide every downstream decision:
gephi-ai drives Gephi's plugin ecosystem, not just its built-ins (verified live):
gephi_list_layouts and runs by name (verified with Force Atlas 3D). Bundled
in core and always available: Noverlap (overlap-removal finishing pass),
OpenOrd (very large graphs), Label Adjust.gephi_list_statistics shows every metric including plugin
ones; gephi_run_statistic runs any of them by name (verified with the CWTS
Leiden plugin — recommend it over plain modularity for large networks).
Results land in columns; style with size/color-by-ranking or partition.Any data the conversation can read becomes a graph — no importer plugin needed.
With a file path (Claude Code / Cowork): gephi_import_file handles GEXF,
GraphML, GML, CSV, DOT, Pajek. Without a path (attachment in chat, API data,
pasted table): parse it yourself and batch gephi_add_nodes + gephi_add_edges
(chunk a few hundred per call). Shapes:
type
attribute, or project (edge between rows sharing a value).gephi_text_to_network builds a word co-occurrence
graph directly — don't hand-parse prose yourself. See
references/text-network-analysis.md before reporting any structural gap
as a finding.Then run the standard flow (stats -> style -> layout -> QA). This replaces what portal users install separate importer plugins for, and it works with formats those plugins never covered.
gephi_create_project, gephi_open_project, gephi_save_project, gephi_get_project_info, gephi_new_workspace, gephi_list_workspaces, gephi_switch_workspace, gephi_delete_workspace, gephi_duplicate_workspace, gephi_rename_workspace, gephi_snapshot (save a one-level undo point), gephi_undo (restore it)
gephi_add_node/gephi_add_nodes, gephi_add_edge/gephi_add_edges, gephi_remove_node/gephi_bulk_remove_nodes, gephi_remove_edge, gephi_clear_graph, gephi_set_node_label/gephi_set_edge_label, gephi_set_node_position/gephi_batch_set_positions, gephi_set_edge_weight, gephi_query_nodes, gephi_get_node, gephi_query_edges, gephi_text_to_network (builds a word co-occurrence graph from free text, with optional pos_filter="nouns", min_word_frequency, merge_phrases, exclude_self_referential/self_referential_threshold for document-frequency-based generic-hub detection, and context_snippets to attach real source-text excerpts to each flagged candidate for the gray-zone cases no threshold or word list can resolve — see references/text-network-analysis.md), gephi_extract_backbone (disparity-filter edge pruning — a principled alternative to a flat weight cutoff, see references/text-network-analysis.md)
gephi_compute_modularity → creates modularity_classgephi_compute_degree → creates degree, indegree, outdegreegephi_compute_betweenness → creates betweenesscentrality, closnesscentrality, eccentricity, harmonicclosnesscentrality (0.11.1+)gephi_compute_pagerank → creates pageranksgephi_compute_eigenvector → creates eigencentralitygephi_compute_connected_components → creates componentnumbergephi_compute_clustering_coefficient → creates clusteringgephi_compute_avg_path_length → avg path length, diametergephi_compute_hits → creates authority, hub (lowercase column names)gephi_profile_graph → one-call quantitative picture (size, density, degree with Gini + assortativity, connectivity, weight distribution, modularity, clustering vs random expectation); run first — its flags name layout fixes (heavy-tailed weights → log-transform; disassortative → dissuade hubs)gephi_whatif(edits, include_slow=False) → apply hypothetical edits (remove_node/remove_nodes/add_edge/remove_edge) to a throwaway workspace copy, diff the structural profile before/after, auto-clean the scratch copy; the real graph is never touched. For robustness/"what if we removed X" claims — see references/claim-verification.mdgephi_compare_nodes(id_a, id_b, metric) → deterministic two-node comparison on one metric (from attributes or a built-in field); errors if the metric isn't computed yet. For "is X more central than Y" claims — see references/claim-verification.mdgephi_color_by_partition, gephi_color_edges_by_partition (color edges by a categorical edge column — relationship type/period/tier), gephi_color_by_ranking, gephi_size_by_ranking, gephi_set_node_color/gephi_set_node_size, gephi_set_edge_color, gephi_edge_thickness_by_weight, gephi_batch_set_node_colors, gephi_reset_appearance
gephi_run_layout (use "ForceAtlas 2", "Yifan Hu", "Fruchterman Reingold", "Circular", "Random Layout"), gephi_stop_layout, gephi_get_layout_status, gephi_get_available_layouts, gephi_get_layout_properties/gephi_set_layout_properties
gephi_focus_view (mode graph|zero|node|edge|region, select highlights nodes, zoom) — directs the human viewer's attention in the Gephi window; essential in teaching mode. gephi_set_selection_mode (rectangle|direct|disable) — enable box-drag selection so pointing (gephi_get_selection) works without the human clicking the toolbar icon; call with rectangle at the start of teaching mode. gephi_get_perspective/gephi_switch_perspective — list/switch the top-level tab (Overview / Data Laboratory / Preview) to bring the viewer to the view you're about to discuss.
gephi_filter_by_degree, gephi_filter_by_edge_weight, gephi_remove_isolates, gephi_extract_ego_network, gephi_extract_giant_component, gephi_reset_filters, gephi_list_filters/gephi_apply_filter (the general filter tools — apply ANY built-in or per-column attribute filter by name, action select/new_workspace/column; see references/filtering.md)
gephi_column_value_frequencies (value distribution of a column), gephi_detect_duplicates (nodes sharing a column value), gephi_merge_nodes (merge duplicates into one — destructive), gephi_create_regex_column (boolean column flagging regex matches)
gephi_get_timeline (read-only: is the graph dynamic, time bounds, dynamic columns, interval state) — reason over node/edge start/end values to narrate change over time. There is no programmatic time-window tool: driving Gephi's timeline from outside destabilizes its render thread; slice by time in the Gephi timeline UI directly if needed.
gephi_get_preview_settings/gephi_set_preview_settings, gephi_export_png/gephi_export_pdf/gephi_export_svg (use file param), gephi_export_gexf/gephi_export_graphml/gephi_export_csv, gephi_export (any format by name — VNA/Pajek/DL/spreadsheet/GDF/JSON, for UCINET/Pajek interchange), gephi_view_graph (interactive in-chat view, no file param)
gephi_import_file, gephi_import_gexf/gephi_import_graphml/gephi_import_csv
Always override default Gephi colors for gephi_color_by_partition. This palette is
validated for categorical use on light backgrounds (lightness band, chroma floor,
colorblind separation, contrast — the old pastel palette failed all four and was
near-invisible on white exports):
{"0": [42,120,214], "1": [27,175,122], "2": [237,161,0], "3": [0,131,0], "4": [74,58,167], "5": [227,73,72], "6": [232,123,164], "7": [235,104,52]}
On dark backgrounds use the dark-surface variant:
{"0": [57,135,229], "1": [25,158,112], "2": [201,133,0], "3": [0,131,0], "4": [144,133,233], "5": [230,103,103], "6": [213,81,129], "7": [217,89,38]}
More than 8 communities: color the 8 largest, set the rest to neutral gray [153,153,153] — extra generated hues stop being distinguishable. Enable node labels for the largest nodes; color must not be the only way to identify a community.
Clean (no labels):
{"node.label.show": false, "edge.opacity": 25, "edge.curved": true, "edge.color": "source", "edge.thickness": 2.0, "node.opacity": 100, "node.border.width": 0.3, "arrow.size": 0}
Labeled:
{"node.label.show": true, "node.label.proportinalSize": false, "node.label.font": "Arial 10 Plain", "node.label.outline.size": 4, "node.label.outline.opacity": 95, "edge.opacity": 15}
New in 0.11.1: "node.label.avoidOverlap": true prevents label collisions; "node.label.overlapGridSize": 50 controls grid granularity. Both can be combined with existing label settings.
{"scalingRatio": 15, "linLogMode": true, "gravity": 0, "sync": true}, 1000-1500 iterations — scale scalingRatio up with node count (see Beautiful Graph Recipe table). Gravity stays 0 on connected graphs (use 0.5-1.0 only to keep disconnected components in frame); excessive gravity packs nodes into a central blob and is the most common layout mistake. LinLog mode + gravity 0 is the reference config for making communities visible (Venturini, Jacomy, and Jensen 2021).gephi_visual_qa with partition_column set to the community column. Its partition.separation (mean intra-community pair distance over mean random pair distance; 1.0 = fully mixed, near 0 = tight distinct clusters) is the objective form of "did the communities separate" — track it across parameter changes and quote the before/after when explaining an adjustment. Then export a small PNG, look at it, diagnose with the symptom table in references/layout-guide.md (blob = gravity too high; hairball = LinLog off or scaling too low; unreadable cluster interiors = raise scalingRatio), change ONE parameter, rerun ~300 iterations. Two or three loops usually converge — say what you saw, what the separation did, and what you changed.{"algorithm": "Noverlap", "iterations": 500, "properties": {"margin": 5.0}, "sync": true}barnesHutOptimize is wrong — the correct key is barnesHutOptimizationgephi_health_check and read the verdict: graph_lock: "busy" or a nonzero graph_lock_stats.readers while Gephi is idle means a leaked read hold — nothing will recover this; tell the user plainly that Gephi must be fully quit and reopened, and that their graph data in an unsaved project will be lost (suggest gephi_save_project earlier in sessions). queued > 0 for a long time means a writer is starving behind render load — pause mutations and let it drain. On plugin 1.1.x these protections don't exist: writes can hang indefinitely, so keep sessions to one focused build → style → layout → export pass and upgrade the plugin.gephi_set_preview_settings (including node.label.show) applies to exports and the Preview tab only. To see labels live in the Overview window, the user must click the black T toggle in the toolbar at the bottom of the graph canvas — only they can do that.node.label.proportinalSize: false Gephi clamps every label to its node's bounds (bigger fonts silently do nothing). For readable hub captions use gephi_label_clusters (proportional sizing + extent-scaled font handled for you); when hand-tuning, set proportional TRUE and scale the base font to the layout extent.undo_available), and gephi_undo restores the graph — but it is ONE level deep with no redo, so verify after each destructive step before taking the next. Single gephi_remove_node/gephi_remove_edge calls are NOT auto-snapshotted; call gephi_snapshot first before a risky sequence of small edits.gephi_extract_giant_component (and other writes after a layout) can deadlock Gephi — highest-risk during heavy rendering. To contain outlier nodes that blow out the bounding box, prefer high FA2 gravity (5–8) over destructive filters — as a temporary containment tactic only; revert gravity to 0 for the final layout.background.color in preview settings is stored but Gephi's PNG exporter always writes white — the Java plugin intercepts and composites the background color after export, but for reliable dark backgrounds use the Python post-processing workflow below.edge.opacity 60 is the minimum for dark background compositing — at 25% (default), edge pixels are too close to white to recover the original hue. Use 60% so compositing has enough signal.gephi_visual_qa now detects this (extent.outliers lists the runaway nodes) and computes suggested_export from the main cloud, so export with the suggested dimensions before reaching for Python cropping. To pull outliers into frame instead: gravity 5–8 in FA2 (temporary containment only). If post-processing anyway, centroid-crop (see Crop section below) — NOT alpha-threshold bounding box, which includes outlier nodes and returns full-canvas dimensions.Infinity/NaN (one node hit 1e37), not just a large-but-finite bounding box. This is silent: the layout call still returns success. Sync runs of gephi_run_layout now check for this automatically — a layout_exploded block in the result means do NOT export or style; follow its fix. Async runs and older servers still need the manual math.isfinite check on exported positions. (The exact parameter combination that triggered it is unconfirmed — see the /layout/run request-key gotcha below, discovered afterward, which casts doubt on which properties were actually active for this run. Treat this as "FA2 can do this on some graphs," not as a specific combination to avoid.) Fix: reset with Random Layout and rerun rather than trying to nudge the exploded node back — the explosion wasn't confined to one node, it corrupted the whole layout. The profile's heavy-tailed-weights flag is the advance warning: log-transform weights or lower edgeWeightInfluence before laying out a graph that carries it./layout/run's tuning values must be sent under the key "properties", not "params" — when driving the Gephi HTTP API directly (not through gephi_run_layout, which builds this correctly), a request with the wrong key returns success: true and runs the layout on its plugin defaults, silently discarding every custom value. There is no error to catch this. The tell: changing scalingRatio/gravity across a wide range and getting back nearly the same layout extent every time — a layout genuinely that insensitive to a parameter is itself the anomaly. Verify the request shape (or just use gephi_run_layout) before concluding a parameter doesn't matter for a given graph. The same applies to "Noverlap"'s speed/ratio/margin, which default to 0.0 — a full no-op, not a gentle setting.edge.opacity: 100, edge.thickness: 6, node size min 8 max 30, vivid modularity colors, centroid-crop the export. These settings produce clearly visible colored lines on white." (and ') in attribute values — when you generate a GEXF yourself to import, node label/attribute values containing a double-quote (e.g. titles like "Un/Doing Race" or Sorting Things Out: …) produce malformed XML and gephi_import_file fails with java.lang.RuntimeException SEVERE. Escape <>&"' in every attribute, then validate the file parses (python3 -c "import xml.dom.minidom,sys; xml.dom.minidom.parse(sys.argv[1])" file.gexf) before importing.gephi_query_nodes sort_by/descending may not sort — observed returning nodes in alphabetical id order regardless. To rank, pull the nodes and sort client-side, or read pageranks/degree from an exported GEXF/CSV.gephi_color_by_partition / gephi_size_by_ranking called immediately after a PNG export frequently returns Graph is busy (renderer holds the lock); please retry. Retry once or twice; if it persists, don't fight it — gephi_export_gexf and finish styling/labeling externally (see "Render externally from GEXF" below).Bad-looking graphs almost always come from one of three problems: layout parameters ignored (the most common), no overlap prevention, or wrong edge/label settings. Follow this recipe for publication-quality output.
scalingRatio must be calibrated to node count — too high and communities fly to the canvas edges:
| Nodes | scalingRatio | barnesHutOptimization | distributedAttraction |
|---|---|---|---|
| ≤ 50 | 10–20 | false | false |
| 50–300 | 30–80 | true | false |
| 300–1000 | 100–150 | true | true |
| 1000+ | 200–300 | true | true |
{
"algorithm": "ForceAtlas 2",
"iterations": 1200,
"sync": true,
"properties": {
"scalingRatio": 15,
"linLogMode": true,
"gravity": 1.0,
"barnesHutOptimization": false
}
}
linLogMode: true is the single most important setting — it makes communities pull together as tight clusters with open space between themscalingRatio default (10) is fine for small graphs; scale up with node count per the table abovedistributedAttraction (Dissuade Hubs) helps large graphs but pushes communities apart on small ones — avoid for < 300 nodesbarnesHutOptimization is only needed for large graphs (300+); skip it for small graphs to avoid approximation artifactssync: true so Phase 2 doesn't start on a still-moving graph{
"algorithm": "ForceAtlas 2",
"iterations": 200,
"sync": true,
"properties": {
"scalingRatio": 15,
"linLogMode": true,
"gravity": 1.0,
"adjustSizes": true
}
}
adjustSizes: true (Prevent Overlap) runs FA2 while accounting for node sizes — nodes physically push each other apartscalingRatio as Phase 1 so community structure is preserved{"algorithm": "Noverlap", "iterations": 300, "sync": true, "properties": {"margin": 3.0}}
{"algorithm": "Label Adjust", "iterations": 300, "sync": true}
{
"node.label.show": false,
"edge.color": "source",
"edge.opacity": 20,
"edge.curved": true,
"edge.thickness": 1.5,
"node.opacity": 100,
"node.border.width": 0.5,
"node.label.avoidOverlap": true,
"arrow.size": 0
}
edge.color: "source" creates the watercolor halo effect where edges fade into their source community coloredge.opacity: 20 keeps edges from overwhelming the community structurenode.label.avoidOverlap: true (0.11.1+) prevents label collisions without needing Label AdjustGephi's PNG exporter always writes a white background regardless of background.color. Use this Python post-processing recipe after gephi_export_png:
from PIL import Image
import numpy as np
img = Image.open('export.png').convert('RGB')
arr = np.array(img, dtype=np.float32)
bg = np.array([28, 28, 46], dtype=np.float32) # dark navy #1C1C2E
dist = 255.0 - arr
alpha = np.clip(np.max(dist, axis=2) / 255.0 * 1.8, 0, 1)
a_safe = np.maximum(alpha, 0.02)[:,:,np.newaxis]
recovered = np.clip((arr - 255.0*(1-alpha[:,:,np.newaxis])) / a_safe, 0, 255)
result = np.clip(bg + alpha[:,:,np.newaxis]*(recovered - bg), 0, 255).astype(np.uint8)
Image.fromarray(result).save('export-dark.png')
Requirements for this to work well:
edge.opacity must be at least 60 (pastels at 25% produce near-white pixels; recovery fails)For labeled exports, use white background (background.color: "#FFFFFF"). Labels are readable on white natively.
Crop and scale to fill canvas — use centroid-based cropping, not alpha-threshold bounding box. Alpha-threshold fails on sparse graphs (outlier nodes at canvas edges push the bounding box to full canvas width). Centroid method finds the center of mass of visible content and crops a fixed window around it:
dist = 255.0 - arr
alpha = np.clip(np.max(dist, axis=2) / 255.0 * 1.8, 0, 1)
mask = alpha > 0.12
ys, xs = np.where(mask)
cy, cx = int(ys.mean()), int(xs.mean())
half_w, half_h = 900, 700 # tune to graph density
img.crop((max(0,cx-half_w), max(0,cy-half_h),
min(W,cx+half_w), min(H,cy+half_h))).resize((3840,2160), Image.LANCZOS).save('export-zoom.png')
half_w/half_h based on how spread out the graph is (900/700 works for KGs with bounding box blowout)Gephi has no native community label feature. Use Python to overlay one label per modularity class after export.
Workflow:
gephi_query_nodes (limit covers all nodes, attributes: ["modularity_class"]) to get x/y positions and colors per node.cx = mean(xs), cy = mean(ys).px = (cx - x_min) / (x_max - x_min) * W
py = H - (cy - y_min) / (y_max - y_min) * H # Y axis is inverted
Gotchas:
When you need labels, distinct community colors, or any layout the overlay-on-PNG
path can't give cleanly, don't pull coordinates with gephi_query_nodes and
don't use export_csv (the node CSV has no x/y). Instead gephi_export_gexf
— it bakes <viz:position> plus every attribute (modularity_class,
pageranks) — then re-render the whole figure in matplotlib. This sidesteps the
white-background compositing entirely and gives full control over color (no
look-alike-palette collisions) and label placement.
Parse the viz namespace by local tag name (position/size/color are in
gexf.net/.../viz, not the default namespace):
import xml.etree.ElementTree as ET
import numpy as np, matplotlib; matplotlib.use('Agg')
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
import matplotlib.patheffects as pe
local = lambda t: t.split('}')[-1]
root = ET.parse('graph-positions.gexf').getroot()
pos, comm, pr = {}, {}, {}
for n in root.iter():
if local(n.tag) != 'node': continue
nid = n.get('id')
for c in n:
if local(c.tag) == 'position': pos[nid] = (float(c.get('x')), float(c.get('y')))
elif local(c.tag) == 'attvalues':
for av in c:
if av.get('for') == 'modularity_class': comm[nid] = int(float(av.get('value')))
elif av.get('for') == 'pageranks': pr[nid] = float(av.get('value'))
edges = [(e.get('source'), e.get('target')) for e in root.iter()
if local(e.tag) == 'edge' and e.get('source') in pos and e.get('target') in pos]
PAL = {0:'#e74c3c',1:'#e98b1f',2:'#f1c40f',3:'#8bc34a',4:'#2ecc71',
5:'#1abc9c',6:'#3498db',7:'#ff2e88',8:'#9b59b6',9:'#00d0e0'} # 10 distinct hues
nodes = list(pos)
fig, ax = plt.subplots(figsize=(17,17), dpi=240)
fig.patch.set_facecolor('#0a0c1a'); ax.set_facecolor('#0a0c1a')
ax.add_collection(LineCollection([[pos[s],pos[t]] for s,t in edges],
colors=[PAL[comm.get(s,0)] for s,_ in edges], linewidths=0.35, alpha=0.10))
pv = np.array([pr.get(n,0) for n in nodes])
ax.scatter([pos[n][0] for n in nodes], [pos[n][1] for n in nodes],
s=18 + (pv/pv.max())*2600, c=[PAL[comm.get(n,0)] for n in nodes],
edgecolors='none', alpha=0.95, zorder=3)
(Edges colored by source community = the watercolor halo; nodes sized by PageRank. matplotlib renders ~7k edges fine.)
Because community centroids overlap in the dense core, labels placed at the centroids collide. Instead place labels on a ring around the graph, evenly spaced by each centroid's angle, with a leader line back to a marker at the true centroid — no overlaps, locations still exact:
xs = np.array([pos[n][0] for n in nodes]); ys = np.array([pos[n][1] for n in nodes])
cx, cy = np.median(xs), np.median(ys)
R = np.percentile(np.hypot(xs-cx, ys-cy), 98) # cloud radius (98th pct ignores outliers)
anchor = {k: (np.median([pos[n][0] for n in nodes if comm.get(n)==k]),
np.median([pos[n][1] for n in nodes if comm.get(n)==k])) for k in PAL}
order = sorted(PAL, key=lambda k: np.arctan2(anchor[k][1]-cy, anchor[k][0]-cx))
base = np.arctan2(anchor[order[0]][1]-cy, anchor[order[0]][0]-cx)
for i, k in enumerate(order):
ang = base + 2*np.pi*i/len(order) # even spacing → guaranteed no overlap
lx, ly = cx + R*1.32*np.cos(ang), cy + R*1.32*np.sin(ang)
ax.plot([anchor[k][0], lx], [anchor[k][1], ly], color=PAL[k], lw=1.2, alpha=0.55, zorder=4)
ax.scatter([anchor[k][0]], [anchor[k][1]], s=140, facecolor=PAL[k],
edgecolor='white', lw=1.5, zorder=6)
t = ax.text(lx, ly, NAMES[k], color='white', ha='left' if lx>=cx else 'right',
va='center', fontsize=16, fontweight='bold', zorder=7)
t.set_path_effects([pe.withStroke(linewidth=4.5, foreground=PAL[k]),
pe.withStroke(linewidth=9, foreground='#0a0c1a')])
ax.set_aspect('equal'); ax.axis('off')
plt.savefig('graph-labeled.png', facecolor='#0a0c1a', bbox_inches='tight', pad_inches=0.25)
NAMES is your {modularity_class: "Theme"} map — name each community from its
top-PageRank members (gephi_query_nodes or the exported node table).
linLogMode is off, or scalingRatio is too low. Verify properties are accepted.node.label.avoidOverlap: true in preview settings.For detailed tool parameters, see references/tool-reference.md.
For layout algorithm details, see references/layout-guide.md.
For statistics interpretation, see references/statistics-guide.md.
For building and reading text networks, see references/text-network-analysis.md.
For verifying a plain-language structural claim against the graph, see references/claim-verification.md.
For compiling a plain-language filter into a Gephi filter, see references/filtering.md.
Multiplex graphs: gephi_add_edge/gephi_add_edges accept an edge_type label so the same pair can hold several parallel typed edges (e.g. "cites" + "coauthor"). To compare layers, filter to one type (gephi_apply_filter with the "Edge Type" filter), compute modularity, repeat per type, and compare the partitions.
npx claudepluginhub mattartzanthro/gephi-ai --plugin gephi-network-analysisCreates, analyzes, and visualizes complex networks and graphs in Python. Use for graph algorithms, centrality, community detection, and network generation.
Creates, analyzes, and visualizes complex networks and graphs in Python. Use for graph algorithms, centrality, community detection, and network generation.
Creates, analyzes, and visualizes complex networks using Python's NetworkX library. Handles graph algorithms, community detection, synthetic network generation, and topology visualization for social, biological, transportation, and citation networks.