diff --git a/.gitignore b/.gitignore index a307529d7..2f1c7a73a 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,5 @@ venv site_libs .DS_Store index_files -digest.txt \ No newline at end of file +digest.txt +**/*.quarto_ipynb diff --git a/assets/images/workflow/fff.png b/assets/images/workflow/fff.png new file mode 100644 index 000000000..539ea4d85 Binary files /dev/null and b/assets/images/workflow/fff.png differ diff --git a/index.qmd b/index.qmd index 9f825d860..cf8500db1 100644 --- a/index.qmd +++ b/index.qmd @@ -100,15 +100,20 @@ Turing is written entirely in Julia, and is interoperable with its powerful ecos ::: -::: {.code-window-title} +::: {.code-window-tabs} ```{=html} -linear_regression.jl +Model +Condition +Prior +Inference +Analysis ``` ::: ::: +::: {#tab-model .code-content .active} ```{.julia .code-overflow-scroll} using Turing @@ -122,11 +127,41 @@ using Turing μ = α .+ β .* x y ~ MvNormal(μ, σ² * I) end +``` +::: + +::: {#tab-condition .code-content} +```julia +# Data +x_data = rand(10) +y_data = rand(10) + +# Condition model on data +model = linear_regression(x_data) | (; y = y_data) +``` +::: + +::: {#tab-prior .code-content} +```julia +# Sample from the prior +prior = sample(model, Prior(), 100) +``` +::: + +::: {#tab-inference .code-content} +```julia +# Run inference using NUTS +chain = sample(model, NUTS(), 1000) +``` +::: -x, y = rand(10), rand(10) -posterior = linear_regression(x) | (; y = y) -chain = sample(posterior, NUTS(), 1000) +::: {#tab-analysis .code-content} +```julia +# Analyze the posterior +describe(chain) +plot(chain) ``` +::: ::: ::: @@ -134,7 +169,374 @@ chain = sample(posterior, NUTS(), 1000) ::: + +::: {.flowchart-section-custom} + +::: {.flowchart-header} +### The Bayesian Workflow +From model definition to posterior analysis, Turing.jl provides a seamless experience. +::: + +::: {.flowchart-container} + +```{=html} + + + + + + + +``` + +::: {#node-math .flow-node} +::: {.node-header} +Mathematical Specification +::: +::: {.node-body} +$$ +\begin{align*} + \sigma^2 &\sim \text{InverseGamma}(3, 4/10) \\ + \gamma &\sim \mathcal{N}(0, \sqrt{10}) \\ + \beta &\sim \mathcal{N}(0, I) \\ + y_i &\sim \log \mathcal{N}(\beta \cdot x_i + \gamma, \sigma) +\end{align*} +$$ +::: +::: + +::: {#node-model .flow-node} +::: {.node-header} +::: {.node-dots} +[]{.dot .red} []{.dot .yellow} []{.dot .green} +::: +linear_regression.jl +::: +::: {.node-body} +```julia +@model function linear_regression(x) + d = size(x, 1) + + # Priors + σ² ~ InverseGamma(3, 4 / 10) + γ ~ Normal(0, √10) + β ~ MvNormal(zeros(d), I) + + # Likelihood + y ~ MvLogNormal(x' * β .+ γ, σ² * I) +end + +model = linear_regression(x_data) +``` +::: +::: + +::: {#node-prior .flow-node} +::: {.node-header} +::: {.node-dots} +[]{.dot .red} []{.dot .yellow} []{.dot .green} +::: +Prior Checks +::: +::: {.node-body} +```julia +model_gen = fix(model, params_gen) +(; y) = rand(model_gen) +chain_gen = sample(model | (y = y,), NUTS(), 1000) +``` +::: +::: + +::: {#node-condition .flow-node} +::: {.node-header} +::: {.node-dots} +[]{.dot .red} []{.dot .yellow} []{.dot .green} +::: +Condition +::: +::: {.node-body} +```julia +model_conditioned = model | (y = y_data,) +``` +::: +::: + +::: {#node-determinability .flow-node} +::: {.node-header} +::: {.node-dots} +[]{.dot .red} []{.dot .yellow} []{.dot .green} +::: +Determinability +::: +::: {.node-body} +::: {.node-plot} +![](assets/images/workflow/fff.png){fig-alt="Determinability Plot"} +::: +::: +::: + +::: {#node-inference .flow-node} +::: {.node-header} +::: {.node-dots} +[]{.dot .red} []{.dot .yellow} []{.dot .green} +::: +Inference +::: +::: {.node-body} +```julia +chain = sample(model_conditioned, NUTS(), 1000) +``` +::: +::: + +::: {#node-analysis .flow-node} +::: {.node-header} +::: {.node-dots} +[]{.dot .red} []{.dot .yellow} []{.dot .green} +::: +Posterior Analysis +::: +::: {.node-body} +``` +Summary Statistics +parameters mean std mcse +σ² 0.0543 0.0032 0.0000 +γ 7.7252 0.3688 0.0066 +β[1] -0.2270 0.1247 0.0022 +β[2] 0.0133 0.1229 0.0022 +``` +::: {.node-plot} +![](assets/images/workflow/fff.png){fig-alt="Posterior Density"} +::: +::: +::: + +::: {#node-predictions .flow-node} +::: {.node-header} +::: {.node-dots} +[]{.dot .red} []{.dot .yellow} []{.dot .green} +::: +Posterior Predictions +::: +::: {.node-body} +::: {.node-plot} +![](assets/images/workflow/fff.png){fig-alt="Posterior Prediction"} +::: +::: +::: + +::: + +::: +```{=html} + +``` + + :::: {.section-header .section-start-space} diff --git a/theming/rules/_flowchart.scss b/theming/rules/_flowchart.scss new file mode 100644 index 000000000..cc5191c73 --- /dev/null +++ b/theming/rules/_flowchart.scss @@ -0,0 +1,186 @@ +.flowchart-section-custom { + padding: 4rem 0; + background-color: $body-bg; + transition: background-color 0.3s ease; + position: relative; +} + +.flowchart-header { + text-align: center; + margin-bottom: 3rem; + + h3 { + color: $text-color; + margin-bottom: 1rem; + } + + p { + color: $text-muted; + max-width: 700px; + margin: 0 auto; + } +} + +.flowchart-container { + position: relative; + display: grid; + grid-template-columns: 1fr 1fr; + column-gap: 8rem; + row-gap: 3rem; + max-width: 1100px; + margin: 0 auto; + padding: 2rem; + z-index: 1; +} + +/* SVG Overlay Layer */ +.flow-svg-layer { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + pointer-events: none; /* Let clicks pass through */ + z-index: 0; + overflow: visible; +} + +.flow-arrow-path { + fill: none; + stroke: $text-muted; // Using text-muted as a proxy for the line color + stroke-width: 2px; + transition: stroke 0.3s ease; + opacity: 0.5; +} + +.flow-arrow-head { + fill: $text-muted; + transition: fill 0.3s ease; + opacity: 0.5; +} + +.flow-node { + background: $panel-bg; + border-radius: 12px; + box-shadow: 0 4px 12px $box-shadow-color; + border: 1px solid $btn-border-color; + display: flex; + flex-direction: column; + transition: transform 0.2s, box-shadow 0.2s, border-color 0.2s; + z-index: 2; + position: relative; + + &:hover { + transform: translateY(-3px); + box-shadow: 0 12px 24px rgba(0,0,0,0.1); // Keep this generic or use a darker shadow var if available + border-color: $teal; + } +} + +// Dark mode specific hover shadow adjustment +body.quarto-dark .flow-node:hover { + box-shadow: 0 12px 24px rgba(0,0,0,0.5); +} + +.node-header { + padding: 0.75rem 1rem; + background: rgba(0,0,0,0.03); + border-bottom: 1px solid $btn-border-color; + font-family: "SF Mono", "Fira Code", monospace; + font-size: 0.85rem; + color: $text-muted; + display: flex; + align-items: center; + justify-content: space-between; + border-radius: 12px 12px 0 0; +} + +.node-dots { + display: flex; + gap: 6px; +} + +.node-body { + padding: 1rem; + font-size: 0.9rem; + color: $text-color; + + pre { + margin: 0 !important; + padding: 0 !important; + background: $code-block-bg !important; + border: none !important; + white-space: pre-wrap; + color: $text-color; + } +} + +/* Syntax Highlighting Adjustments for Dark Mode */ +body.quarto-dark .sourceCode { + .kw { color: #c792ea; } + .fu { color: #82aaff; } + .fl { color: #f78c6c; } + .st { color: #c3e88d; } + .op { color: #89ddff; } + .pp { color: #c792ea; } +} + +.node-plot { + margin-top: 1rem; + border: 1px solid $btn-border-color; + border-radius: 6px; + overflow: hidden; + background: white; // Plots are usually on white background + + img { + display: block; + width: 100%; + height: auto; + } +} + +/* Grid Positioning */ +#node-math { grid-column: 1; grid-row: 1; } +#node-model { grid-column: 2; grid-row: 1; } + +#node-prior { grid-column: 1; grid-row: 2; margin-top: 2rem; } +#node-condition { grid-column: 2; grid-row: 2; margin-top: 2rem; } + +#node-determinability { grid-column: 1; grid-row: 3; } +#node-inference { grid-column: 2; grid-row: 3; } + +#node-analysis { grid-column: 2; grid-row: 4; } +#node-predictions { grid-column: 2; grid-row: 5; } + +#node-math .node-body { + display: flex; + justify-content: center; + align-items: center; + font-size: 1.1rem; +} + +/* Responsive */ +@media (max-width: 992px) { + .flowchart-container { + grid-template-columns: 1fr; + gap: 3rem; + padding: 1rem; + } + + #node-math, #node-model, #node-prior, #node-condition, + #node-determinability, #node-inference, #node-analysis, #node-predictions { + grid-column: 1; + grid-row: auto; + margin-top: 0; + } + + /* Reorder for linear flow on mobile */ + #node-math { order: 1; } + #node-model { order: 2; } + #node-prior { order: 3; } + #node-determinability { order: 4; } + #node-condition { order: 5; } + #node-inference { order: 6; } + #node-analysis { order: 7; } + #node-predictions { order: 8; } +} diff --git a/theming/rules/_layouts.scss b/theming/rules/_layouts.scss index e7ebb441c..79a1f217c 100644 --- a/theming/rules/_layouts.scss +++ b/theming/rules/_layouts.scss @@ -184,6 +184,7 @@ align-items: center; border-bottom: 1px solid lighten($btn-border-color, 5%); position: relative; + justify-content: space-between; /* Changed to space-between to push tabs to right */ } .code-window-dots { @@ -200,14 +201,45 @@ font-size: 0.8rem; } - .dot { - width: 13px; - height: 13px; - border-radius: 50%; - display: inline-block; - &.red { background-color: #ff5f56; } - &.yellow { background-color: #ffbd2e; } - &.green { background-color: #27c93f; } + .code-window-tabs { + display: flex; + gap: 1rem; + z-index: 10; /* Ensure tabs are clickable above title if they overlap */ + } + + .tab { + cursor: pointer; + color: $text-muted; + font-size: 0.85rem; + font-weight: 600; + padding: 0.2rem 0.6rem; + border-radius: 4px; + transition: all 0.2s ease; + user-select: none; + + &:hover { + color: $text-color; + background-color: rgba(0,0,0,0.05); + } + + &.active { + color: $primary; + background-color: rgba($primary, 0.1); + } + } + + .code-content { + display: none; + + &.active { + display: block; + animation: fadeIn 0.3s ease; + } + } + + @keyframes fadeIn { + from { opacity: 0; } + to { opacity: 1; } } .sourceCode { @@ -229,6 +261,16 @@ } } +.dot { + width: 13px; + height: 13px; + border-radius: 50%; + display: inline-block; + &.red { background-color: #ff5f56; } + &.yellow { background-color: #ffbd2e; } + &.green { background-color: #27c93f; } +} + /* Core Packages Section */ .core-packages-grid { display: grid; @@ -326,41 +368,219 @@ white-space: nowrap; } -.unified-card-footer { - padding: 1rem 1.5rem; - border-top: 1px solid lighten($panel-bg, 7%); - display: flex; - justify-content: space-between; - align-items: center; - font-size: 0.85rem; - color: $text-muted; - background-color: $background-body; +/* Split View for Code and Plots */ +.split-view { + display: flex; + flex-direction: row; + align-items: stretch; + min-height: 350px; /* Ensure enough height for plot */ + background-color: $code-block-bg; } -.unified-card-meta { +.split-code { + flex: 1; + min-width: 0; /* Prevent overflow */ + display: flex; + flex-direction: column; + + /* Override quarto code block margins */ + div.sourceCode { + margin: 0 !important; + height: 100%; display: flex; flex-direction: column; - gap: 0.25rem; - min-width: 0; + } + + pre { flex-grow: 1; + margin: 0 !important; + border-radius: 0 0 0 4px !important; + } } -.unified-card-author { - font-weight: 600; - color: $text-color; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; +.split-plot { + flex: 1; + background-color: white; + display: flex; + align-items: center; + justify-content: center; + border-left: 1px solid darken($code-block-bg, 5%); + padding: 1rem; + + img { + max-width: 100%; + max-height: 100%; + height: auto; + object-fit: contain; + filter: drop-shadow(0 4px 6px rgba(0,0,0,0.1)); + } } -.unified-card-date { - font-size: 0.8rem; +/* Responsive: Stack on small screens */ +@media (max-width: 992px) { + .split-view { + flex-direction: column; + } + + .split-plot { + border-left: none; + border-top: 1px solid darken($code-block-bg, 5%); + min-height: 250px; + padding: 1.5rem; + } + + .split-code pre { + border-radius: 0 !important; + } +} + +/* Workflow Section Styles */ +.workflow-container { + display: grid; + grid-template-columns: 300px 1fr; + gap: 2rem; + align-items: start; +} + +.workflow-nav { + display: flex; + flex-direction: column; + position: relative; + padding: 1rem 0; +} + +.workflow-step { + display: flex; + align-items: center; + gap: 1rem; + padding: 1rem; + border-radius: 8px; + cursor: pointer; + transition: all 0.2s ease; + border: 1px solid transparent; + + &:hover { + background-color: rgba($primary, 0.05); + } + + &.active { + background-color: white; + border-color: $btn-border-color; + box-shadow: 0 4px 12px rgba(0,0,0,0.05); + + .step-marker { + background-color: $primary; + color: white; + border-color: $primary; + } + + .step-label { + color: $primary; + } + } +} + +.step-marker { + width: 32px; + height: 32px; + border-radius: 50%; + border: 2px solid $text-muted; + color: $text-muted; + display: flex; + align-items: center; + justify-content: center; + font-weight: 700; + font-size: 0.9rem; + flex-shrink: 0; + transition: all 0.2s ease; + background-color: white; + z-index: 2; +} + +.step-info { + display: flex; + flex-direction: column; +} + +.step-label { + font-weight: 700; + color: $text-color; + font-size: 1rem; + transition: color 0.2s ease; +} + +.step-desc { + font-size: 0.85rem; + color: $text-muted; + line-height: 1.3; +} + +.workflow-connector { + width: 2px; + height: 20px; + background-color: $border-color; + margin-left: 26px; /* Center with marker (16px + 1rem padding) */ + margin-top: -5px; + margin-bottom: -5px; + z-index: 1; +} + +.workflow-display { + min-height: 450px; + background-color: white; + overflow: hidden; +} + +.workflow-content { + display: none; + animation: fadeIn 0.3s ease; + + &.active { + display: block; + } +} + +.content-header { + padding: 1.5rem; + border-bottom: 1px solid $border-color; + + h5 { + margin-bottom: 0.5rem; + font-weight: 700; + } + + p { + margin-bottom: 0; color: $text-muted; + } } -.unified-card-reading-time { - font-weight: 600; - color: $teal; - white-space: nowrap; - font-size: 0.8rem; +@media (max-width: 992px) { + .workflow-container { + grid-template-columns: 1fr; + } + + .workflow-nav { + flex-direction: row; + overflow-x: auto; + padding-bottom: 1rem; + gap: 1rem; + } + + .workflow-step { + min-width: 200px; + flex-direction: column; + text-align: center; + align-items: center; + padding: 1rem; + border: 1px solid $border-color; + } + + .workflow-connector { + display: none; + } + + .step-marker { + margin-bottom: 0.5rem; + } } diff --git a/theming/theme-dark.scss b/theming/theme-dark.scss index f54f90524..e2088193c 100644 --- a/theming/theme-dark.scss +++ b/theming/theme-dark.scss @@ -16,6 +16,7 @@ @import "rules/quarto-tweaks"; @import "rules/responsive"; @import "rules/hoverables-dark"; +@import "rules/flowchart"; .hero-logo-light { display: none; diff --git a/theming/theme-light.scss b/theming/theme-light.scss index 3242b3f3a..076b6fac8 100644 --- a/theming/theme-light.scss +++ b/theming/theme-light.scss @@ -16,6 +16,7 @@ @import "rules/responsive"; @import "rules/quarto-tweaks"; @import "rules/hoverables-light"; +@import "rules/flowchart"; .hero-logo-light { display: block; diff --git a/workflow.md b/workflow.md new file mode 100644 index 000000000..cca78583d --- /dev/null +++ b/workflow.md @@ -0,0 +1,72 @@ +``` +\begin{align*} + \sigma^2 &\sim \text{InverseGamma}(3, 4/10) \\ + \gamma &\sim \mathcal{N}(0, \sqrt{10}) \\ + \beta &\sim \mathcal{N}(0, I) \\ + y_i &\sim \log \mathcal{N}(\beta \cdot x_i + \gamma, \sigma) \quad \text{for } i = 1, \dots, N +\end{align*} +``` + +to Turing.jl: + +Let's give id 1 to this block +```julia +@model function linear_regression(x) + d = size(x, 1) + + # Priors + σ² ~ InverseGamma(3, 4 / 10) + γ ~ Normal(0, √10) + β ~ MvNormal(zeros(d), I) + + # Likelihood + y ~ MvLogNormal(x' * β .+ γ, σ² * I) +end + +model = linear_regression(x_data) +``` + +From id 1 to Prior Checks: + +```julia +model_gen = fix(model, params_gen) +(; y) = rand(model_gen) +chain_gen = sample(model | (y = y,), NUTS(), 1000) +``` + +From Prior Checks to Determinability (ID 2): + +PLOT Image + +From ID 1, also goes Condition: + +```julia +model_conditioned = model | (y = y_data,) +``` + +Condtion to Perform Inference: + +```julia +chain = sample(model_conditioned, NUTS(), 1000) +``` + +Perform Inference to Post-inference Analysis: + +``` +Summary Statistics +parameters mean std mcse ... +Symbol Float64 Float64 Float64 ... + +σ² 0.0543 0.0032 0.0000 ... +γ 7.7252 0.3688 0.0066 ... +β[1] -0.2270 0.1247 0.0022 ... +β[2] 0.0133 0.1229 0.0022 ... +``` + +Plot Image + +Then to Posterior Predictions (ID 3): + +Plot image + +From ID 3 to ID 2 (Determinability) in a dashed line arrow with label "Iterate if necessary" \ No newline at end of file