observable_plot - Split View
from fasthtml.common import *
import numpy as np

plot_js = """
function createPlot(data) {
    const plot = Plot.rectY(data, Plot.binX({y: "count"},{x: d => d.value,fill:"steelblue"})).plot();
    const div = document.querySelector("#plot");
    div.replaceChildren(plot);
}

// Set up initial load via HTMX
htmx.on('htmx:afterSettle', evt => {
    if (evt.detail.target.id === 'data-store') {
        // The data is now properly JSON-encoded
        const data = JSON.parse(evt.detail.target.textContent);
        createPlot(data);
    }
});
"""

app, rt = fast_app(
    hdrs=(Script(src="https://cdn.jsdelivr.net/npm/d3@7"),
          Script(src="https://cdn.jsdelivr.net/npm/@observablehq/[email protected]")))

@rt
def index():
    return Div(
        Section(
            H1(A("Observable", href="https://observablehq.com/@observablehq/plot", target="_blank"), " Plot Demo"),
            P("The data is randomly generated on the server and is fetched on initial page load."),
            P("Try opening the browser developer tools and viewing the Network tab to see the data reponse for each http request."),
            # On bytton click it sends a get request to the `get_data` route and puts the response in the `data-store` div 
            Button("Fetch New Data", get=get_data, hx_target="#data-store")),
        # Store for the JSON chart data
        Div(id="data-store", get=get_data, hx_trigger="load", hidden=True),
        # Plot container
        Div(id="plot"),
        # Include the JavaScript for the plot
        Script(plot_js)
        )

@rt
def get_data():
    # Generate sample data
    data = [{"value": float(x)} for x in np.random.randn(100)]
    # Return as proper JSON response
    return JSONResponse(data)

serve()