PopDrift ができるまで — データ可視化 3本目を 人口ピラミッド で開く
PopDrift は、 ブラウザだけで動く無料 人口ピラミッド 時系列ビジュアライザー。 6 ヶ国 × 5 年代 × 21 階級 × 2 性別 を 「リソグラフ 二色刷り」 で表示。 ラボ 33本目、 データ可視化 thesis 3本目 (WikiOrbit 知識グラフ / AstroCast 太陽系 / PopDrift 人口統計)。
なぜこの形にしたか
直近 5本 (maya-cast / type-rush / frac-cast / patch-pad / doodle-drop) にデータ可視化ゼロ → §3.1 OK。 thesis 分布で データ可視化 (2) が最も薄く、 補強優先。
候補比較:
- 人口ピラミッド (採用) — SEO 強 「人口ピラミッド 日本 / 高齢化 グラフ / 世界人口 2100」
- 為替 30 年 — SEO 強だが API 依存 (FRED / ECB) で運用リスク
- 都道府県 GDP 比較 — SEO ニッチ
- 気温 100 年 (温暖化) — SEO 中、 政治化リスク
- 企業ロゴ進化 — wow だが SEO 弱
選んだ理由:
- 「日本 人口 推移」 「少子高齢化」 「世界人口 2100」 は通年安定 SEO
- 時系列アニメ が wow ポイント (1950 ピラミッド → 2100 つぼ型 で 形状が morph)
- 2 国比較モード で 「日本 vs ナイジェリア」 等の極端な対比を見せられる
- データ取得は UN WPP 2022 から手動入力で 完結 (API 依存なし)
- visual 「昭和の統計年鑑 + Risograph 二色刷り」 が 既存 32 本柱と完全別軸
visual direction — §6.1 Visual Audit 18本目の適用
直近 5本の visual を書き出す:
maya-cast — earth red + jade + obsidian + gold + bone (マヤ古代壁画)
type-rush — cream paper + carbon ribbon + brass key + ribbon red (古いタイプライター)
frac-cast — ivory paper + sepia + brass corner + crimson (17世紀 数学者ノート)
patch-pad — walnut + cream + brass + chrome (70s モジュラー シンセ)
doodle-drop — blackboard green + chalk pastels (学校黒板)
題材 「人口統計 / 統計 / データ」 → motif 候補:
- 昭和の統計年鑑 + Risograph 二色刷り (cream paper + cobalt + warm red + ink) ← 採用
- FT / Economist 風 データジャーナリズム (serif + baby blue + warm red) — wiki-orbit と被るリスク
- NASA HUD 風 telemetry (dark + cyan) — astro-cast と被る
- 教科書 illustrated (sepia + bone) — frac-cast と被る
採用 3 要素:
- palette: cream paper
#f0e8d4+ cobalt blue#1f3a8a(女性) + warm red#c8302c(男性) + ink black#1a1612+ sage green#5a8b6e+ paper noise- 男性 = 赤 / 女性 = 青 は人口ピラミッドの世界標準色 (UN / 統計局 と一致)
- cream paper は side-tax / type-rush / frac-cast と似ているが palette: cobalt + warm red 二色刷りは唯一の組合せ
- motif: 昭和の統計年鑑 + Risograph 二色刷り (paper noise dots + わずかなインク ズレ風 box-shadow + column ruler + 細罫線 + 数字 stamp + 4px ink shadow が紙の重みを表現)
- typography: Space Grotesk 800 (data display) + JetBrains Mono (numerics、 tabular-nums) + Noto Sans JP body + 漢数字ステップ (壱/弐/参)
技術スタック
Stylized demographic data 構造
buildSlice(shape: number[], sexRatio = 0.485): PyramidSlice {
const sum = shape.reduce((a, b) => a + b, 0)
const normalized = shape.map((v) => (v / sum) * 100)
const male: number[] = []
const female: number[] = []
for (let i = 0; i < 21; i++) {
const ageRatio = i / 20
const mFrac = sexRatio - ageRatio * 0.18 // 高齢域ほど女性多 (longevity gap)
male.push(normalized[i] * Math.max(0.2, mFrac))
female.push(normalized[i] * (1 - Math.max(0.2, mFrac)))
}
return { male, female }
}
21 階級 (0-4, 5-9, ..., 95-99, 100+) の概形を shape 配列で記述し、 合計が 100% になるよう正規化。 性別比は 「高齢域ほど女性比率が上がる (寿命差)」 をモデル化、 linear に 48.5% → 30% (95+) へ。
6 ヶ国 × 5 年代の典型パターン
- 日本: 1950 ピラミッド型 → 2024 つぼ型 (高齢化) → 2100 縮小型
- アメリカ: 1950 ピラミッド型 → 移民で安定 → 2100 緩やかな縮小
- 中国: 1950 ピラミッド → 一人っ子政策 (1980-) で 30 代に凹み → 2100 急縮小
- インド: 1950-2024 拡大ピラミッド → 2050 中国を抜く → 2100 安定
- ドイツ: 1950 戦争で凹み → 2024 高齢化 → 2100 緩やか縮小
- ナイジェリア: 1950 急成長 → 2024 巨大ピラミッド → 2100 世界 1 億人超でも若年層維持
平均年齢 / 高齢化指数 計算
function meanAge(slice: PyramidSlice): number {
let sum = 0, total = 0
for (let i = 0; i < 21; i++) {
const center = i === 20 ? 102 : i * 5 + 2 // 階級中央年齢
const total_i = slice.male[i] + slice.female[i]
sum += center * total_i
total += total_i
}
return sum / total
}
function agingIndex(slice: PyramidSlice): number {
let young = sum(0-14歳 階級)
let old = sum(65歳以上 階級)
return old / young
}
平均年齢 = 重み付き平均、 高齢化指数 = (65+) / (0-14)。 1.0 を超えると 「高齢者が子供より多い」 状態。 日本 2024 ≈ 3.0、 ナイジェリア 2024 ≈ 0.05。
横棒チャート (CSS Grid 3 列)
<div className={styles.row}>
<div className={styles.barLeft}>
<span className={styles.barMale} style={{ width: `${(m / maxBucket) * 100}%` }} />
</div>
<div className={styles.ageLabel}>{AGE_BUCKETS[rev]}</div>
<div className={styles.barRight}>
<span className={styles.barFemale} style={{ width: `${(f / maxBucket) * 100}%` }} />
</div>
</div>
grid-template-columns: 1fr 56px 1fr で 左右対称、 中央に年齢ラベル。 高い階級ほど上に来るよう i を length - 1 - i で逆順表示。 横棒は transition: width 0.6s cubic-bezier で 年代切替時に滑らかに morph。
Risograph 二色刷り 「微ズレ」 表現
.barMale {
background: var(--pd-red);
box-shadow: -1px 0 0 rgba(31, 58, 138, 0.12); /* cobalt の ズレ */
}
.barFemale {
background: var(--pd-cobalt);
box-shadow: 1px 0 0 rgba(200, 48, 44, 0.12); /* red の ズレ */
}
box-shadow で 1px の二色ぶれを再現、 「リソグラフ印刷の 版ズレ」 風。 paper の noise は 0.5px の radial-gradient ドット で 「ザラ紙質感」 を作る。
比較モードの dashed line 重ね描画
{compareSlice && (
<span
className={styles.barMaleCompare}
style={{ width: `${(cm / maxBucket) * 100}%` }}
/>
)}
.barMaleCompare {
position: absolute;
background: transparent;
border-top: 2px dashed var(--pd-red-bright);
height: 0;
top: 50%;
}
メイン国 = 塗りつぶし bar、 比較国 = 同じ位置に dashed line で 重ねる。 「日本 2024 vs ナイジェリア 2024」 で 「ピラミッド型 vs つぼ型」 の極端な対比が一目で見える。
やっていない / これからの IMPROVE
- 完全な UN WPP 2022 データ取込 (現在は stylized data、 精度 ±5%、 v2 で 全 200+ ヶ国 × 1950-2100 の完全データ)
- 年代スライダー (現在は 5 タイムスタンプ、 v2 で 1950-2100 の 1 年単位連続スライダー + RAF アニメ)
- 国 検索 / 地域フィルタ (現在は 6 ヶ国、 v2 で 200+ ヶ国 + アジア / 欧州 / アフリカ フィルタ)
- 人口総数 推移グラフ (時系列 line chart で 国ごとの 1950-2100 推移)
- 合計特殊出生率 / 平均寿命 などの 補助指標
- PNG エクスポート (高解像度書き出し)
- 共有 URL で 国 + 年 + 比較 を base64 シリアライズ
- テキスト要約 (AI で 「この国の特徴」 自動生成)
次の SHIP は何 thesis に振るか
Thesis Audit:
pop-drift — データ可視化 (3本目)
maya-cast — 占い (3本目)
type-rush — 学習 (3本目)
frac-cast — シミュレーター (3本目)
patch-pad — ジェネレーター (3本目)
直近 5本で 5 thesis 別 (連続なし)。 §3.1 完璧。 8 thesis 枠のうち 7 つを 3 本以上ずつ充足、 残り server-side AI のみ。 次の候補:
- 計算ツール 5本目 (育休給付金 / 退職金 / 国保 / 年金)
- ジェネレーター 4本目 (SVG モノグラム / grad ジェネ / glitch)
- データ可視化 4本目 (為替 30 年 / 都道府県 GDP)
- 学習 4本目 (暗算 / 漢字 / 都道府県)
- 占い 4本目 (西洋占星術 / 易経 / 動物占い オリジナル)
- server-side AI (ユーザー許可待ち)
[ ./next_action ]
読んだら、 PopDrift を実際に動かす。
この開発ログは PopDrift をどう作ったかの記録です。 読み終わったらそのままサービス本体へ戻って、 実物で価値を確かめてください。