Skip to content

Phase 3: 出力品質(保存 DPI・図サイズの単位・欧文フォント・プリセット・クリップボード) - #3

Merged
mioupa merged 16 commits into
mainfrom
phase3-output
Oct 8, 2026
Merged

mioupa merged 16 commits into
mainfrom
phase3-output

Conversation

@mioupa

@mioupa mioupa commented Oct 8, 2026

Copy link
Copy Markdown
Owner

要件定義書9章の Phase 3(出力品質。C1–C6)と、6章の左パネルの整理を実装しました。Phase 2 から残っていた漏れ(保存設定を変えても、表示中のコードとダウンロードする .py が古いまま)も直しています。

変更内容

保存 DPI(C1)

  • 72 / 150 / 300 / 600 / 任意(50〜1200)から選べる。既定は 300(U1)。プレビューは今までどおり dpi 100。
  • 生成コードの fig.savefig と GUI の「保存」は、同じ formats.savefig_kwargs を使う。dpi は PNG / JPG のときだけ書く。
  • 保存・コピーの画像には画素数の上限(1億画素、1辺 65536 未満)を設けた。超えると「保存 DPI」の日本語エラー。上限ちょうどでも Pyodide で保存できることを確認した(wasm のメモリは約 600 MB)。

図のサイズの単位と、文字の扱い(C2)

  • 図のサイズを inch / cm / mm で指定できる。既定は inch の 8×6(U2)。設定には「選んだ単位の値」を持つ。単位を切り替えたら入力欄の数値を換算する(図の大きさは変えない)。
  • 生成コードは figsize=(8.5 / CM_PER_INCH, 6.4 / CM_PER_INCH) のように割り算でインチに直す。1 / 2.54 を掛けると 20.32 cm が 7.999… inch になり、300 dpi の画像が 2399 px になるため。
  • PDF は pdf.fonttype=42 で文字を埋め込む(Illustrator などで文字を編集できる)。SVG は「パスに変換」(既定)と「テキストのまま」を選べる。rcParams の値は formats.savefig_rc の1か所で決め、生成コードにも同じ値を書く。
  • 日本語フォントを、Noto Sans CJK JP(OTF、CFF 形式、約16 MB)から、同じデザインの TrueType 版 Noto Sans JP(約5.7 MB)に替えた。 matplotlib 3.10 は CFF 形式のフォントを Type 42 で正しく埋め込めない(TrueType 用の FontFile2 に CFF を入れるため、pdffonts が不一致を警告し、mutool / Ghostscript では文字が崩れる)。文字幅は完全に一致し、見た目は変わらない。ハングルと中国語専用の漢字は含まれない(JIS 第1〜第4水準は含む)。

欧文フォント(C3)

  • Arimo(Arial 互換)と Tinos(Times 互換)を選べる(U3)。選んだときだけ jsDelivr から取得する(約 0.3〜0.5 MB。Cache Storage に保存)。起動時には取得しないので、起動時間は変わらない。
  • 欧文は選んだフォント、日本語は Noto Sans JP で描く(matplotlib の文字単位のフォールバック)。Tinos のときは数式を STIX にする。
  • 生成コードは、手元にフォントが入っているかを確かめてから指定する。無い環境でも「findfont: … not found」の警告を出さずに、日本語フォントで描く。
  • 取得に失敗したら警告を1回出し、そのフォントを選んでいる間は以後の表示にも添える(再試行はしない)。

プリセットとカラーパレット(C4)

  • 「標準」「論文1段組(8.5 cm、8 pt)」「論文2段組(17 cm、8 pt)」「スライド16:9(24 × 13.5 cm、18 pt)」。「適用」ボタンで、図のサイズ・フォントサイズ・線幅・点サイズをまとめて書き込む(設定にプリセット名は残さない)。
  • 点サイズは、点を表示している系列だけを書き換える(line の「自動」の系列に点が出ないように)。
  • パレット(UD カラー / tab10 / グレースケール)を切り替えると、全系列を系列の順に塗り直す。色の候補と、系列を足したときの既定色も、選んだパレットから取る。

クリップボードへのコピー(C5)

  • 保存 DPI の PNG(背景透過は保存設定に従う)を、ClipboardItem に Promise<Blob> として渡してコピーする(Safari の制約に合わせ、クリックの中で navigator.clipboard.write を呼ぶ)。Chrome / Edge 98 以降、Safari 13.1 以降、Firefox 127 以降。非対応の環境では「保存する」を案内する。

