Skip to content

Commit 5a11cac

Browse files
DoodleBUGS: GSoC 2025 Report (#126)
* Shravan's GSoC 2025 Report * update GSoC report * update team page * minor css fix and report update * update report * update alias * update alias * Update news/posts/DoodleBUGS-Introduction/index.qmd Co-authored-by: Hong Ge <[email protected]> * Update index.qmd * Update index.qmd * change folder name for report * Apply previous suggestion of @yebai --------- Co-authored-by: Hong Ge <[email protected]>
1 parent aa4bd7a commit 5a11cac

File tree

9 files changed

+403
-2
lines changed

9 files changed

+403
-2
lines changed
196 KB
Loading
94.9 KB
Loading
110 KB
Loading
Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
1+
---
2+
title: "GSoC Report for DoodleBUGS: a Browser-Based Graphical Interface for Drawing Probabilistic Graphical Models"
3+
description: "Shravan Goswami's GSoC 2025 final report: goals, architecture, progress vs proposal, and how to try it."
4+
toc: true
5+
categories:
6+
- GSoC
7+
- Blog
8+
author:
9+
- name: Shravan Goswami
10+
url: https://shravangoswami.com/
11+
date: 2025-09-01
12+
aliases:
13+
- /GSoC-2025-Report-DoodleBUGS # submitted this to GSoC so please remember to update incase moving this page somewhere else
14+
bibliography: references.bib
15+
csl: university-of-york-ieee.csl
16+
link-citations: true
17+
nocite: |
18+
@*
19+
---
20+
21+
## TL;DR
22+
23+
- BUGS (Bayesian Inference Using Gibbs Sampling) is a probabilistic programming language for Bayesian models, and JuliaBUGS is its modern implementation in Julia. DoodleBUGS is a browser-based graphical interface for JuliaBUGS, allowing users to draw probabilistic graphical models and generate BUGS code.
24+
- Implemented: visual editor (nodes, edges, nested plates), legacy BUGS code generation that compiles with [JuliaBUGS](https://github.com/TuringLang/JuliaBUGS.jl) [@JuliaBUGS; @bugs-book], local execution via a Julia backend, unified standalone script generation (frontend), timeouts, multiple layouts, and extensive cleanup/typing.
25+
- Changed from proposal: frontend implemented in Vue 3 (instead of React); backend simplified (frontend is the single source of truth for standalone scripts).
26+
- Status: Working application. Try it here (static UI): [https://turinglang.org/JuliaBUGS.jl/DoodleBUGS/](https://turinglang.org/JuliaBUGS.jl/DoodleBUGS/). For local inference, run the backend server.
27+
28+
## DoodleBUGS UI
29+
30+
![DoodleBUGS UI](DoodleBUGS.png)
31+
32+
## DoodleBUGS Project Structure
33+
34+
```{.bash}
35+
DoodleBUGS/ # Vite + Vue 3 app (UI editor)
36+
├── README.md # project documentation
37+
├── public/ # static assets served by Vite
38+
│ └── examples/ # example projects
39+
├── experiments/ # prototypes and exploratory work
40+
├── runtime/ # Julia HTTP backend (API endpoints & dependencies)
41+
├── src/ # application source
42+
│ ├── assets/ # styles and static assets
43+
│ ├── components/ # Vue components composing the UI
44+
│ │ ├── canvas/ # graph canvas and toolbars
45+
│ │ ├── common/ # shared UI primitives
46+
│ │ ├── layouts/ # app layout and modals
47+
│ │ │ └── MainLayout.vue # main application layout
48+
│ │ ├── left-sidebar/ # palette, project manager, execution settings
49+
│ │ ├── panels/ # code preview and data input panels
50+
│ │ ├── right-sidebar/ # execution, JSON editor, node properties
51+
│ │ └── ui/ # base UI elements (buttons, inputs, selects)
52+
│ ├── composables/ # reusable logic (codegen, drag & drop, graph, validator, grid)
53+
│ ├── config/ # configuration and node definitions
54+
│ ├── stores/ # Pinia state stores (graph, data, execution, project, UI)
55+
│ └── types/ # TypeScript types and ambient declarations
56+
├── tmp/ # local temporary outputs (ignored in builds)
57+
└── ztest/ # scratch/test artifacts
58+
```
59+
60+
## Motivation
61+
62+
[JuliaBUGS](https://github.com/TuringLang/JuliaBUGS.jl) is a modern Julia implementation of the BUGS language [@bugs-rjournal; @bugs-book; @bugs-project]. DoodleBUGS revives the original visual modelling concept with a modern browser-based stack so users can:
63+
64+
- Construct probabilistic graphical models visually (nodes, edges, plates).
65+
- Export readable legacy BUGS code that compiles with JuliaBUGS [@JuliaBUGS; @bugs-rjournal; @bugs-book].
66+
- Run inference and inspect results from the UI. Common BUGS applications include parallel MCMC [@multibugs], survival analysis [@bugs-survival], and Gibbs-style samplers [@albert-chib-1993; @informs-gibbs].
67+
68+
## What Was Built
69+
70+
- Visual editor
71+
- Node types: stochastic, observed, deterministic
72+
- Plates with arbitrary nesting; robust drag-in/out and creation inside plates
73+
- Graph layouts: Dagre (default), fCoSE (Force-Directed), Cola (Physics Simulation), KLay (Layered); stable interactions
74+
- Legacy BUGS code generation [@bugs-rjournal; @bugs-book]
75+
- Topological ordering and plate-aware traversal
76+
- Parameter formatting and safe index expansion
77+
- Implemented in `DoodleBUGS/src/composables/useBugsCodeGenerator.ts`
78+
- Execution flow
79+
- Frontend POSTs to `/api/run` with body: `model_code` (BUGS), `data` and `inits` (JSON), `data_string` and `inits_string` (Julia NamedTuple literals), and `settings` `{ n_samples, n_adapts, n_chains, seed, timeout_s }`. If `/api/run` returns 404, it falls back to `/api/run_model`.
80+
- Backend creates a temp dir, writes `model.bugs` and `payload.json`, generates an ephemeral `run_script.jl`, compiles with `JuliaBUGS.@bugs`, wraps with `ADgradient(:ReverseDiff)`, and samples via `AdvancedHMC.NUTS` through `AbstractMCMC` (Threads or Serial). It writes summaries (incl. ESS, R-hat) and quantiles to JSON and returns `{ success, summary, quantiles, logs, files[] }`, where `files` includes `model.bugs`, `payload.json`, `run_script.jl`, and `results.json`.
81+
- Frontend also generates a `standalone.jl` script locally (mirrors backend execution) and shows it alongside the backend files; the backend does not attach a standalone script.
82+
- Timeouts/resilience
83+
- Configurable timeout (frontend); enforced in backend worker
84+
- Safe temp directory cleanup on Windows with retries
85+
- Cleanup/typing
86+
- Strong, project-wide TypeScript typing across stores, components, and composables
87+
- Removal of unused backend code; consistent naming and logs
88+
89+
## Architecture Overview
90+
91+
- Frontend: [Vue 3](https://vuejs.org/), [Pinia](https://pinia.vuejs.org/), [Cytoscape.js](https://js.cytoscape.org/) [@cytoscapejs], [CodeMirror](https://codemirror.net/)
92+
- Code generation: `DoodleBUGS/src/composables/useBugsCodeGenerator.ts`
93+
- Execution panel: `DoodleBUGS/src/components/right-sidebar/ExecutionPanel.vue`
94+
- Backend (Julia) HTTP server
95+
- Server: `DoodleBUGS/runtime/server.jl`
96+
- Project deps: `DoodleBUGS/runtime/Project.toml` (HTTP, JSON3, JuliaBUGS, AbstractMCMC, AdvancedHMC, ReverseDiff, MCMCChains, DataFrames, StatsBase, Statistics)
97+
- Endpoints: GET `/api/health`; POST `/api/run` and `/api/run_model`
98+
- Execution: creates temp dir, writes `model.bugs` and `payload.json`, generates `run_script.jl`, enforces optional timeout
99+
100+
## Design Principles and Architecture
101+
102+
**Design principles**
103+
104+
- Visual-first modeling with deterministic export to legacy BUGS [@bugs-rjournal; @bugs-book].
105+
- Separation of concerns: editing (graph), generation (BUGS), execution (backend), and results (summary/quantiles) are modular.
106+
- Deterministic ordering: topological sort + plate-aware traversal ensures readable, stable code output.
107+
- Robustness: cancellable frontend fetch, backend-enforced timeout, and resilient temp cleanup on Windows (`safe_rmdir()`).
108+
109+
**Frontend architecture (Vue 3 + Cytoscape.js)**
110+
111+
- Core graph state is managed in Vue; [Cytoscape.js](https://js.cytoscape.org/) handles layout, hit-testing, and interaction semantics (including compound nodes for plates) [@cytoscapejs].
112+
- Code generation lives in `DoodleBUGS/src/composables/useBugsCodeGenerator.ts` and maps `GraphNode`/`GraphEdge` to BUGS:
113+
- Kahn topological sort for definition order
114+
- Plate-aware recursion for `for (...) { ... }` blocks
115+
- Parameter canonicalization (indices, numeric/expr passthrough)
116+
- Standalone Julia script generation uses `generateStandaloneScript()` in the same composable, mirroring backend execution.
117+
118+
**Backend architecture (Julia)**
119+
120+
- `run_model_handler()` in `DoodleBUGS/runtime/server.jl` materializes `model.bugs`, `payload.json`, and a transient `run_script.jl` that:
121+
- Builds `NamedTuple`s from JSON or string-literal data/inits
122+
- Compiles via `JuliaBUGS.@bugs`, wraps with `ADgradient(:ReverseDiff)` [@ReverseDiff]
123+
- Samples with `AdvancedHMC.NUTS` through `AbstractMCMC` (Threads or Serial) [@AdvancedHMC; @AbstractMCMC; @HoffmanGelman2014]
124+
- Emits summaries (incl. ESS and R-hat) via `MCMCChains`/`DataFrames` and quantiles to JSON
125+
[@MCMCChains; @DataFrames]
126+
- Timeout: worker process is killed if exceeding `timeout_s`.
127+
- Cleanup: `safe_rmdir()` retries with GC to avoid EBUSY on Windows.
128+
129+
## Why Vue (not React)?
130+
131+
The proposal planned React; we chose Vue 3 after evaluating the graph layer and developer velocity for this app.
132+
133+
- Tried Konva (canvas) for custom graph editing: powerful drawing primitives, but required bespoke graph semantics (hit testing, edge routing, compound nodes) that [Cytoscape.js](https://js.cytoscape.org/) provides out of the box.
134+
- Tried D3 force/layouts: flexible, but compound nodes (plates), nesting, and drag constraints became a significant amount of custom code to maintain.
135+
- [Cytoscape.js](https://js.cytoscape.org/) offered:
136+
- Native graph model with compound nodes (great for plates)
137+
- Integrated layouts (Dagre, fCoSE, Cola, KLay) and rich interaction APIs [@webcola; @elk]
138+
- Mature ecosystem and performance characteristics for medium-sized graphs
139+
- [Vue 3](https://vuejs.org/) (vs React) for this project:
140+
- Composition API made integrating an imperative graph library (Cytoscape) straightforward via composables and lifecycle hooks
141+
- SFC ergonomics and Pinia stores enabled quick iteration with strong TypeScript support
142+
- Template reactivity + refs reduced reconciliation overhead when bridging to Cytoscape’s imperative API
143+
- Minimal glue code for state management (Pinia) vs setting up reducers/selectors; enabled rapid iteration
144+
- Vite + Vue tooling yielded fast HMR for UI-heavy iterations
145+
- Design inspirations: draw.io for interaction affordances; Stan Playground for model/run UX [@drawio; @stan-playground].
146+
147+
## Comparison to Legacy DoodleBUGS
148+
149+
The legacy tool was a windows desktop application driving WinBUGS [@winbugs]; the new DoodleBUGS is a browser-based editor targeting JuliaBUGS [@JuliaBUGS].
150+
151+
![Legacy DoodleBUGS](Legacy-DoodleBUGS.png)
152+
153+
![New DoodleBUGS](New-DoodleBUGS.png)
154+
155+
Key differences:
156+
157+
- Platform and backend
158+
- Legacy: Desktop UI, WinBUGS execution pipeline
159+
- New: Web UI, Julia backend via `JuliaBUGS.@bugs`, sampling with `AdvancedHMC.NUTS` through `AbstractMCMC`
160+
- Graph engine and plates
161+
- Legacy: Bespoke graph handling with limited nesting semantics
162+
- New: [Cytoscape.js](https://js.cytoscape.org/) with compound nodes for robust nested plates; custom drag-and-drop for drag-in/out and creating inside plates
163+
- Layouts and interactions
164+
- Legacy: Limited auto-layout support
165+
- New: Multiple layout engines (Dagre, fCoSE, Cola, KLay) and stable interactions; positions updated after `layoutstop` [@webcola; @elk]
166+
- Code generation
167+
- Legacy: Export to BUGS without strong ordering guarantees
168+
- New: Deterministic topological + plate-aware traversal; parameter canonicalization and safe index expansion
169+
- Execution and tooling
170+
- Legacy: WinBUGS-managed runs
171+
- New: Lightweight Julia HTTP backend, configurable timeouts, resilient temp cleanup, JSON summaries via `MCMCChains`
172+
- DevX and maintainability
173+
- New: Vue 3 + TypeScript + Pinia; unified standalone script generation on the frontend; leaner backend responses
174+
175+
## Progress vs Proposal
176+
177+
- Implemented
178+
- Visual editor with nested plates and robust drag-and-drop
179+
- BUGS code generator (topological + plate-aware)
180+
- Local execution + summaries/quantiles
181+
- Unified standalone script generation (frontend)
182+
- Timeouts/resilience
183+
- Multiple layouts and interactions
184+
- Extensive cleanup/typing
185+
- Execution timeout (end-to-end)
186+
- Layout options (Dagre (default, layered), fCoSE (force-directed), Cola (physics simulation), KLay (layered)) and interactions
187+
- Cleanup and stronger typing
188+
- Changed
189+
- Vue 3 instead of React
190+
- Backend responses smaller; no standalone script attachment
191+
- Deferred/Partial
192+
- Visualizations: integrate with MCMCChains.jl for plots (trace, density, PPC, diagnostics). ESS and R-hat already included in summary statistics.
193+
- WebKit/Safari support
194+
- UX polish for large graphs
195+
196+
## How to Run Locally
197+
198+
Frontend (Vite):
199+
200+
```bash
201+
# from repo root
202+
cd DoodleBUGS
203+
npm install
204+
npm run dev
205+
```
206+
207+
Backend (Julia):
208+
209+
```bash
210+
# from repo root
211+
julia --project=DoodleBUGS/runtime DoodleBUGS/runtime/server.jl
212+
# server listens on http://localhost:8081
213+
```
214+
215+
Notes:
216+
217+
- CORS is enabled in the backend so the dev UI can call `http://localhost:8081`.
218+
- Try it here (static UI): [https://turinglang.org/JuliaBUGS.jl/DoodleBUGS/](https://turinglang.org/JuliaBUGS.jl/DoodleBUGS/)
219+
220+
## API Summary for Backend Server
221+
222+
- GET `/api/health``{ "status": "ok" }`
223+
- POST `/api/run` (alias: `/api/run_model`)
224+
- Body: `model_code`, `data` (JSON), `inits` (JSON), `data_string` (Julia literal), `inits_string` (Julia literal), `settings` `{ n_samples, n_adapts, n_chains, seed, timeout_s }`
225+
- Response: `{ success, summary, quantiles, logs, files[] }` where `files[]` contains `model.bugs`, `payload.json`, `run_script.jl`, `results.json`
226+
- Note: Frontend falls back to `/api/run_model` if `/api/run` is unavailable (404)
227+
228+
See `DoodleBUGS/runtime/server.jl`.
229+
230+
## Current Limitations
231+
232+
- WebKit/Safari/iOS: unsupported at this time (see `DoodleBUGS/README.md`).
233+
- Limited visualization beyond summary/quantiles.
234+
- Overlapped plates (nodes with multiple parent plates) are currently not supported; see [#362](https://github.com/TuringLang/JuliaBUGS.jl/issues/362).
235+
236+
## Future Work
237+
238+
- Backend: Add Pluto.jl as a backend for supporting compound documents and QuartoNotebookRunner.jl for running notebooks.
239+
- Diagnostics/visualization: integrate with MCMCChains.jl for plots (trace, density, PPC, diagnostics). ESS and R-hat already available in summary stats.
240+
- UX: richer node templates, validation, distribution hints
241+
- Sharing: shareable links/cloud sync (projects already persisted locally)
242+
- Browser compatibility: WebKit/Safari and iOS/iPadOS
243+
- Performance: virtualization for large graphs
244+
245+
## Acknowledgements
246+
247+
Much appreciation goes to my mentors Xianda Sun and Hong Ge. The work is impossible without your help and support.
248+
249+
- Mentors: Xianda Sun ([\@sunxd3](https://github.com/sunxd3)) and Hong Ge ([\@yebai](https://github.com/yebai))
250+
- TuringLang/JuliaBUGS community and contributors
251+
252+
## Appendix: Project Links
253+
254+
- Repo: [https://github.com/TuringLang/JuliaBUGS.jl](https://github.com/TuringLang/JuliaBUGS.jl)
255+
- Try it here: [https://turinglang.org/JuliaBUGS.jl/DoodleBUGS/](https://turinglang.org/JuliaBUGS.jl/DoodleBUGS/)
256+
257+
## PRs during GSoC:
258+
259+
- [#321 - Add ISSUE template for DoodleBUGS](https://github.com/TuringLang/JuliaBUGS.jl/pull/321)
260+
- [#339 - DoodleBUGS Project: Phase 1](https://github.com/TuringLang/JuliaBUGS.jl/pull/339)
261+
- [#340 - DoodleBUGS: update all workflows to run on relevent project only](https://github.com/TuringLang/JuliaBUGS.jl/pull/340)
262+
- [#341 - Exclude navigation bar from DoodleBUGS project](https://github.com/TuringLang/JuliaBUGS.jl/pull/341)
263+
- [#347 - DoodleBUGS: Basic Code Generation, Advanced Exports, and State Persistence](https://github.com/TuringLang/JuliaBUGS.jl/pull/347)
264+
- [#357 - DoodleBUGS: Allow Nested Plates, add new layouts and fix lot of linting issues](https://github.com/TuringLang/JuliaBUGS.jl/pull/357)
265+
- [#368 - New Folder Structure](https://github.com/TuringLang/JuliaBUGS.jl/pull/368)
266+
- [#388 - DoodleBUGS Project: Phase 2 (Backend) ](https://github.com/TuringLang/JuliaBUGS.jl/pull/388)
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
@misc{bugs-rjournal,
2+
title = {The BUGS Language},
3+
url = {https://journal.r-project.org/articles/RN-2006-005/RN-2006-005.pdf},
4+
note = {R Journal/News article}
5+
}
6+
7+
@misc{bugs-book,
8+
title = {The BUGS Book: A Practical Introduction to Bayesian Analysis},
9+
url = {https://onlinelibrary.wiley.com/doi/10.1111/anzs.12058},
10+
publisher = {Wiley}
11+
}
12+
13+
@misc{bugs-project,
14+
title = {The BUGS Project},
15+
url = {https://www.mrc-bsu.cam.ac.uk/software/bugs/}
16+
}
17+
18+
@misc{multibugs,
19+
title = {MultiBUGS: Parallel BUGS Modeling},
20+
url = {https://pmc.ncbi.nlm.nih.gov/articles/PMC7116196/}
21+
}
22+
23+
@misc{bugs-survival,
24+
title = {Bayesian survival analysis with BUGS},
25+
url = {https://onlinelibrary.wiley.com/doi/10.1002/sim.8933}
26+
}
27+
28+
@misc{albert-chib-1993,
29+
title = {Inference via Gibbs (Albert \& Chib)},
30+
url = {https://apps.olin.wustl.edu/faculty/chib/papers/albertchibjb93.pdf}
31+
}
32+
33+
@misc{informs-gibbs,
34+
title = {Bayesian Inference Using Gibbs Sampling},
35+
url = {https://pubsonline.informs.org/doi/10.1287/ited.2013.0120}
36+
}
37+
38+
@article{HoffmanGelman2014,
39+
title = {The No-U-Turn Sampler: Adaptively Setting Path Lengths in Hamiltonian Monte Carlo},
40+
author = {Hoffman, Matthew D. and Gelman, Andrew},
41+
year = {2014},
42+
url = {https://arxiv.org/abs/1111.4246},
43+
journal = {arXiv preprint arXiv:1111.4246}
44+
}
45+
46+
@misc{AbstractMCMC,
47+
title = {AbstractMCMC.jl},
48+
url = {https://github.com/TuringLang/AbstractMCMC.jl}
49+
}
50+
51+
@misc{AdvancedHMC,
52+
title = {AdvancedHMC.jl},
53+
url = {https://github.com/TuringLang/AdvancedHMC.jl}
54+
}
55+
56+
@misc{ReverseDiff,
57+
title = {ReverseDiff.jl},
58+
url = {https://github.com/JuliaDiff/ReverseDiff.jl}
59+
}
60+
61+
@misc{MCMCChains,
62+
title = {MCMCChains.jl},
63+
url = {https://github.com/TuringLang/MCMCChains.jl}
64+
}
65+
66+
@misc{DataFrames,
67+
title = {DataFrames.jl},
68+
url = {https://dataframes.juliadata.org/}
69+
}
70+
71+
@misc{cytoscapejs,
72+
title = {Cytoscape.js},
73+
url = {https://js.cytoscape.org/}
74+
}
75+
76+
@misc{webcola,
77+
title = {WebCola},
78+
url = {https://ialab.it.monash.edu/webcola/}
79+
}
80+
81+
@misc{elk,
82+
title = {Eclipse Layout Kernel (ELK / KLay)},
83+
url = {https://www.eclipse.org/elk/}
84+
}
85+
86+
@misc{drawio,
87+
title = {draw.io (diagrams.net)},
88+
url = {https://www.diagrams.net/}
89+
}
90+
91+
@misc{stan-playground,
92+
title = {Stan Playground},
93+
url = {https://stan-playground.flatironinstitute.org/}
94+
}
95+
96+
@misc{winbugs,
97+
title = {WinBUGS},
98+
url = {http://www.openbugs.net/w/FrontPage}
99+
}
100+
101+
@misc{JuliaBUGS,
102+
title = {JuliaBUGS.jl},
103+
url = {https://github.com/TuringLang/JuliaBUGS.jl}
104+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<style xmlns="http://purl.org/net/xbiblio/csl" version="1.0" default-locale="en-GB">
3+
<!-- This style was edited with the Visual CSL Editor (http://editor.citationstyles.org/visualEditor/) -->
4+
<info>
5+
<title>University of York - IEEE</title>
6+
<id>http://www.zotero.org/styles/university-of-york-ieee</id>
7+
<link href="http://www.zotero.org/styles/university-of-york-ieee" rel="self"/>
8+
<link href="http://www.zotero.org/styles/ieee" rel="independent-parent"/>
9+
<link href="https://subjectguides.york.ac.uk/referencing-style-guides/ieee" rel="documentation"/>
10+
<category citation-format="numeric"/>
11+
<category field="engineering"/>
12+
<updated>2025-07-11T09:55:45+00:00</updated>
13+
<rights license="http://creativecommons.org/licenses/by-sa/3.0/">This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License</rights>
14+
</info>
15+
</style>

0 commit comments

Comments
 (0)