diff --git a/news/posts/2025-09-01-GSoC-Report-DoodleBUGS/DoodleBUGS.png b/news/posts/2025-09-01-GSoC-Report-DoodleBUGS/DoodleBUGS.png new file mode 100644 index 000000000..6aca1b9ba Binary files /dev/null and b/news/posts/2025-09-01-GSoC-Report-DoodleBUGS/DoodleBUGS.png differ diff --git a/news/posts/2025-09-01-GSoC-Report-DoodleBUGS/Legacy-DoodleBUGS.png b/news/posts/2025-09-01-GSoC-Report-DoodleBUGS/Legacy-DoodleBUGS.png new file mode 100644 index 000000000..22c71ff3d Binary files /dev/null and b/news/posts/2025-09-01-GSoC-Report-DoodleBUGS/Legacy-DoodleBUGS.png differ diff --git a/news/posts/2025-09-01-GSoC-Report-DoodleBUGS/New-DoodleBUGS.png b/news/posts/2025-09-01-GSoC-Report-DoodleBUGS/New-DoodleBUGS.png new file mode 100644 index 000000000..d6d4925c8 Binary files /dev/null and b/news/posts/2025-09-01-GSoC-Report-DoodleBUGS/New-DoodleBUGS.png differ diff --git a/news/posts/2025-09-01-GSoC-Report-DoodleBUGS/index.qmd b/news/posts/2025-09-01-GSoC-Report-DoodleBUGS/index.qmd new file mode 100644 index 000000000..644c42362 --- /dev/null +++ b/news/posts/2025-09-01-GSoC-Report-DoodleBUGS/index.qmd @@ -0,0 +1,266 @@ +--- +title: "GSoC Report for DoodleBUGS: a Browser-Based Graphical Interface for Drawing Probabilistic Graphical Models" +description: "Shravan Goswami's GSoC 2025 final report: goals, architecture, progress vs proposal, and how to try it." +toc: true +categories: + - GSoC + - Blog +author: + - name: Shravan Goswami + url: https://shravangoswami.com/ +date: 2025-09-01 +aliases: + - /GSoC-2025-Report-DoodleBUGS # submitted this to GSoC so please remember to update incase moving this page somewhere else +bibliography: references.bib +csl: university-of-york-ieee.csl +link-citations: true +nocite: | + @* +--- + +## TL;DR + +- 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. +- 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. +- Changed from proposal: frontend implemented in Vue 3 (instead of React); backend simplified (frontend is the single source of truth for standalone scripts). +- 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. + +## DoodleBUGS UI + +![DoodleBUGS UI](DoodleBUGS.png) + +## DoodleBUGS Project Structure + +```{.bash} +DoodleBUGS/ # Vite + Vue 3 app (UI editor) +├── README.md # project documentation +├── public/ # static assets served by Vite +│ └── examples/ # example projects +├── experiments/ # prototypes and exploratory work +├── runtime/ # Julia HTTP backend (API endpoints & dependencies) +├── src/ # application source +│ ├── assets/ # styles and static assets +│ ├── components/ # Vue components composing the UI +│ │ ├── canvas/ # graph canvas and toolbars +│ │ ├── common/ # shared UI primitives +│ │ ├── layouts/ # app layout and modals +│ │ │ └── MainLayout.vue # main application layout +│ │ ├── left-sidebar/ # palette, project manager, execution settings +│ │ ├── panels/ # code preview and data input panels +│ │ ├── right-sidebar/ # execution, JSON editor, node properties +│ │ └── ui/ # base UI elements (buttons, inputs, selects) +│ ├── composables/ # reusable logic (codegen, drag & drop, graph, validator, grid) +│ ├── config/ # configuration and node definitions +│ ├── stores/ # Pinia state stores (graph, data, execution, project, UI) +│ └── types/ # TypeScript types and ambient declarations +├── tmp/ # local temporary outputs (ignored in builds) +└── ztest/ # scratch/test artifacts +``` + +## Motivation + +[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: + +- Construct probabilistic graphical models visually (nodes, edges, plates). +- Export readable legacy BUGS code that compiles with JuliaBUGS [@JuliaBUGS; @bugs-rjournal; @bugs-book]. +- 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]. + +## What Was Built + +- Visual editor + - Node types: stochastic, observed, deterministic + - Plates with arbitrary nesting; robust drag-in/out and creation inside plates + - Graph layouts: Dagre (default), fCoSE (Force-Directed), Cola (Physics Simulation), KLay (Layered); stable interactions +- Legacy BUGS code generation [@bugs-rjournal; @bugs-book] + - Topological ordering and plate-aware traversal + - Parameter formatting and safe index expansion + - Implemented in `DoodleBUGS/src/composables/useBugsCodeGenerator.ts` +- Execution flow + - 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`. + - 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`. + - 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. +- Timeouts/resilience + - Configurable timeout (frontend); enforced in backend worker + - Safe temp directory cleanup on Windows with retries +- Cleanup/typing + - Strong, project-wide TypeScript typing across stores, components, and composables + - Removal of unused backend code; consistent naming and logs + +## Architecture Overview + +- Frontend: [Vue 3](https://vuejs.org/), [Pinia](https://pinia.vuejs.org/), [Cytoscape.js](https://js.cytoscape.org/) [@cytoscapejs], [CodeMirror](https://codemirror.net/) + - Code generation: `DoodleBUGS/src/composables/useBugsCodeGenerator.ts` + - Execution panel: `DoodleBUGS/src/components/right-sidebar/ExecutionPanel.vue` +- Backend (Julia) HTTP server + - Server: `DoodleBUGS/runtime/server.jl` + - Project deps: `DoodleBUGS/runtime/Project.toml` (HTTP, JSON3, JuliaBUGS, AbstractMCMC, AdvancedHMC, ReverseDiff, MCMCChains, DataFrames, StatsBase, Statistics) + - Endpoints: GET `/api/health`; POST `/api/run` and `/api/run_model` + - Execution: creates temp dir, writes `model.bugs` and `payload.json`, generates `run_script.jl`, enforces optional timeout + +## Design Principles and Architecture + +**Design principles** + +- Visual-first modeling with deterministic export to legacy BUGS [@bugs-rjournal; @bugs-book]. +- Separation of concerns: editing (graph), generation (BUGS), execution (backend), and results (summary/quantiles) are modular. +- Deterministic ordering: topological sort + plate-aware traversal ensures readable, stable code output. +- Robustness: cancellable frontend fetch, backend-enforced timeout, and resilient temp cleanup on Windows (`safe_rmdir()`). + +**Frontend architecture (Vue 3 + Cytoscape.js)** + +- 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]. +- Code generation lives in `DoodleBUGS/src/composables/useBugsCodeGenerator.ts` and maps `GraphNode`/`GraphEdge` to BUGS: + - Kahn topological sort for definition order + - Plate-aware recursion for `for (...) { ... }` blocks + - Parameter canonicalization (indices, numeric/expr passthrough) +- Standalone Julia script generation uses `generateStandaloneScript()` in the same composable, mirroring backend execution. + +**Backend architecture (Julia)** + +- `run_model_handler()` in `DoodleBUGS/runtime/server.jl` materializes `model.bugs`, `payload.json`, and a transient `run_script.jl` that: + - Builds `NamedTuple`s from JSON or string-literal data/inits + - Compiles via `JuliaBUGS.@bugs`, wraps with `ADgradient(:ReverseDiff)` [@ReverseDiff] + - Samples with `AdvancedHMC.NUTS` through `AbstractMCMC` (Threads or Serial) [@AdvancedHMC; @AbstractMCMC; @HoffmanGelman2014] + - Emits summaries (incl. ESS and R-hat) via `MCMCChains`/`DataFrames` and quantiles to JSON + [@MCMCChains; @DataFrames] + - Timeout: worker process is killed if exceeding `timeout_s`. + - Cleanup: `safe_rmdir()` retries with GC to avoid EBUSY on Windows. + +## Why Vue (not React)? + +The proposal planned React; we chose Vue 3 after evaluating the graph layer and developer velocity for this app. + +- 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. +- Tried D3 force/layouts: flexible, but compound nodes (plates), nesting, and drag constraints became a significant amount of custom code to maintain. +- [Cytoscape.js](https://js.cytoscape.org/) offered: + - Native graph model with compound nodes (great for plates) + - Integrated layouts (Dagre, fCoSE, Cola, KLay) and rich interaction APIs [@webcola; @elk] + - Mature ecosystem and performance characteristics for medium-sized graphs +- [Vue 3](https://vuejs.org/) (vs React) for this project: + - Composition API made integrating an imperative graph library (Cytoscape) straightforward via composables and lifecycle hooks + - SFC ergonomics and Pinia stores enabled quick iteration with strong TypeScript support + - Template reactivity + refs reduced reconciliation overhead when bridging to Cytoscape’s imperative API + - Minimal glue code for state management (Pinia) vs setting up reducers/selectors; enabled rapid iteration + - Vite + Vue tooling yielded fast HMR for UI-heavy iterations +- Design inspirations: draw.io for interaction affordances; Stan Playground for model/run UX [@drawio; @stan-playground]. + +## Comparison to Legacy DoodleBUGS + +The legacy tool was a windows desktop application driving WinBUGS [@winbugs]; the new DoodleBUGS is a browser-based editor targeting JuliaBUGS [@JuliaBUGS]. + +![Legacy DoodleBUGS](Legacy-DoodleBUGS.png) + +![New DoodleBUGS](New-DoodleBUGS.png) + +Key differences: + +- Platform and backend + - Legacy: Desktop UI, WinBUGS execution pipeline + - New: Web UI, Julia backend via `JuliaBUGS.@bugs`, sampling with `AdvancedHMC.NUTS` through `AbstractMCMC` +- Graph engine and plates + - Legacy: Bespoke graph handling with limited nesting semantics + - 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 +- Layouts and interactions + - Legacy: Limited auto-layout support + - New: Multiple layout engines (Dagre, fCoSE, Cola, KLay) and stable interactions; positions updated after `layoutstop` [@webcola; @elk] +- Code generation + - Legacy: Export to BUGS without strong ordering guarantees + - New: Deterministic topological + plate-aware traversal; parameter canonicalization and safe index expansion +- Execution and tooling + - Legacy: WinBUGS-managed runs + - New: Lightweight Julia HTTP backend, configurable timeouts, resilient temp cleanup, JSON summaries via `MCMCChains` +- DevX and maintainability + - New: Vue 3 + TypeScript + Pinia; unified standalone script generation on the frontend; leaner backend responses + +## Progress vs Proposal + +- Implemented + - Visual editor with nested plates and robust drag-and-drop + - BUGS code generator (topological + plate-aware) + - Local execution + summaries/quantiles + - Unified standalone script generation (frontend) + - Timeouts/resilience + - Multiple layouts and interactions + - Extensive cleanup/typing + - Execution timeout (end-to-end) + - Layout options (Dagre (default, layered), fCoSE (force-directed), Cola (physics simulation), KLay (layered)) and interactions + - Cleanup and stronger typing +- Changed + - Vue 3 instead of React + - Backend responses smaller; no standalone script attachment +- Deferred/Partial + - Visualizations: integrate with MCMCChains.jl for plots (trace, density, PPC, diagnostics). ESS and R-hat already included in summary statistics. + - WebKit/Safari support + - UX polish for large graphs + +## How to Run Locally + +Frontend (Vite): + +```bash +# from repo root +cd DoodleBUGS +npm install +npm run dev +``` + +Backend (Julia): + +```bash +# from repo root +julia --project=DoodleBUGS/runtime DoodleBUGS/runtime/server.jl +# server listens on http://localhost:8081 +``` + +Notes: + +- CORS is enabled in the backend so the dev UI can call `http://localhost:8081`. +- Try it here (static UI): [https://turinglang.org/JuliaBUGS.jl/DoodleBUGS/](https://turinglang.org/JuliaBUGS.jl/DoodleBUGS/) + +## API Summary for Backend Server + +- GET `/api/health` → `{ "status": "ok" }` +- POST `/api/run` (alias: `/api/run_model`) + - 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 }` + - Response: `{ success, summary, quantiles, logs, files[] }` where `files[]` contains `model.bugs`, `payload.json`, `run_script.jl`, `results.json` + - Note: Frontend falls back to `/api/run_model` if `/api/run` is unavailable (404) + +See `DoodleBUGS/runtime/server.jl`. + +## Current Limitations + +- WebKit/Safari/iOS: unsupported at this time (see `DoodleBUGS/README.md`). +- Limited visualization beyond summary/quantiles. +- Overlapped plates (nodes with multiple parent plates) are currently not supported; see [#362](https://github.com/TuringLang/JuliaBUGS.jl/issues/362). + +## Future Work + +- Backend: Add Pluto.jl as a backend for supporting compound documents and QuartoNotebookRunner.jl for running notebooks. +- Diagnostics/visualization: integrate with MCMCChains.jl for plots (trace, density, PPC, diagnostics). ESS and R-hat already available in summary stats. +- UX: richer node templates, validation, distribution hints +- Sharing: shareable links/cloud sync (projects already persisted locally) +- Browser compatibility: WebKit/Safari and iOS/iPadOS +- Performance: virtualization for large graphs + +## Acknowledgements + +Much appreciation goes to my mentors Xianda Sun and Hong Ge. The work is impossible without your help and support. + +- Mentors: Xianda Sun ([\@sunxd3](https://github.com/sunxd3)) and Hong Ge ([\@yebai](https://github.com/yebai)) +- TuringLang/JuliaBUGS community and contributors + +## Appendix: Project Links + +- Repo: [https://github.com/TuringLang/JuliaBUGS.jl](https://github.com/TuringLang/JuliaBUGS.jl) +- Try it here: [https://turinglang.org/JuliaBUGS.jl/DoodleBUGS/](https://turinglang.org/JuliaBUGS.jl/DoodleBUGS/) + +## PRs during GSoC: + +- [#321 - Add ISSUE template for DoodleBUGS](https://github.com/TuringLang/JuliaBUGS.jl/pull/321) +- [#339 - DoodleBUGS Project: Phase 1](https://github.com/TuringLang/JuliaBUGS.jl/pull/339) +- [#340 - DoodleBUGS: update all workflows to run on relevent project only](https://github.com/TuringLang/JuliaBUGS.jl/pull/340) +- [#341 - Exclude navigation bar from DoodleBUGS project](https://github.com/TuringLang/JuliaBUGS.jl/pull/341) +- [#347 - DoodleBUGS: Basic Code Generation, Advanced Exports, and State Persistence](https://github.com/TuringLang/JuliaBUGS.jl/pull/347) +- [#357 - DoodleBUGS: Allow Nested Plates, add new layouts and fix lot of linting issues](https://github.com/TuringLang/JuliaBUGS.jl/pull/357) +- [#368 - New Folder Structure](https://github.com/TuringLang/JuliaBUGS.jl/pull/368) +- [#388 - DoodleBUGS Project: Phase 2 (Backend) ](https://github.com/TuringLang/JuliaBUGS.jl/pull/388) diff --git a/news/posts/2025-09-01-GSoC-Report-DoodleBUGS/references.bib b/news/posts/2025-09-01-GSoC-Report-DoodleBUGS/references.bib new file mode 100644 index 000000000..906ed0998 --- /dev/null +++ b/news/posts/2025-09-01-GSoC-Report-DoodleBUGS/references.bib @@ -0,0 +1,104 @@ +@misc{bugs-rjournal, + title = {The BUGS Language}, + url = {https://journal.r-project.org/articles/RN-2006-005/RN-2006-005.pdf}, + note = {R Journal/News article} +} + +@misc{bugs-book, + title = {The BUGS Book: A Practical Introduction to Bayesian Analysis}, + url = {https://onlinelibrary.wiley.com/doi/10.1111/anzs.12058}, + publisher = {Wiley} +} + +@misc{bugs-project, + title = {The BUGS Project}, + url = {https://www.mrc-bsu.cam.ac.uk/software/bugs/} +} + +@misc{multibugs, + title = {MultiBUGS: Parallel BUGS Modeling}, + url = {https://pmc.ncbi.nlm.nih.gov/articles/PMC7116196/} +} + +@misc{bugs-survival, + title = {Bayesian survival analysis with BUGS}, + url = {https://onlinelibrary.wiley.com/doi/10.1002/sim.8933} +} + +@misc{albert-chib-1993, + title = {Inference via Gibbs (Albert \& Chib)}, + url = {https://apps.olin.wustl.edu/faculty/chib/papers/albertchibjb93.pdf} +} + +@misc{informs-gibbs, + title = {Bayesian Inference Using Gibbs Sampling}, + url = {https://pubsonline.informs.org/doi/10.1287/ited.2013.0120} +} + +@article{HoffmanGelman2014, + title = {The No-U-Turn Sampler: Adaptively Setting Path Lengths in Hamiltonian Monte Carlo}, + author = {Hoffman, Matthew D. and Gelman, Andrew}, + year = {2014}, + url = {https://arxiv.org/abs/1111.4246}, + journal = {arXiv preprint arXiv:1111.4246} +} + +@misc{AbstractMCMC, + title = {AbstractMCMC.jl}, + url = {https://github.com/TuringLang/AbstractMCMC.jl} +} + +@misc{AdvancedHMC, + title = {AdvancedHMC.jl}, + url = {https://github.com/TuringLang/AdvancedHMC.jl} +} + +@misc{ReverseDiff, + title = {ReverseDiff.jl}, + url = {https://github.com/JuliaDiff/ReverseDiff.jl} +} + +@misc{MCMCChains, + title = {MCMCChains.jl}, + url = {https://github.com/TuringLang/MCMCChains.jl} +} + +@misc{DataFrames, + title = {DataFrames.jl}, + url = {https://dataframes.juliadata.org/} +} + +@misc{cytoscapejs, + title = {Cytoscape.js}, + url = {https://js.cytoscape.org/} +} + +@misc{webcola, + title = {WebCola}, + url = {https://ialab.it.monash.edu/webcola/} +} + +@misc{elk, + title = {Eclipse Layout Kernel (ELK / KLay)}, + url = {https://www.eclipse.org/elk/} +} + +@misc{drawio, + title = {draw.io (diagrams.net)}, + url = {https://www.diagrams.net/} +} + +@misc{stan-playground, + title = {Stan Playground}, + url = {https://stan-playground.flatironinstitute.org/} +} + +@misc{winbugs, + title = {WinBUGS}, + url = {http://www.openbugs.net/w/FrontPage} +} + +@misc{JuliaBUGS, + title = {JuliaBUGS.jl}, + url = {https://github.com/TuringLang/JuliaBUGS.jl} +} diff --git a/news/posts/2025-09-01-GSoC-Report-DoodleBUGS/university-of-york-ieee.csl b/news/posts/2025-09-01-GSoC-Report-DoodleBUGS/university-of-york-ieee.csl new file mode 100644 index 000000000..9fce5957b --- /dev/null +++ b/news/posts/2025-09-01-GSoC-Report-DoodleBUGS/university-of-york-ieee.csl @@ -0,0 +1,15 @@ + + diff --git a/team/team.yml b/team/team.yml index b05850161..b1d6d2685 100644 --- a/team/team.yml +++ b/team/team.yml @@ -227,6 +227,22 @@ # GSOC Contributors: - title: Google Summer of Code Students + subtitle: GSoC 2025 + members: + - name: Shravan Goswami + image: shravan-goswami.jpg + university: Uka Tarsadia University + gsoc_project: "DoodleBUGS: a Browser-Based Graphical Interface for JuliaBUGS" + gsoc_project_link: + gsoc_report: /news/posts/2025-08-28-DoodleBUGS-Introduction/index.html + links: + - website: https://shravangoswami.com/ + - github: https://github.com/shravanngoswamii + - twitter: https://twitter.com/shravangoswamii + - linkedin: https://www.linkedin.com/in/shravangoswami/ + - mail: shravanngoswamii@gmail.com + +- title: subtitle: GSoC 2023 members: - name: Zuheng(David) Xu diff --git a/theming/variables/_colors-dark.scss b/theming/variables/_colors-dark.scss index a535ebb5a..cbb4ba34b 100644 --- a/theming/variables/_colors-dark.scss +++ b/theming/variables/_colors-dark.scss @@ -11,7 +11,7 @@ $box-shadow-color: rgba(0, 0, 0, 0.4); $background-body: #1c2128; // Use the main page background for code blocks to ensure consistency -$code-block-bg: $background-body; +$code-block-bg: #212529; // Define the background for panels, making them stand out slightly $panel-bg: $gray-900; diff --git a/theming/variables/_colors-light.scss b/theming/variables/_colors-light.scss index d3a3bd6be..51fb1ff7a 100644 --- a/theming/variables/_colors-light.scss +++ b/theming/variables/_colors-light.scss @@ -9,7 +9,7 @@ $links-hover: lighten($links, 10%); $box-shadow-color: rgba(0, 0, 0, 0.06); -$code-block-bg: $gray-100; +$code-block-bg: #f1f3f5; $panel-bg: $white;