diff --git a/docs.json b/docs.json index 20264e692c..d56a1200c9 100644 --- a/docs.json +++ b/docs.json @@ -180,6 +180,7 @@ "icon": "/icons/cropped-models.svg", "pages": [ "models", + "models/marimo", "models/quickstart", "models/models_quickstart", { diff --git a/index.mdx b/index.mdx index 59a1148817..7952331a2a 100644 --- a/index.mdx +++ b/index.mdx @@ -7,6 +7,7 @@ mode: wide import {Banner} from "/snippets/Banner.jsx"; import {HomeWrapper} from "/snippets/home.jsx"; import {ProductCard} from "/snippets/ProductCard.jsx"; +import {Marimo} from "/snippets/Marimo.jsx";
diff --git a/marimo-examples/matplotlib.txt b/marimo-examples/matplotlib.txt new file mode 100644 index 0000000000..9ff8a1581f --- /dev/null +++ b/marimo-examples/matplotlib.txt @@ -0,0 +1,27 @@ +```python +import matplotlib.pyplot as plt +import numpy as np + +from matplotlib import colors + +np.random.seed(19680801) + +datasets = [ + (i+1)/10 * np.random.rand(10, 20) + for i in range(4) +] + +fig, axs = plt.subplots(2, 2) +fig.suptitle('Multiple images') + +# create a single norm to be shared across all images +norm = colors.Normalize(vmin=np.min(datasets), vmax=np.max(datasets)) + +images = [] +for ax, data in zip(axs.flat, datasets): + images.append(ax.imshow(data, norm=norm)) + +fig.colorbar(images[0], ax=axs, orientation='horizontal', fraction=.1) + +plt.show() +``` \ No newline at end of file diff --git a/marimo-examples/quickstart.txt b/marimo-examples/quickstart.txt new file mode 100644 index 0000000000..a02e95208e --- /dev/null +++ b/marimo-examples/quickstart.txt @@ -0,0 +1,44 @@ +# /// script +# requires-python = ">=3.10" +# dependencies = [ +# "marimo", +# "numpy==2.2.6", +# "wandb==0.22.3", +# ] +# /// + + +```python +import ssl +import wandb +import random +``` + +```python +key = input("Enter your W&B API key: ") +wandb.login(key=key) +``` + + +```python +# Project that the run is recorded to +entity="entity" +project = "my-awesome-project" + +# Dictionary with hyperparameters +config = { + 'epochs' : 10, + 'lr' : 0.01 +} + +with wandb.init(project=project, config=config) as run: + offset = random.random() / 5 + print(f"lr: {config['lr']}") + + # Simulate a training run + for epoch in range(2, config['epochs']): + acc = 1 - 2**-config['epochs'] - random.random() / config['epochs'] - offset + loss = 2**-config['epochs'] + random.random() / config['epochs'] + offset + print(f"epoch={config['epochs']}, accuracy={acc}, loss={loss}") + run.log({"accuracy": acc, "loss": loss}) +``` \ No newline at end of file diff --git a/marimo-examples/slider-example.txt b/marimo-examples/slider-example.txt new file mode 100644 index 0000000000..334ddedbc5 --- /dev/null +++ b/marimo-examples/slider-example.txt @@ -0,0 +1,12 @@ +```python +import marimo as mo +``` + +```python +slider = mo.ui.slider(1, 10) +slider +``` + +```python +slider.value * "🍃" +``` diff --git a/models/marimo.mdx b/models/marimo.mdx new file mode 100644 index 0000000000..15aca2a074 --- /dev/null +++ b/models/marimo.mdx @@ -0,0 +1,58 @@ +--- +title: Marimo demos +description: Examples of Marimo rendering code snippets from molab notebooks and Marimo files. +--- +import {Marimo} from "/snippets/Marimo.jsx"; + +## Marimo preview using molab notebook URLs + +The following examples are rendered using iframes that link to molab notebook. Note that, these are static iframes and do not have the interactive features of Marimo. + +### Matplotlib example + + + +### Quickstart + + +## Marimo preview using molab app mode + +The following examples are rendered using iframes that link to molab notebook in app mode. If it works, these should be interactive. + +### Matplotlib example + + + +### Quickstart + + + +## Marimo preview injecting Marimo examples + +The following examples use Marimo to render code snippets directly from the Marimo files in the `/marimo-examples/` directory. To do this, we defined a `Marimo` React component that takes a `file` prop pointing to the Marimo file location. Note that these Marimo renderings have the full interactive features of Marimo. + +### Matplotlib example + + +### Quickstart + \ No newline at end of file diff --git a/models/quickstart.mdx b/models/quickstart.mdx index 6eace1c189..e197d5942c 100644 --- a/models/quickstart.mdx +++ b/models/quickstart.mdx @@ -125,4 +125,4 @@ Explore more features of the W&B ecosystem: 4. Automate hyperparameter searches and optimize models with [W&B Sweeps](/models/sweeps). 5. Analyze runs, visualize model predictions, and share insights on a [central dashboard](/models/tables). 6. Visit [W&B AI Academy](https://wandb.ai/site/courses/) to learn about LLMs, MLOps, and W&B Models through hands-on courses. -7. Visit [weave-docs.wandb.ai](/weave) to learn how to track track, experiment with, evaluate, deploy, and improve your LLM-based applications using Weave. +7. Visit [weave-docs.wandb.ai](/weave) to learn how to track track, experiment with, evaluate, deploy, and improve your LLM-based applications using Weave. \ No newline at end of file diff --git a/snippets/Marimo.jsx b/snippets/Marimo.jsx new file mode 100644 index 0000000000..94d5d1feaf --- /dev/null +++ b/snippets/Marimo.jsx @@ -0,0 +1,190 @@ +/** + * Marimo component - self-contained with all processing logic + * Loads content from external file and creates interactive notebook + * + * Usage: + * + */ +export const Marimo = ({ file }) => { + const containerRef = React.useRef(null); + const processedRef = React.useRef(false); + + React.useEffect(() => { + if (!file || typeof window === 'undefined' || processedRef.current) return; + + // Mark as processed to prevent double execution + processedRef.current = true; + + // Initialize global state on window object + if (typeof window !== 'undefined') { + window.__marimoState = window.__marimoState || { + scriptLoaded: false, + scriptLoading: false + }; + } + + // Function to load Marimo script if not already loaded + const loadMarimoScript = () => { + return new Promise((resolve) => { + if (window.__marimoState.scriptLoaded) { + resolve(); + return; + } + + if (window.__marimoState.scriptLoading) { + // Wait for the script to finish loading + const checkInterval = setInterval(() => { + if (window.__marimoState.scriptLoaded) { + clearInterval(checkInterval); + resolve(); + } + }, 100); + return; + } + + window.__marimoState.scriptLoading = true; + + // Add Marimo config + const configScript = document.createElement('script'); + configScript.type = "text/x-marimo-snippets-config"; + configScript.textContent = ` +configureMarimoButtons({title: "Open in a marimo notebook"}); +configureMarimoIframes({height: "400px"}); + `; + document.body.appendChild(configScript); + + // Load Marimo script + const script = document.createElement('script'); + script.src = "https://cdn.jsdelivr.net/npm/@marimo-team/marimo-snippets@1"; + script.type = "text/javascript"; + script.onload = () => { + window.__marimoState.scriptLoaded = true; + window.__marimoState.scriptLoading = false; + console.log('Marimo script loaded successfully from CDN'); + + // Check if the script actually loaded the functions we expect + if (typeof configureMarimoButtons === 'function') { + console.log('Marimo functions are available'); + } else { + console.log('Warning: Marimo functions not found after script load'); + } + + // Trigger DOMContentLoaded for Marimo to process existing elements + setTimeout(() => { + console.log('Triggering initial DOMContentLoaded after script load'); + document.dispatchEvent(new Event('DOMContentLoaded')); + }, 100); + + resolve(); + }; + script.onerror = () => { + window.__marimoState.scriptLoading = false; + console.error('Failed to load Marimo script'); + resolve(); // Resolve anyway to not block + }; + document.body.appendChild(script); + }); + }; + + // Main processing function + const processMarimo = async () => { + try { + // Fetch the content + console.log(`Fetching Marimo content from: ${file}`); + const response = await fetch(file); + + if (!response.ok) { + throw new Error(`Failed to load: ${response.status} ${response.statusText}`); + } + + const content = await response.text(); + console.log(`Fetched ${content.length} characters from ${file}`); + + // Create marimo-iframe element + const marimoIframe = document.createElement('marimo-iframe'); + + // Parse markdown and create HTML elements + const codeBlockRegex = /```python\n([\s\S]*?)\n```/g; + let match; + let blockCount = 0; + + while ((match = codeBlockRegex.exec(content)) !== null) { + const pre = document.createElement('pre'); + const code = document.createElement('code'); + code.className = 'language-python'; + code.textContent = match[1]; + pre.appendChild(code); + marimoIframe.appendChild(pre); + blockCount++; + } + + console.log(`Created marimo-iframe with ${blockCount} code blocks`); + + // Load Marimo script first + await loadMarimoScript(); + + // Clear container and add marimo-iframe + if (containerRef.current) { + // Clear the loading message and remove loading styles + containerRef.current.innerHTML = ''; + containerRef.current.style.padding = ''; + containerRef.current.style.background = ''; + containerRef.current.style.borderRadius = ''; + + // Add the marimo-iframe + containerRef.current.appendChild(marimoIframe); + console.log('Added marimo-iframe to DOM, element exists:', !!document.querySelector('marimo-iframe')); + + // Trigger DOMContentLoaded for this new element + setTimeout(() => { + const marimoElements = document.querySelectorAll('marimo-iframe'); + console.log(`Found ${marimoElements.length} marimo-iframe elements before triggering DOMContentLoaded`); + + document.dispatchEvent(new Event('DOMContentLoaded')); + + // Check if successful + setTimeout(() => { + const frames = document.querySelectorAll('iframe[src*="marimo.app"]'); + if (frames.length > 0) { + console.log(`Success! Marimo created ${frames.length} iframe(s)`); + } else { + console.log('No Marimo iframes created. Checking marimo-iframe elements still exist...'); + const stillExists = document.querySelectorAll('marimo-iframe'); + console.log(`${stillExists.length} marimo-iframe elements still in DOM`); + } + }, 1000); + }, 200); + } + } catch (err) { + console.error('Error processing Marimo:', err); + if (containerRef.current) { + containerRef.current.innerHTML = ` +
+ Failed to load Marimo notebook: ${err.message} +
+ `; + } + } + }; + + // Start processing after a short delay to ensure component is mounted + const timer = setTimeout(processMarimo, 100); + + return () => clearTimeout(timer); + }, [file]); + + // Render container with initial loading message + return ( +
+ Loading Marimo notebook... +
+ ); +};