Two independent reader-facing defects on the published french_rev page, both found while validating QuantEcon/data-lectures#51 by rendering the live page and running the published notebook. Neither was introduced by the data migration; the first was made more visible by it.
1. Data Sources documents three of the five datasets the lecture reads
lectures/french_rev.md:59 says "This lecture uses data from three spreadsheets assembled by {cite}sargent_velde1995" and lists fig_3.xlsx, dette.xlsx and assignat.xlsx at :60-62.
The lecture actually reads five files. caron.npy and nom_balances.npy are fetched from the same base_url at :711-714 and are named nowhere outside code cells — a case-insensitive grep of the whole file for caron|nom_balances|\.npy returns 6 hits, all of them code.
Nine of the eighteen published figures derive entirely from those two files (fr_fig104 and its five variants, plus the three exercise-solution figures). So half the lecture's figures rest on sources a reader cannot click through to, in a section whose whole purpose is provenance.
Being fair about it: this is pre-existing documentation debt, not a concealed inconsistency. Both manifests state the gap explicitly in their header comments, and CATALOG.md publicly lists this lecture as a consumer of both .npy files. But 6986e35a (#826) rewrote exactly those three bullets in place to repoint them, which was the natural moment to add the other two — and the validation checklist for that work described them as "the three Data Sources links", encoding the gap rather than catching it.
lecture-wasm/lectures/french_rev.md:57-62 is identical and needs the same fix.
2. A stray 30-row DataFrame renders above fr_fig3
The published page renders an uncaptioned 30-row DataFrame table as the output of the data1.replace(0, np.nan, inplace=True) cell, immediately above the fr_fig3 figure. Confirmed reader-visible in a headless browser: table.dataframe, visible, 1117 px tall, 30 tbody rows, not collapsed.
The cause is a pandas 3 behaviour change, not anything the migration did. In pandas 3.0.3 — the version the live build used, per the publish run's conda log — DataFrame.replace(..., inplace=True) executes return self rather than returning None, so Jupyter renders the cell's last expression. The mutation still applies correctly (NaNs applied = 2), so no figure and no number is wrong. Purely cosmetic.
It is a genuine regression rather than long-standing: the 2026-03-09 archived copy of this page has class="dataframe" ×0, and the anaconda 2026.07 bump (#797, 2026-07-20) predates the migration.
The blast radius is narrower than "every inplace=True idiom", which is worth stating so this doesn't turn into a large sweep. In pandas 3.0.3, only replace, fillna and interpolate return self; dropna, set_index, reset_index, sort_values and rename still correctly return None. So only cells whose last statement is an inplace replace/fillna/interpolate are affected.
Simplest fix here is data1 = data1.replace(0, np.nan), which is also the form pandas is steering toward.
Two independent reader-facing defects on the published
french_revpage, both found while validating QuantEcon/data-lectures#51 by rendering the live page and running the published notebook. Neither was introduced by the data migration; the first was made more visible by it.1. Data Sources documents three of the five datasets the lecture reads
lectures/french_rev.md:59says "This lecture uses data from three spreadsheets assembled by {cite}sargent_velde1995" and listsfig_3.xlsx,dette.xlsxandassignat.xlsxat:60-62.The lecture actually reads five files.
caron.npyandnom_balances.npyare fetched from the samebase_urlat:711-714and are named nowhere outside code cells — a case-insensitive grep of the whole file forcaron|nom_balances|\.npyreturns 6 hits, all of them code.Nine of the eighteen published figures derive entirely from those two files (
fr_fig104and its five variants, plus the three exercise-solution figures). So half the lecture's figures rest on sources a reader cannot click through to, in a section whose whole purpose is provenance.Being fair about it: this is pre-existing documentation debt, not a concealed inconsistency. Both manifests state the gap explicitly in their header comments, and
CATALOG.mdpublicly lists this lecture as a consumer of both.npyfiles. But6986e35a(#826) rewrote exactly those three bullets in place to repoint them, which was the natural moment to add the other two — and the validation checklist for that work described them as "the three Data Sources links", encoding the gap rather than catching it.lecture-wasm/lectures/french_rev.md:57-62is identical and needs the same fix.2. A stray 30-row DataFrame renders above
fr_fig3The published page renders an uncaptioned 30-row DataFrame table as the output of the
data1.replace(0, np.nan, inplace=True)cell, immediately above thefr_fig3figure. Confirmed reader-visible in a headless browser:table.dataframe, visible, 1117 px tall, 30tbodyrows, not collapsed.The cause is a pandas 3 behaviour change, not anything the migration did. In pandas 3.0.3 — the version the live build used, per the publish run's conda log —
DataFrame.replace(..., inplace=True)executesreturn selfrather than returningNone, so Jupyter renders the cell's last expression. The mutation still applies correctly (NaNs applied = 2), so no figure and no number is wrong. Purely cosmetic.It is a genuine regression rather than long-standing: the 2026-03-09 archived copy of this page has
class="dataframe"×0, and the anaconda 2026.07 bump (#797, 2026-07-20) predates the migration.The blast radius is narrower than "every
inplace=Trueidiom", which is worth stating so this doesn't turn into a large sweep. In pandas 3.0.3, onlyreplace,fillnaandinterpolatereturnself;dropna,set_index,reset_index,sort_valuesandrenamestill correctly returnNone. So only cells whose last statement is an inplacereplace/fillna/interpolateare affected.Simplest fix here is
data1 = data1.replace(0, np.nan), which is also the form pandas is steering toward.