docs(01-hello): rebuild example as Shiny's Old Faithful 01_hello - #207
Merged
Conversation
Replaces the name/counter latency demo with Shiny's canonical 01_hello app —
a bins slider over the Old Faithful waiting times — rebuilt ui.tsx-first.
The server never renders a picture. One reactive_output returns histogram
{breaks, counts} as plain JSON plus a caption; www/app.js reads it with
useShinyOutputValue and draws the bars as SVG rects. That contrast with
traditional Shiny's renderPlot({ hist(...) }) is the point of the example.
- faithful.py: waiting times + a stdlib-only binner shared by app.py and
app-core.py, so the Python side stays dependency-free (no numpy/matplotlib)
- faithful.csv: base R's `faithful` exported for the Python servers; app.R
uses the built-in dataset and hist(..., plot = FALSE)
- app.R wraps the histogram vectors in I() so bins = 1 serializes as a JSON
array rather than a scalar, and returns NULL until the client's first bins
message arrives (Python raises a silent exception instead)
- The chart stays mounted while the server recomputes and only dims via
useShinyOutputStatus, per the repo's flicker guidance
Verified in a browser against app.py, app-core.py, and app.R: R and Python
produce identical counts at bins 1/2/7/30/50, and the console is clean.
schloerke
force-pushed
the
schloerke/example1-oldfaithful-hello
branch
from
August 19, 2026 20:44
7b18602 to
e5bc553
Compare
Carries #206's change forward onto the rewritten example. www/index.html is now two lines (stylesheet + deferred script) and app.js creates its own mount container via document.body.appendChild(document.createElement("div")) — safe because the script is deferred, so <body> is parsed when it runs. This prepares 01-hello for the upcoming page_react() page mode, where the server emits no body HTML at all and the client owns its mount point.
This was referenced Aug 19, 2026
schloerke
force-pushed
the
schloerke/example1-oldfaithful-hello
branch
from
August 19, 2026 20:57
a6fdcdf to
ff6f005
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Rebuilds
examples/01-helloas Shiny's canonical01_helloOld Faithful app,ui.tsx-first. It replaces the previous name-input/click-counter latency demo.Why this app
01_hellois the app every Shiny user has seen, which makes it the clearest possible place to show what changes under theui.tsxpattern. Traditional Shiny renders the histogram on the server —renderPlot({ hist(...) })ships a PNG and the browser is a passive<img>. Here the server never produces a picture:reactive_outputreturning{breaks, counts}as plain JSON, plus a caption. That's the whole server: no plotting library, no image encoding, noplotOutputplaceholder.www/app.jsreads that JSON withuseShinyOutputValueand draws the bars as SVG<rect>s. Because the chart is real DOM the client owns, it can be styled or made interactive without another round trip.The slider goes the other way:
useShinyInput("bins", 30)pushes to Shiny, which recomputes the counts. Still no JSX, no bundler, nopackage.json.Notable bits
faithful.py— waiting times plus a stdlib-only equal-width binner, shared byapp.pyandapp-core.py. Keeps the Python side dependency-free (no numpy/matplotlib), which matters for the example that exists to be minimal.faithful.csv— base R'sfaithfulexported so Python needs no data dependency.app.Ruses the built-in dataset andhist(..., plot = FALSE).I()inapp.R— without it,bins = 1serializescountsas a scalar instead of a length-1 JSON array and the client crashes. Found by clicking; worth knowing about generally when areactive_outputreturns vectors.NULLbefore the firstbinsmessage — Python raises a silent exception instead.req()also works, but its silent error still reaches the client and shows up as a console error, which is a poor look for the flagship example.useShinyOutputStatus— the chart stays mounted while the server recomputes and only dims, per the flicker guidance inCLAUDE.md. Dragging the slider never tears the SVG down.Relationship to #206
Second commit carries #206's change forward onto the rewritten example:
www/index.htmlis two lines andapp.jsappends its own mount div to<body>, preparing 01-hello for the upcomingpage_react()mode where the server emits no body HTML. #206 has been closed as superseded. Note it was stacked on #198 (schloerke/npm-distribution) while this branches offmain— if #198 needs the body-mount change on its own branch, it will have to be reapplied there.Stacked follow-up: #210
Rewriting this example surfaced a pre-existing bug — Core-mode apps never served their own
www/, soapp-core.pyloaded/and then 404'd onapp.jsandmain.css. That fix lives in #210, stacked on this branch, since it's a separate idea: it touches10-bookmarkingand the package docs, not this example's content.That means
app-core.pyis still broken on this branch alone — it works once #210 lands.app.py(Express) andapp.Rare unaffected and work here.Verification
Booted all three server entries and drove them in a browser:
sum == 272throughout), and thebins = 1edge case renders.document.getElementById("root")isnull, with the mount div a direct<body>child.favicon.ico.(The
app-core.pyround trip was verified with #210 applied on top.)make py-check-testspasses (74);make py-check-typesclean;air format,ruff, andprettierapplied.Note when trying it locally:
www/app.jsis served statically with no cache busting, so a hard refresh is needed after pulling.