21職種の母集団を対数軸で比べるページを作り、パンくずの生スラッグ176件を直す

開発mdx-playground

21職種の母集団を対数軸で比べるページを作り、パンくずの生スラッグ176件を直す

「お笑い芸人 → 約7,000人〜20,000人以上」。 手元にあったのは、才能で食う職業の人数をざっと並べた推計のリストだった。 幅は粗いし、出どころも書いていない。 それでも、桁が3つも4つも違う職業が同じ縦に並んでいるのを見て、対数軸に載せれば形が出ると思った。

Vue ページで作らせることにした。 ただ、推計のまま絵にしても飾りにしかならない。 先に数字の裏取りをさせた。

元ネタの20項目はどこまで合っていたか

元ネタ20項目のうち、17項目は一致か範囲内に収まった。 ズレたのは3件。 税理士は7.9万人ではなく8.2万人、海事代理士は1,400人ではなく約3,500人だった。

3件目は、数字ではなく定義がずれていた。 ラノベ作家の「9,000人台」は現役の人数ではなく、21年間の延べ累計だった。 ストックの列にフローの数字が1つ紛れ込んでいて、デビュー枠を21年ぶん足した数を、いま食えている人数として読んでいた。

データと純関数は app/utils/talentPopulation.ts に分けさせた。 本文中の件数や倍率もすべてデータから算出させたので、あとで職種を足しても文章の数字がずれない。

ストックとフローを同じ軸に置けるか

母集団と年間参入枠の2つを、同じ対数ドットプロットに載せる設計にしていた。 ここでテストが落ちた。 プロ棋士の年4人が、母集団側の軸の下限10を下回って潰れる。

ストック(何人いるか)とフロー(毎年何人入れるか)は同じ軸に置けない。 並べ終えてから見れば当然だが、テストが落ちるまで気づかなかった。 フロー用の軸を独立させて、29件のテストが通った。

平均年収は出すべきか

ページの形が見えたところで、職業ごとの平均年収も推定できないかと聞いた。 ただ、聞きながら自分で疑っていた。 才能の世界は上から下までの差が大きいので、平均を取る意味があまりない。

方針は中央値と分布の形に決めた。 チャートは中央値と平均を線でつなぐダンベルにさせた。 2つの点が離れているほど、上澄みが平均を引き上げているという読み方になる。

ここでもテストが1件捕まえている。 行政書士は公的調査があるのに、中央値も平均も公表されていない。 出ているのは分布だけで、年収500万円未満が76%という形である。 「公的統計なら中央値か平均がある」と決めてかかっていたので、条件を実態に合わせさせた。 中央値が取れない職業は、分布の記述だけを表で示す形にした。

このタイミングでプロサッカー選手(1,915人)も才能側に足した。 元ネタのリストには無かったので、追加であることが分かる印を付けさせている。 20職種が21職種になった。

目盛りが途中から万表記に変わっていた

出てきたチャートの目盛りが 10 / 100 / 1,000 / 1万 / 10万 / 100万 と並んでいた。 1,000の次で単位が切り替わるので、桁が何倍ずつ進んでいるのか目で追えない。 ドットに付いた数値ラベル(348,000 など)とも表記が食い違っていた。

3桁区切りに統一させた。 対数軸は「目盛りの間隔が等しい=倍率が等しい」ことが読めて初めて機能するので、表記を混ぜると軸そのものが働かなくなる。

職種数を「20職種」と直書きしている箇所も2度出てきた。 最初は本文側で見つけて算出に切り替えさせたが、あとから hosts の側にも残っているのが分かった。

目次の置き場所とクアドラントの並び順

目次がページ幅いっぱいに広がって本文と重なっていた。 原因は、TableOfContentsposition: sticky のサイドバー列に入る前提のコンポーネントだったことである。 それをページ先頭に直置きしていた。 本文とサイドバーの2カラムに組み直させ、1024px以下では目次が消えるのに合わせてカラムも畳ませた。

受注型、提案型、資本型を整理したクアドラントでは、S(自営業)が右列に出ていた。 右列は「仕組みと資本が金を生む」側なので、意味が逆になる。 配列を ESBI の呼び名順に並べると、2×2グリッドの行優先の並びと合わずに S が右へ落ちる。 画面配置に合わせた並び順に直させて、テストで固定した。

本文だけが早く折り返っていた

パラグラフの途中に不要な改行が入っている、と指摘した。 カードやチャートは横いっぱいに伸びているのに、本文だけが手前で折り返る。