数式の案内(C6)

  • 「軸・目盛」区分に、$ で囲んだ数式・上付き・下付きの書き方と、matplotlib の説明ページ(版を固定)へのリンクを置いた。
  • 数式の書き間違いは「数式を解釈できませんでした」という日本語のエラーにした(今までは「レイアウトの自動調整に失敗しました」や内部エラーになっていた)。

左パネルの整理(6章)

  • 「データ読み込み」「系列」「軸・目盛」「体裁」「保存」の5区分を <details> で折りたためるようにした。状態は localStorage に保持する。既存の要素 id は変えていない。
  • 「描画設定: 先頭からスキップする行数」の欄名を「描画から除外する先頭行数」に改めた。

設定スキーマ v2

  • plot.figure.unit、plot.latinFont、plot.palette、save.dpi、save.svgText を追加した。v1 からの移行(settings.migrate_settings)では、v1 の保存が常に 120 dpi だったため save.dpi を 120 にする。JS と Python の既定値の一致はテストで確認している。

Phase 2 からの漏れの修正

  • GUI 同期中に保存設定(形式・DPI・SVG の文字など)を変えても、表示中のコードは次の描画まで古いままだった。新しい API script で、図は描き直さずにコードだけを作り直すようにした。

計測値(docs/PERFORMANCE.md「Phase 3 後」)

項目(ms、中央値) Phase 2 後 Phase 3 後 比較
コールド起動 3,607 3,564 同等
ウォーム起動 3,452 3,441 同等
初回ファイル読込 → 最初のプロット 178 177 同等
設定変更 → プロット更新(デバウンス込み) 466 471 同等
保存(PNG、120 dpi) 246 246 同等
保存(PNG、300 dpi。新しい既定) – 405 –
初回 .xlsx 読込 → 最初のプロット 329 329 同等
編集モードでの実行 438 579 悪い(既定の DPI のため。120 dpi では 438 前後)
欧文フォントを選ぶ → プロット更新(初回 / キャッシュあり) – 468 / 467 –
クリップボードへのコピー(300 dpi) – 422 –

悪くなった2項目(300 dpi の保存、編集モードの実行)は、どちらも既定の DPI が 120 から 300 になり、画素数が 6.25 倍になったため。120 dpi では Phase 2 後と同じ値。

オーナーが決めたこと(2026-10-08。AGENTS.md §13.2、要件定義書 §2.3 に記録)

  • U1: 保存 DPI の既定値は 300。U2: 図サイズの既定の単位は inch(8×6)。cm と mm も選べる。U3: 欧文フォントは Arimo と Tinos。
  • U3 のライセンスの記載を訂正した。どちらも SIL OFL 1.1(要件作成時の「Apache 2.0」は誤り)。README にフォントとライセンスの節を設けた。
  • 日本語フォントを TrueType 版 Noto Sans JP に替えた(上記)。
  • 単位の切替は数値を換算する。パレットの切替は全系列を塗り直す。コピーは保存 DPI の PNG。左パネルの区分は5つ(「注釈・解析」は Phase 5 で作る)。

テスト

  • 単体テスト: 482 passed(uv run pytest)
  • E2E: 68 passed(uv run pytest tests/e2e)
  • 生成コードの一致確認に、cm 指定とプリセットのケース、欧文フォント(Arimo)・cm・PDF のケースを追加した(手元の CPython に Arimo が無い状態で、警告なしに動くことも確認)
  • Chromium 上で、実際の Noto Sans JP と Arimo / Tinos を埋め込んだ PDF が TrueType(Type 42)になり、Type 3 が無いことを E2E で確認
  • Illustrator で PDF を開き、文字を編集できるか(PDF の検証ツール pdffonts / mutool / Ghostscript では正常)
  • Safari と Firefox の実機でのクリップボードへのコピー(自動テストは Chromium のみ)

注意点

  • 実フォントを jsDelivr から取得する E2E があり、インターネット接続が必要。
  • 1億画素の保存では、Pyodide の wasm メモリが約 600 MB まで増えたまま戻らない。メモリの少ない端末では足りない可能性がある。

🤖 Generated with Claude Code

mioupa and others added 16 commits October 8, 2026 03:07
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…section

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Multiplying by 1 / 2.54 turned 20.32 cm into 7.999... inches, so saved
images lost a pixel (2399 px instead of 2400 at 300 dpi).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
script_json generates the script from the loaded data without running it, so the
code tab can follow save settings. raster_pixels used ceil, but Agg truncates, so
the too-large message now shows the real pixel size.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…sync with save settings

The Latin font (Arimo / Tinos) is fetched only when selected. The save section
gains DPI, SVG text mode and a PDF note. Save-setting changes now regenerate the
displayed code without re-rendering the image.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mioupa
mioupa merged commit e239143 into main Oct 8, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant