Skip to content

Crime Linkage: Expand to 500+ rings #6

Description

@vanguard-hack

Feature Ticket: Crime Linkage Network Explorer — Scale to 500 Rings, Full-Network Default View, Zoom Controls

Summary

Three changes to the existing Network Explorer (crime ring linkage visualization):

  1. Scale the ring dataset from 241 to 500, with a realistic (not uniform/random) network topology.
  2. Change the default view: instead of loading into a single pre-selected ring, show all rings at once as one combined network on load; selecting a ring from the sidebar then filters/zooms into that ring specifically.
  3. Add explicit + / − zoom controls to the graph canvas, alongside the existing scroll-to-zoom.

Current State

  • Sidebar lists rings (#1 Hanumantha's ring, #2 Jagadish's ring, ...) with member count, district, and primary crime type.
  • On load, one ring is pre-selected (appears to default to #1) and its subgraph (20 nodes, 31 links) renders in the canvas.
  • Canvas supports hover-to-trace, scroll-to-zoom, and drag-to-pan — but no visible zoom buttons.
  • Nodes are colored by district, sized by (presumably) degree/centrality within the ring.
  • Total: 241 rings.
Image

1. Scale to 500 Rings — with Realistic Topology

This isn't just "add 259 more rows." Real crime-linkage networks aren't uniform — they follow recognizable patterns, and the visualization should reflect that rather than looking like randomly scattered, evenly-sized clusters. Specific requirements:

  • Ring size distribution should follow a power-law-like curve, matching what's already visible in the current 241 (20, 19, 15, 15, 13, 13, 12, 12, 10, 9, 9...): a small number of large rings (15–20+ members), a long tail of small rings (2–4 members). Don't generate 500 rings of roughly similar size — that's the "looks random" problem being flagged.
  • Most rings should be fully disjoint (no shared members with any other ring) — this is the realistic default, since most crime rings genuinely don't connect to each other. Target roughly 70–80% fully isolated rings.
  • A minority of rings should share members across ring boundaries, creating larger connected super-clusters — representing real cases where an individual is linked to multiple separate crime rings (e.g., a fence who moves stolen goods for several unrelated theft rings, or a financier connected to multiple fraud rings). Target roughly 20–30% of rings with at least one cross-ring shared member, producing maybe a handful of larger connected components alongside the many small isolated ones.
  • District distribution should be weighted, not uniform — align with actual district-level crime volume/population if that data is available, rather than spreading rings evenly across all districts.
  • Crime type distribution should be weighted similarly — common crime types (theft, rash driving, cheating) should be proportionally more frequent than rare ones (kidnapping, molestation), matching real case-type frequency rather than an even split.
  • Degree distribution within each ring should also follow a power-law — a ring shouldn't be a uniform mesh; it should have 1–2 "hub" members with many links (ringleaders/key connectors) and most members with just 1–2 links, which is what makes the existing Ring Implement slash (/) commands for Assistant #1 visual (Hanumantha, Stella, Mohan as visibly larger/more-connected nodes) look realistic in the first place. Keep generating that pattern at scale.

Open question for the team (see below): is the ring data currently backed by an actual entity-resolution/link-analysis pipeline running over case records, or is it synthetic/seed data for the demo? The approach to "get to 500" differs significantly depending on the answer — see Open Questions.


2. Default View: Full Network, Not a Single Pre-Selected Ring

Current behavior: loads directly into one ring's subgraph.
Required behavior: on load, with no ring selected, the canvas should render all 500 rings together as a single combined network graph — the disjoint rings appearing as separate scattered clusters, and the cross-linked rings forming the larger connected components described above. This gives the officer an actual overview of the linkage landscape before drilling into any one ring.

Requirements:

  • Sidebar list still shows all rings (see performance note below on virtualization), but none is selected/highlighted by default.
  • Clicking a ring in the sidebar transitions the canvas from the full-network view into that ring's isolated subgraph (the current single-ring behavior), and highlights that ring's card in the sidebar.
  • Provide a clear way back to the full-network overview — e.g., a "Show all rings" / "Clear selection" control, not just browser back.
  • In the full-network view, consider dimming node labels by default (with thousands of nodes, showing every name at once is unreadable) — show labels on hover, or only for hub nodes above a size threshold, with full labels appearing once zoomed into a single ring.
  • Legend (district color key) stays visible in both views.

3. Zoom Controls (+ / −)

Requirement: Add a floating zoom control widget to the canvas — a + button and a button (standard map/graph UI convention, typically bottom-right corner of the canvas), in addition to the existing scroll-to-zoom and drag-to-pan.

Details:

  • Each click zooms by a fixed increment (e.g., 1.2× per click), with defined min/max zoom bounds so users can't zoom past the point of losing context or so far in that layout breaks.
  • Include a third "fit to view" / reset button alongside +/− — especially useful for snapping back to "see the whole ring" after zooming in on a cluster, or "see the whole network" after zooming into a subgraph.
  • Keep scroll-to-zoom and drag-to-pan working exactly as they do now — the buttons are additive, not a replacement (some users on trackpads/touch devices rely on buttons more than scroll gestures).
  • Keyboard support: +/- keys mirror the buttons; standard accessibility labeling (aria-label="Zoom in" / "Zoom out") on both.
  • Zoom should animate smoothly (short transition, not an instant jump) for both button clicks and scroll.

Performance Considerations (matters more once this is 500 rings + full-network default view)

At 500 rings averaging ~8–10 members each, the full-network view could involve 4,000–5,000+ nodes and a comparable or larger number of links rendered simultaneously — a meaningfully different performance problem than the current single-ring view of ~20 nodes.

  • Rendering technology: if the current canvas is SVG-based, it will likely struggle at this scale. Recommend a WebGL-backed graph renderer (e.g., Sigma.js, Cytoscape.js with a WebGL renderer, or PixiJS-based custom rendering) for the full-network view specifically. The single-ring detail view can likely stay on the current renderer if it's already performant at ~20 nodes.
  • Precompute layout, don't compute client-side on every load: run the force-directed layout simulation once (server-side or in a build/data-generation step) and store x/y coordinates per node, rather than re-running the physics simulation in the browser on every page load. Recompute and cache only when the underlying ring data changes.
  • Sidebar list virtualization: don't mount 500 DOM list items at once — use a virtualized list (e.g., react-window/react-virtualized or equivalent) that only renders the visible rows.
  • Single network payload, not 500 API calls: the full-network view needs one endpoint that returns all nodes/links/ring metadata together, not a loop of per-ring requests.

API / Data Requirements

  • New or updated endpoint for the full network: e.g., GET /api/crime-linkage/network → returns all nodes (with precomputed x/y, district, size/degree), all links (including cross-ring links), and ring boundary metadata (which nodes belong to which ring) in one payload.
  • Existing single-ring endpoint (presumably already backing the current detail view) stays as-is: GET /api/crime-linkage/rings/{ringId}.
  • Sidebar ring list: paginated or fully returned with lightweight fields only (name, member count, district, primary crime type) — don't embed full subgraph data in the list payload.

Acceptance Criteria

  • Dataset contains 500 rings with power-law-distributed ring sizes (matching the pattern visible in the current 241)
  • ~70–80% of rings are fully disjoint (no shared members with other rings)
  • ~20–30% of rings share at least one member with another ring, forming larger connected components
  • District and crime-type distribution across rings is weighted, not uniform
  • On page load with no ring selected, canvas renders the full network of all 500 rings, scattered with visible disjoint clusters and connected super-clusters
  • Sidebar lists all 500 rings (virtualized for performance) with none pre-selected by default
  • Selecting a ring transitions the canvas to that ring's isolated subgraph and highlights it in the sidebar
  • A clear "show all rings" control returns from single-ring view to the full-network overview
  • + and zoom buttons are present on the canvas, functional, with defined zoom bounds and a smooth animated transition
  • A "fit to view" / reset control is present alongside the zoom buttons
  • Scroll-to-zoom and drag-to-pan continue to work unchanged
  • Full-network view renders and remains interactive (pan/zoom/hover) at 500-ring scale without significant lag on target hardware — define and test against a specific frame-rate/load-time budget (see open questions)
  • Node labels are suppressed or limited by default in full-network view to avoid visual clutter, appearing on hover or when zoomed into a ring

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions