Repository navigation
feat(python): six P1 tutorials — radar, network, t-SNE, paired, calendar, competing risk (en+zh) - #426
Merged
Conversation
This was referenced Nov 2, 2026
Main's quarto-publish has been failing since the #417 renv refresh: regplot's model.frame re-evaluation on Clinics/Nomogram.qmd errored with "factor stage has new levels Stage IVA" under newer survival releases. Root cause: the cohort's time column used only days_to_death, so every censored patient (Alive, time = NA) was silently dropped by coxph/psm. The single Stage IVA patient is censored, so the level disappeared from the fitted model's xlevels; when regplot re-evaluates model.frame against the full LIHC frame, the stricter survival check rejects the unseen level. Fix the data preparation instead of the symptom: analysis time is days_to_death for dead patients and days_to_last_follow_up for censored patients, then drop rows without a usable positive time. This restores all 259 censored patients to the Cox/AFT fits (the models were previously fit on the 172 dead patients only), keeps every stage level in the model, and makes regplot render again. Verified end-to-end locally: all 8 chunks of the patched tutorial execute under R 4.5.2 / survival 3.8.6 / regplot master.
ShixiangWang
force-pushed
the
codex/python-p1-tutorials
branch
from
November 2, 2026 07:09
3e0a252 to
4557723
Compare
Contributor
✅ QMD Format Check✅ All 7 checked QMD file(s) pass format validation!
|
regplot's added.obs() calls model.frame(fit, data=app). Newer survival (>=3.8.x in renv.lock) evaluates the coxph call in environment(fit$terms) — set by rms::datadist — where the appended data frame does not exist, raising "object 'app' not found". Storing the model frame via model=TRUE lets model.frame.coxph short-circuit on fit$model.
survival 3.8's model.frame.coxph evaluates the rebuilt model.frame call in environment(fit$terms) whose parent is the global env, so the data symbol it receives must exist there verbatim. regplot's added.obs() only creates app inside its own scope, hence 'object app not found'. Pre-binding app <- rbind(observation, LIHC) in the chunk works around it. Verified locally with survival 3.8-12 + regplot@3ee4817.
… tutorials (en+zh) Implements the six P1 topics from issue #424: - RadarPlot: matplotlib polar single/multi-series + plotly Scatterpolar; per-axis normalization pitfall panel - NetworkPlot: networkx spring/kamada layouts, degree and module encoding, weighted edges, hub-subnetwork application - TsnePlot: PCA vs t-SNE, perplexity sweep, PCA pre-reduction, seed/pitfalls - PairedPlot: slope/arrow/dumbbell variants with paired t-test annotation - CalendarHeatmap: GitHub-style week grid and month x day pcolormesh, week-offset algorithm - CompetingRiskPlot: hand-rolled Aalen-Johansen CIF (verified against the sum_k CIF_k = 1 - KM identity), 1-KM overestimation panel, Gray-test notes Supporting fixes so CI stays green: - requirements.txt: add networkx (imported by NetworkPlot) - manage-dependencies.py: extend PYTHON_STDLIB (calendar, base64, ...) so the publish workflow's --update no longer pip-installs stdlib names - sync-gallery.py: route plotly Scatterpolar chunks to MANUAL (no static PNG without kaleido), with test coverage; gallery CSVs synced (15 new rows each language, Ids 1051-1065)
The publish workflow renders with pandas 3.1, where the chained Index arithmetic in the data-prep chunk produced an Index without .clip and failed the build. Rewrite the chunk on numpy (day_of_year/day_of_week arrays, np.clip, explicit first-Monday offset) — byte-identical values to the figure-generating script on pandas 2.3, and it also fixes a real alignment bug: Jan 1-2 previously floored to week -1 and wrapped via negative indexing into the last grid column (overwriting Dec 31's cell and shifting the Jan label). Month labels now reuse the same offset. RadarPlot: clip(lower=, upper=) keyword form for pandas 3.
ShixiangWang
force-pushed
the
codex/python-p1-tutorials
branch
from
November 2, 2026 09:09
4557723 to
aae8b1e
Compare
Contributor
✅ QMD Format Check✅ All 7 checked QMD file(s) pass format validation!
|
Contributor
📊 Quarto Render PreviewThe new or modified Quarto files have been rendered and are available as artifacts. 🔗 View and Download Rendered Files Click the link above, scroll to the "Artifacts" section at the bottom of the page, and download Modified files: |
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.
Summary
Implements the six P1 topics from #424 (Python tutorial backlog), each as a bilingual (
.qmd+.zh.qmd) tutorial with demo/application images, sidebar entries, and gallery CSV rows:Python/RadarPlotScatterpolarinteractive variant; per-axis normalization pitfall panelPython/NetworkPlotnetworkxspring (seeded) / Kamada-Kawai layouts, degree/module encoding, weighted edges, hub-subnetwork applicationPython/TsnePlotPython/PairedPlotscipy.stats.ttest_relannotationPython/CalendarHeatmappcolormesh, week-offset algorithm, maskingPython/CompetingRiskPlotSupporting fixes (required to keep CI green)
requirements.txt: addnetworkx(new import).manage-dependencies.py: extendPYTHON_STDLIB(calendar,base64, …) — the publish workflow runs--updateand would otherwisepip install calendar(a junk PyPI name) now that a tutorial imports it.sync-gallery.py: route plotlyScatterpolarchunks to MANUAL (no static PNG without kaleido), matching existingSunbursthandling; +1 test.files/gallery_data*.csv: +15 rows per language (Ids 1051–1065), per the Python 可视化 P1/P2 教程待实施清单(#422 调研遗留,9 主题) #424 note that the next free Id is 1051.Verification
sync-sidebar.py --check: in sync (352 pages).sync-gallery.py --check: in sync (90 manual cases, +1 new MANUAL = the interactive radar chunk, same pattern as the existing sunburst).pytest .github/scripts/: 31 passed (incl. new Scatterpolar test).mcptests: 104 passed (untouched).Part of #424 (P1 batch). P2 remains: waffle, wordcloud, 3D scatter.