Question/Possible Feature Idea for Tag Editing #1329
Replies: 2 comments
-
|
If it's something we'd be interested in, this is what my proposal would look like: Technical Proposal: Tag Graph View in TagStudioAuthor: Justinian Erdmier (Prepared with Claude) 1. Executive SummaryThis proposal outlines a plan to add an interactive graph/web visualisation to TagStudio, enabling users to spatially explore their tags and the parent–child relationships between them. The feature draws direct inspiration from Obsidian's graph view, adapted for the specific domain of a tag management system rather than a note-linking system. The graph view would be accessible as a new panel or window from the existing Tag Manager (Edit → Tag Manager, or 2. Problem Statement & MotivationTagStudio currently presents tags in a flat, scrollable, list-based interface (the
A graph view addresses all of these by rendering each tag as a node and each parent–child relationship as an edge, laid out using a force-directed algorithm. 3. Scope & Requirements3.1 Functional Requirements
3.2 Non-Functional Requirements
3.3 Out of Scope (initial release)
4. Analysis of the Existing Codebase4.1 Data ModelThe tag hierarchy is stored in an SQLite database via SQLAlchemy. The key models are:
Critically, the 4.2 Existing Library APIThe
Additionally, 4.3 Existing UI Architecture
The Style Guide specifies a view/controller split: views define UI elements and raise callbacks via 5. Implementation ApproachesThere are three viable approaches, each with distinct trade-offs. 5.1 Approach A: Qt QGraphicsScene + NetworkX Layout (Recommended)Description: Build the graph view as a custom Technology:
Architecture: How it works:
Precedent: Qt's own official PySide6 documentation includes a NetworkX graph viewer example that demonstrates exactly this pattern — Advantages:
Disadvantages:
Risk Mitigation:
5.2 Approach B: Embedded QWebEngineView + JavaScript Graph LibraryDescription: Render the graph in an embedded web view using a JavaScript visualisation library such as D3.js (force simulation), Cytoscape.js, or vis.js. Communication between Python and JavaScript occurs via Technology:
Architecture: Advantages:
Disadvantages:
5.3 Approach C: Custom Force-Directed Simulation in QGraphicsScene (No External Graph Library)Description: Implement everything from scratch using only Qt: a custom force-directed layout algorithm operating directly on Architecture: Same as Approach A, but without NetworkX. Advantages:
Disadvantages:
6. RecommendationApproach A (QGraphicsScene + NetworkX) is the recommended path. It provides the best balance of native integration, development speed, code quality, and performance. The Qt QGraphicsView framework is specifically designed for this kind of interactive 2D canvas, and NetworkX provides well-tested layout algorithms with minimal overhead. The official PySide6 documentation even includes a worked example of this exact combination, which significantly de-risks the implementation. The key reasons for preferring Approach A over Approach B (WebEngine):
Approach C (fully custom) is only recommended if the project has an absolute policy against new dependencies. The development cost is substantially higher for a worse initial result. 7. Detailed Design (Approach A)7.1 New Dependency# In pyproject.toml [project] dependencies:
"networkx~=3.4",NetworkX 3.4+ requires Python ≥3.10 (TagStudio requires 3.12, so this is compatible). NumPy is already a dependency. 7.2 Module Structure7.3 Data Flow7.4 Key Classes
|
| Algorithm | NetworkX Function | Best For |
|---|---|---|
| Force-Directed (Fruchterman-Reingold) | nx.spring_layout() |
General-purpose, good for discovering clusters |
| ForceAtlas2 | nx.forceatlas2_layout() |
Large graphs, better separation |
| Kamada-Kawai | nx.kamada_kawai_layout() |
Smaller graphs, aesthetically pleasing |
| Circular | nx.circular_layout() |
Overview of all tags equally spaced |
| Hierarchical / Layered | nx.multipartite_layout() |
Emphasising parent-child depth |
For hierarchical visualisation, Graphviz's dot layout (available via pygraphviz or pydot) would be ideal but adds a system-level dependency. A simpler alternative is to compute a topological sort and assign vertical layers based on the longest path from a root node, then use nx.multipartite_layout().
7.6 Integration Points
Launching the graph view:
In ts_qt.py (QtDriver), the graph view would be initialised similarly to the existing tag_manager_panel:
self.tag_graph_panel = PanelModal(
widget=TagGraphPanel(self, self.lib),
title=Translations["tag_graph.title"],
done_callback=lambda checked=False: (
self.main_window.preview_panel.set_selection(
self.selected, update_preview=False
)
),
has_save=False,
)Menu bar entry:
Add a new action under Edit (or View):
- "Tag Graph View" /
Ctrl+G
Translation keys to add:
{
"tag_graph.title": "Tag Graph",
"tag_graph.layout.force_directed": "Force-Directed",
"tag_graph.layout.hierarchical": "Hierarchical",
"tag_graph.layout.circular": "Circular",
"tag_graph.search_placeholder": "Search tags...",
"tag_graph.context.edit_tag": "Edit Tag",
"tag_graph.context.delete_tag": "Delete Tag",
"tag_graph.context.add_child": "Add Child Tag",
"tag_graph.context.add_parent": "Add Parent Tag"
}7.7 Performance Considerations
| Tag Count | Expected Behaviour |
|---|---|
| < 500 | Instant layout, smooth interaction |
| 500–2,000 | Layout computed in background thread (~1–3s), smooth interaction once rendered |
| 2,000–5,000 | Layout in background thread (~3–10s), may need level-of-detail (hide labels at low zoom) |
| > 5,000 | Requires level-of-detail rendering, possible viewport culling, progressive layout |
Strategies:
- Run layout computation in a
QThreadwith a progress indicator. - Use
QGraphicsScene.setItemIndexMethod(QGraphicsScene.NoIndex)for scenes with many moving items during layout animation, switching back toBspTreeIndexonce stable. - Hide node labels when zoomed out beyond a threshold.
- Implement viewport culling (only render items visible in the current viewport).
7.8 Visual Design
Nodes should visually echo the existing tag widgets used elsewhere in TagStudio:
- Rounded rectangle shape (matching the tag pill/chip style in the preview panel).
- Background colour from
TagColorGroup.primary. - Border colour derived from the tag colour (using existing
get_border_color()helper). - Text colour from the existing
get_text_color()helper. - Category tags distinguished by a thicker border or a small icon overlay.
- Hidden tags rendered at 40% opacity.
- Selected nodes highlighted with a glow or thicker, brighter border.
Edges should be semi-transparent grey by default, brightening when hovered or when either connected node is selected.
8. Implementation Plan
Phase 1: Core Graph Rendering (MVP)
- Add
networkxdependency. - Implement
TagGraphNodeandTagGraphEdgewidgets. - Implement
TagGraphView(view layer) with pan, zoom, and basic rendering. - Implement
TagGraphPanel(controller layer) that loads tags and renders the graph. - Add menu bar entry and keyboard shortcut.
- Add translation keys.
Estimated effort: Medium-high
Phase 2: Interaction & Tag Management
- Node click → details panel (sidebar or tooltip).
- Node double-click → open
BuildTagPanelin aPanelModal. - Right-click context menu (edit, delete, add child/parent).
- Create Tag button.
- Refresh graph after any tag mutation.
Estimated effort: Medium
Phase 3: Polish & Performance
- Layout algorithm selector (force-directed, hierarchical, circular).
- Search/filter bar with highlight.
- Animated layout transitions (
QPropertyAnimationon node positions). - Background thread for layout computation.
- Level-of-detail rendering (hide labels at low zoom).
- Node size scaling by entry count (optional, toggleable).
- Keyboard navigation (arrow keys to traverse edges, Enter to select).
Estimated effort: Medium
Phase 4: Future Enhancements (Post-MVP)
- Drag-and-drop to reparent tags (drag a node onto another to add a parent relationship).
- Subgraph focus mode (click a node to show only its N-hop neighbourhood).
- Export graph as image (PNG/SVG).
- Minimap for navigation in large graphs.
- Undo/redo for graph mutations.
9. Testing Strategy
- Unit tests (
pytest): Test the data transformation layer (Library → NetworkX DiGraph construction, layout computation). - Widget tests (
pytest-qt): TestTagGraphViewinstantiation, node creation, and signal emission. - Integration tests: Test that tag CRUD operations from the graph view correctly modify the database and refresh the view.
- Snapshot tests (
syrupy, already a project dependency): Capture rendered graph state for regression testing. - Manual testing: Visual inspection on Windows, macOS, and Linux, with libraries of varying sizes (10, 100, 1,000, 5,000 tags).
10. Open Questions
Before beginning implementation, the following questions should be clarified with the TagStudio maintainers:
- Window or panel? Should the graph view open as a separate window (like the current Tag Manager), as a dockable panel, or as an alternative view within the main content area (replacing the thumbnail grid)?
- Dependency policy: Is adding
networkxas a new dependency acceptable, or would a lighter alternative (e.g.,igraphor a custom layout) be preferred? - Design review: Would the maintainers like to see a visual mockup or prototype before full implementation?
- Edge direction convention: Should edges visually point from child → parent (following the
TagParentdata model), or from parent → child (following the conceptual "inherits from" hierarchy)?
11. References
- Qt for Python — NetworkX Graph Viewer Example — official PySide6 example demonstrating QGraphicsView + NetworkX integration.
- NetworkX Layout Algorithms — documentation for all available layout functions.
- Qt QGraphicsView Framework — Qt's 2D scene graph documentation.
- TagStudio Contributing Guide — project contribution guidelines.
- TagStudio Style Guide — code style and MVC architecture conventions.
- Obsidian Graph View — the inspiration for this feature.
Beta Was this translation helpful? Give feedback.
-
|
I also used Claude to generate a very rough mockup of what this would look like (emphasis on "look"; this isn't meant to showcase implementation, but just how the UI could look). This mockup is made using JS and is obviously not polished, but it conveys the general idea. https://claude.ai/public/artifacts/b8203883-8b66-4691-8cea-7388b81e569a |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
I see that on the roadmap, there is an entry titled "New Tabbed Tag Building UI to Support New Tag Features". However, there aren't any quick and accessible descriptions explaining what this is. I've wanted to propose adding a new feature for tag editing that lets users see their tags in a graph/web view (think the graph view in Obsidian). This way, the user can visualise their tags, see their relationships, etc.
The roadmap entry title suggests the feature is about building the tags, but I don't see how being "tabbed" fits into that. If there is a feature to rework the UI for managing tags, I'm happy to wait until that's done and go from there. As it is, any complex tag system is near-impossible to manage, with no way to visualise it. I would like to contribute to making that happen.
Beta Was this translation helpful? Give feedback.
All reactions