<br> は0個だった。 犯人は max-widthch 指定である。 ch は半角文字1つぶんの幅なので、74ch は日本語だと約37文字にしかならない。 940pxのコンテナの中で本文だけが575〜637pxに絞られ、300px以上を余らせて折り返していた。

ch を撤去して、本文も940px幅で折り返るようになった。 英文向けの読みやすさの定石をそのまま日本語に持ち込むと効きすぎる。

パンくずを記事と同じ形にする

/blog を開いて、このページのパンくずが他の記事と揃っていないことに気づいた。 記事コンテンツとしてブログ側に置いてほしい、とも伝えた。

/blog/ 配下に置けば Home / 一覧 / ラベル になり、マークダウン記事と同じ形に揃う。 既存の作法がそこにあったので合わせさせた。 あわせて記事一覧に登録させ、/blog のカレンダーの8月31日に載ることを確認した。

パンくずの生スラッグはどこまで残っていたか

ここで、パンくずの現在地が Home / public-key-crypto のように生のスラッグで出るページが他にもあったことを思い出した。 残っているなら全部直すよう頼んだ。

洗い出しは何度かやり直している。 最初の走査は89件を返したが、肝心の public-key-crypto が入っていない。 CourseShell のようなラッパー経由でパンくずを出すページを拾えていなかった。 静的解析でコンポーネントを推移的に辿る方法も試したが、確実さで劣る。 最終的に、各ページ自身のタイトルからラベル候補を機械抽出する方針に切り替えた。

登録先は2つに分けさせた。 トップレベル(/foo)は segmentLabelMap に51件を入れた。 入れ子(/a/b)はスラッグが一般語と衝突しうるので、フルパスの pathLabelMap に125件を入れた。 合計176件である。

機械抽出なので、ページ内の別の見出しを拾ったものが混ざっていた。 ai-credit-monitor が「① 調達コスト」、sp500-backtest が「The Reckoning」。 これらは補正ルールを当てて手当てさせ、親を見れば分かる語(/zaimu-dd/guide/* の「財務DD」など)は子のラベルから落とさせた。

既存テストが1件落ちた。 落ちたのは、生スラッグを期待値に固定していた箇所である。 そのテストの目的は「非公開」クラムの挿入確認なので、期待ラベルのほうを更新した。 そのうえで、app/pages を走査して「現在地ラベル=最終セグメント」のルートが1つも無いことを検査するテストを足させた。 新しいページで登録を忘れたら落ちる。

テストは43件が通った。 リポジトリ全体でも244スイート、20,315件が通っている。

コミットと後片付け

コミットの前に範囲を確認させたら、別セッションの作業がインデックスにステージ済みで残っていた。 14ファイル、9,035行のうち約9,000行が相手の生成データである。 巻き込まないよう、自分のファイルだけをパス指定でコミットさせた。 待っているあいだ、自分の3ファイルは一度インデックスから外させている。 相手がパス指定なしで git commit した瞬間に、こちらの3ファイルまで巻き込まれるからである。 インデックスから外してもファイルの中身は消えない。

学習ゲートは受領証をインデックス全体のSHA1で照合する仕組みなので、他人の変更が混ざった状態では通せない。 今回はスキップを指示し、理由をログに残して通した。

464972bb fix(chart): 長期系列のX軸で月ラベルが消える問題を直す
d94629fd feat(blog): 才能の母集団と勉強の母集団 — 21職種を対数軸で比較する記事ページ
2d10c482 fix(breadcrumb): 生スラッグのまま表示されていた176ルートに日本語ラベルを付ける

1本目は別ページで見つけた不具合で、長期系列のX軸が年だけになっていたものである。 36ヶ月を超えると各年1月のラベルだけに間引く実装だったため、55ヶ月ある系列では月が消えていた。

ノードのプロセスが38個も立っていたので、プッシュを済ませてから /procs で掃除させた。 dev サーバーと、二重三重に立っていたMCPサーバー4本を止めた。

学びメモ

  • ストックとフローを同じ対数軸に載せると、小さいほうの系列が下限で潰れる。テストが先に見つけた
  • 「公的統計があるなら中央値も平均もある」は成り立たない。分布だけ公表という形がある
  • 対数軸の目盛りで単位表記を混ぜると、倍率が読めなくなって対数にした意味が消える
  • ch は半角基準。日本語に max-width: 74ch を当てると想定の半分ほどの文字数で折り返る
  • 共有コンポーネントは、置かれる前提(sticky のサイドバー列など)ごと確認してから使う
  • 並列セッションのステージが混ざるとコミット範囲も学習ゲートも巻き込まれる。パス指定で切り出す
#Nuxt #データ可視化#対数スケール#パンくずリスト #Vitest