GSoC Report for DoodleBUGS: a Browser-Based Graphical Interface for Drawing Probabilistic Graphical Models

GSoC
Blog
Shravan Goswami’s GSoC 2025 final report: goals, architecture, progress vs proposal, and how to try it.
Author
Published

September 1, 2025

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 [1], [2], 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/. For local inference, run the backend server.

DoodleBUGS UI

DoodleBUGS UI

DoodleBUGS Project Structure

Directory Structure
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 is a modern Julia implementation of the BUGS language [2], [3], [4]. 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 [1], [2], [3].
  • Run inference and inspect results from the UI. Common BUGS applications include parallel MCMC [5], survival analysis [6], and Gibbs-style samplers [7], [8].

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 [2], [3]
    • 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, Pinia, Cytoscape.js [9], CodeMirror
    • 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 [2], [3].
  • 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 handles layout, hit-testing, and interaction semantics (including compound nodes for plates) [9].
  • 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 NamedTuples from JSON or string-literal data/inits
    • Compiles via JuliaBUGS.@bugs, wraps with ADgradient(:ReverseDiff) [10]
    • Samples with AdvancedHMC.NUTS through AbstractMCMC (Threads or Serial) [11], [12], [13]
    • Emits summaries (incl. ESS and R-hat) via MCMCChains/DataFrames and quantiles to JSON [14], [15]
    • 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 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 offered:
    • Native graph model with compound nodes (great for plates)
    • Integrated layouts (Dagre, fCoSE, Cola, KLay) and rich interaction APIs [16], [17]
    • Mature ecosystem and performance characteristics for medium-sized graphs
  • Vue 3 (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 [18], [19].

Comparison to Legacy DoodleBUGS

The legacy tool was a windows desktop application driving WinBUGS [20]; the new DoodleBUGS is a browser-based editor targeting JuliaBUGS [1].

Legacy DoodleBUGS

New DoodleBUGS

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 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 [16], [17]
  • 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):

# from repo root
cd DoodleBUGS
npm install
npm run dev

Backend (Julia):

# from repo root
julia --project=DoodleBUGS/runtime DoodleBUGS/runtime/server.jl
# server listens on http://localhost:8081

Notes:

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.

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) and Hong Ge (@yebai)
  • TuringLang/JuliaBUGS community and contributors

PRs during GSoC:

Back to top

References

[1]
“JuliaBUGS.jl.” Available: https://github.com/TuringLang/JuliaBUGS.jl
[2]
“The BUGS book: A practical introduction to bayesian analysis.” Wiley. Available: https://onlinelibrary.wiley.com/doi/10.1111/anzs.12058
[3]
[4]
“The BUGS project.” Available: https://www.mrc-bsu.cam.ac.uk/software/bugs/
[5]
“MultiBUGS: Parallel BUGS modeling.” Available: https://pmc.ncbi.nlm.nih.gov/articles/PMC7116196/
[6]
“Bayesian survival analysis with BUGS.” Available: https://onlinelibrary.wiley.com/doi/10.1002/sim.8933
[7]
“Inference via gibbs (albert & chib).” Available: https://apps.olin.wustl.edu/faculty/chib/papers/albertchibjb93.pdf
[8]
“Bayesian inference using gibbs sampling.” Available: https://pubsonline.informs.org/doi/10.1287/ited.2013.0120
[9]
“Cytoscape.js.” Available: https://js.cytoscape.org/
[10]
“ReverseDiff.jl.” Available: https://github.com/JuliaDiff/ReverseDiff.jl
[11]
“AdvancedHMC.jl.” Available: https://github.com/TuringLang/AdvancedHMC.jl
[12]
“AbstractMCMC.jl.” Available: https://github.com/TuringLang/AbstractMCMC.jl
[13]
M. D. Hoffman and A. Gelman, “The no-u-turn sampler: Adaptively setting path lengths in hamiltonian monte carlo,” arXiv preprint arXiv:1111.4246, 2014, Available: https://arxiv.org/abs/1111.4246
[14]
“MCMCChains.jl.” Available: https://github.com/TuringLang/MCMCChains.jl
[15]
“DataFrames.jl.” Available: https://dataframes.juliadata.org/
[16]
“WebCola.” Available: https://ialab.it.monash.edu/webcola/
[17]
“Eclipse layout kernel (ELK / KLay).” Available: https://www.eclipse.org/elk/
[18]
“Draw.io (diagrams.net).” Available: https://www.diagrams.net/
[19]
“Stan playground.” Available: https://stan-playground.flatironinstitute.org/
[20]
“WinBUGS.” Available: http://www.openbugs.net/w/FrontPage