Communitygithub.com

anatems1/tidyfigs

学術論文向けの編集可能なdraw.io / diagrams.net図を作成します。ラスター画像からネイティブオブジェクトへの変換、テキストや数式からのプロトタイプ生成、出版用の調整の3モードを提供します。

tidyfigs とは?

tidyfigsは、学術論文で使用する高品質な図を、draw.ioネイティブオブジェクトとして作成するためのAIエージェントスキルです。主に3つのモードがあります: モードAではPNGやJPGなどのラスター画像を解析し、ピクセルトレースではなく座標計測とテーマロールに基づいて編集可能なdraw.io図に変換します。モードBでは文章やLaTeX数式から3つの異なる図のプロトタイプを生成し、ユーザーが選択できるようにします。モードCでは既存の.drawio図を出版基準に合わせて調整し、印刷サイズ、フォント、カラー/グレースケール、LaTeX対応、コネクタ、キャプションなどを最適化してエクスポートします。すべてのモードでPythonビルドスクリプトを生成し、テーマロール(YAML/TOML/JSON)を使用して色やフォントを一元管理するため、再現性と再利用性が高く、出版品質を保証します。Claude Code、Cursor、Codexなどの主要なAIエージェントプラットフォームで動作します。

対応✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/anatems1/tidyfigs/tree/HEAD/skills/tidyfigs

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

学術論文向けの編集可能なdraw.io図

Pythonのビルドスクリプト(すべての座標、役割、サイズが記録され、図の再生成やテーマ変更が可能な成果物)を使って、draw.ioネイティブオブジェクトとして図を構築します。ピクセルトレースは行わず、テキストをラスタライズすることもありません。各呼び出しとルールの詳細: REFERENCE.md。コピーするパターン: EXAMPLES.md。

ツールの実行

すべてのコードは1つのファイルに含まれています。以下のTはpython drawio_toolkit.pyを意味します:

T <tool> [args]        # 例: T lint_drawio fig.drawio --theme theme.yaml   (すべてのツールで --help 使用可能)
T unpack ./tidyfigs        # オプション: 通常のフォルダ構造 scripts/ assets/ examples/; その後 python scripts/<tool>.py

Pythonでは: import drawio_toolkit; drawio_toolkit.setup() → from drawio_kit import Diagram、from figlib import *、from drawio_doc import Doc が利用可能になります。生成されたビルドスクリプトは自動的にライブラリを見つけます。

コード実行が利用できない場合? それでも同じ方法に従ってください: ビルドスクリプト(または小さな図の場合はdraw.io XML直接 — REFERENCE §14参照)をユーザーが実行できるように書き、プレビュー/リント出力やスクリーンショットを自分で見る代わりにユーザーに提供してもらうよう依頼してください。

モードの選択

入力モード出力
再作成するラスター画像A 画像<img>.drawio + <img>#drawio.png (300 dpi) (画像の隣に)
文章 / 論文セクション / 数式B テキスト3つのプロトタイプ → ユーザーが選択 → <name>.drawio
出版対応にする既存の.drawioC 拡張<name>#ENHANCED.drawio + PDF/SVG/PNG エクスポート

AまたはBの後にはCが続くことがよくあります。リクエストが明確に曖昧な場合のみ、どのモードかを尋ねてください。

共通ルール(全モード)

  • テーマロールのみ使用。 色、フォント、サイズ、線幅、不透明度はYAML/TOML/JSONテーマから取得します(fill="primary"、size="body"、sw="thick"、fill_opacity="tint")。ティントは既存のロール + 不透明度ロールであり、新しい16進数コードではありません。新しい色が必要な場合? セマンティックロール(highlight、chunk_b)を追加し、ユーザーに伝えてください。リントはテーマ外の値をすべて報告します。最終版ではそれらは存在しません。
  • 意図に正規化: 同等の要素には同一サイズ、行/列には1つのギャップ(row、row_widths、fit_row、column、grid_boxes)、共有エッジには1つの座標を使用。ラベルはラベル対象の中央に配置(x + w/2)。±1 pxのノイズは無視します。
  • コネクタの接続: 線が図形に触れる場合は常にsrc/tgt(+ exit/entry 分数)で接続。ptsにはdraw.ioが計算できないもの(自由始点、中間点、自由終点)のみをリストします。自由点は区切り線、プロット軸、接続されていないベクトルにのみ使用します。
  • 曲線エッジ(route="curved"、flex_arrow、cycle): 中間点は制御点であり、曲線は連続する中間点の中間点を通過します。
  • Z順序 = 作成順序(後で作成されたものが前面): キャンバス → パネル → 塗りつぶし → 図形 → コネクタ → テキスト → 注釈。一緒に動くものはグループ化します(with d.group("tile"))。
  • 安定したIDを重要な頂点に付与(エッジに必要、読みやすいリントのため)。
  • テキストマークアップ: **bold** *italic* __underline__ {role|colored} \n \*; インラインLaTeX ( … ); 表示数式は d.equation(r"...")(ネイティブMathJax、編集可能)。raw=True でHTMLを渡します。
  • 確認は目視で: ビルド後毎回、画像ツールでPNGプレビューを表示。数値(リント、スコア、監査)はガイドに、視覚的なチェックが決定します。プレビューはdraw.ioを近似: 絵文字は灰色の四角、円柱/書類は長方形、スモールキャップスなし、数式はmathtext経由。
  • ワークスペースの衛生: スクラッチスクリプト、プローブ、クロップは <workdir>/scratch/ に保存し、ユーザーのファイルの隣には絶対に置かない。
  • アカデミックデフォルト: 白背景、図内タイトルなし(代わりにキャプションを起草)、≤ 3色相 + ティント、色は唯一のエンコーディングにしない、1つのフォントファミリー、≤ 6–7サイズロール、≤ ~25テキストアイテム。

モードA — 画像 → 編集可能なdraw.io

手法: 計測 → 計画 → テーマ設定 → ビルドスクリプト → レンダリング → 比較 → 修正を、プレビューがソースのレイアウトと一致するまで繰り返します。座標は実際のグリッドで計測したソース画像のピクセルです(拡大表示を目視で判断するのは変換不良の最大の原因です)。

A0 トリアージ(工数を設定。最初にEXAMPLES.mdで最も近い例を読んでください):

階層見た目主な技法反復回数最終スコア
1 単純ボックス、ラベル、直線/エルボー矢印、1–3パネルrect、text、接続された edge、row2–3≥ 0.88
2 グリッド/ダッシュボードアイコン付きタイル、列、ミニフロー、箇条書きpanel、グループ、fit_row/grid_boxes、icon、直交エッジ3–5≥ 0.88
3 プロット/幾何学軸、ベクトル、点、円、波線矢印、回転ラベルdot、circle、アンカー、flex_arrow、曲線エッジ、rotation3–6≥ 0.85
4 複雑3-D曲面、メッシュ、写真、密な散布図、コールアウトsurface_mesh、polygon、image_crop、scatter_*、callout、zレイヤリング5–10≥ 0.78

A1 スキャフォールド + 検査: T new_build images/fig.png [--theme user.yaml] [--scale 1] で images/fig_drawio_work/ を作成(build.py、theme.yaml、NOTES.md、inspect/、iterations/、scratch/、history.json; 保持)。inspect/summary.md を読み、表示 source.grid*.png(位置)、source.boxes.png/.json(正確なバウンディングボックス + 中央色 — 直接使用)、source.ocr.png/.json(テキスト + フォントサイズ: 幅フィット est_px_if_regular/bold を使用、目視で選択)、source.palette.png(色 → 最も近いロール、ΔE)。スキャフォールドは検出されたボックスをbuild.pyに事前入力します。それらを精緻化します。任意の領域をズーム: T inspect_image zoom SRC --box x0 y0 x1 y1 --factor 3 --step 10; 薄い/明るい特徴を数値で調査(T inspect_image probe SRC --box … またはnumpy、REFERENCE §6.1)。OCRの誤認識や検出器が接触図形を統合することがあります — 常に目視で確認してください。

A2 NOTES.mdで計画: Z順序で領域ごとにインベントリ。要素ごとに決定: ネイティブ頂点(ボックス、パネル、ピル、円、ダイヤモンド、円柱)・ネイティブテキスト(すべてのテキスト、常に)・接続された edge(接続)・自由 edge(軸、区切り線)・flex_arrow(広い/波線)・グループ内のdot(散布図 ≤ ~400 点)・polygon/svg_layer/surface_mesh(ブロブ、ビーム、メッシュ、3-D)・image_crop(写真、テクスチャ、ロゴのみ — その上のラベルはネイティブで再構築)・ライブラリ図形または絵文字 icon(アイコン; どれかを指定)。すべての非ネイティブ決定を報告用に記録します。

A3 テーマ: ユーザーの色/フォント → ロール、ソースの各色を最も近いロールにマッピング。そうでない場合はソースの主要色を重複排除して ≤ 6–8ロールに。OCRサイズを ≤ 6–7 サイズロールにクラスタリング(同じ視覚レベル ⇒ 同じロール)。最も近いウェブセーフファミリー(Helvetica/Arial; LaTeXスタイルセリフの場合はTimes New Roman); Roboto/Interの場合は google: true。ズームで線の太さを測定します。

A4 build.pyを書く(Diagram.from_source は事前配線済み; 全APIは REFERENCE §2):

pid, (cx, cy, cw, ch) = d.panel(52, 110, 620, 570, "**AUTO-ENCODING**", header_h=70, header_fill="primary",
                                header_color="background", title_size="heading")
for (x, y, w, h), t in zip(d.row_widths(182, 336, [97, 138, 97, 97], 62, gap=13), ["[A]", "[MASK]", "[C]", "[D]"]):
    d.rect(x, y, w, h, t, fill="token", stroke="text", rounded=4, size="body", id="tok_" + t.strip("[]"))
d.rect(275, 455, 170, 62, "**Encoder**", fill="primary", color="background", rounded=4, id="enc")
d.edge([], src="enc", tgt="tok_MASK", sw="thick", exit=(.5, 0), entry=(.5, 1))
d.edge([(108, 486)], tgt="enc", entry=(0, .5))                     # 自由始点、接続終点
d.text("Dimension 2", 365, 144, size="small", rotation=-90)
d.image_crop((49, 199, 143, 309), border="text")                   # ソースからコピーした写真

ランダム化コンテンツ(散布図)は固定 seed とラベル周りのキープアウト矩形を使用します。> ~600 頂点 → 装飾マークを1つの svg_layer に統合。小さなソース → --scale 2 でテキスト ≥ 10 pxに。

A5 反復: T iterate images/fig_drawio_work --note "what changed" = ビルド → レンダリング → 比較 → リント → スナップショット + 履歴。iter_NN_side.png(すべての要素: 表現、サイズ、太さ、折り返し)、iter_NN_edges.png(赤 = ソースのみ、シアン = プレビューのみ; ペアがマージするまで移動)、iter_NN_heat.png + 最悪セル(次にそれらをズーム)を表示。パスで作業: (1) キャンバス、パネル、グリッド → (2) 検出されたバウンディングボックスにスナップして正規化された図形 → (3) すべてのコネクタをポートで接続 → (4) フォントロール、太さ、センタリング、valign → (5) エッジ差分の磨き。反復ごとに数個の関連するものを変更。スコアが下がったら元に戻す。停止条件: すべてのインベントリ要素が存在(ソースを領域ごとに再読)、リント 0 エラー、オーバーフロー/オーバーラップ/テーマ外の警告なし、並べ替えで位置ずれや誤テキストなし、スコアが横ばい(2反復で < 0.005 の向上)。draw.io CLIが存在する場合: 最終の T render_preview OUT --engine drawio を1回実行。

A6 最終化: images/fig.drawio が最新のビルド。エクスポート T render_preview images/fig.drawio -o "images/fig#drawio.png" --dpi 300。画像フォルダにはソース、.drawio、#drawio.png(+ 作業ディレクトリ)のみ。報告: パス; ネイティブ vs 埋め込み(写真、SVGレイヤー、絵文字プレースホルダ); 使用/追加されたロール; 既知の逸脱; 保持されたソースのタイプミス; 再テーマ方法(theme.yamlを編集 → python build.py)と再スケール。


モードB — テキスト → 3つの編集可能な図のプロトタイプ

文章を読み、その主張をインベントリし、3つの異なる図ファミリーを構築し、チェックし、並べ替えシートを提示します。ユーザーが選択し、最終化します。

出力場所: ファイル drafts/methods.md → drafts/methods_figures/; 貼り付けテキスト → ./figures/<slug>/; 複数セクション/長い入力 → 文章ごとに1つのサブフォルダ p1_<slug>/ …; ユーザーが名前を付けたフォルダ → 正確にその名前(--out-dir)。ユーザーにパスを伝えます。すべての文章で共有される1つのテーマ(--theme または出力ルートの theme.yaml を編集)。

B1 スキャフォールド + 分析: T new_figures drafts/methods.md [--theme t.yaml] [--split|--whole] [--passages 1,3] または T new_figures --text "<passage>" --name rag_pipeline。文章ごとに出力: 単語数、数式、構造的手がかり、3つの提案ファミリー。見出しなしの ≤ 350単語 = 1つの文章。図に値する構造がない(純粋な物語)? 図を強制する代わりにそのように伝えます。

B2 インベントリ(NOTES.md): エンティティ、順序付けられたステップ(動詞付き)、関係(方向 + 動詞)、単位付き数量、修飾語、結論 — それぞれ短い引用付き。ファミリーを確認(REFERENCE §7): デフォルト = 主要構造の3つのレイアウト(詳細 / コンパクト概要 / 代替レンズ); 強い第2構造 → 2 + 1; 数式 → 数式トリオ(付随的でない場合)。3つはトポロジー(レーン / スタック / ラジアル / 行列 / チャート / プレート)で異なり、スタイリングではない。数学、科学、アルゴリズムの文章では、静的な箇条書きカードよりも能動的なデモンストレーション(入力された行列計算、連続座標/計量空間、ベイジアンプレート、因果DAG)を優先します。

B3 build.pyを書く — 3つのビルダー。それぞれが独自のキャンバスサイズの新しいDiagramを取得:

from figlib import *
INFERRED = ["v1: ordinal ratings interpret the passage's qualitative wording"]   # ユーザーに報告
ALLOWED_TERMS = ["layer"]                # 構造的な単語、主張ではない
LINT_IGNORE = []                         # 意図的に受け入れる警告(部分文字列)
def v1(d):                               # スイムレーンパイプライン
    lane(d, 20, 20, 1060, 175, "Offline indexing")
    chain(d, ["Inspection reports\n(scanned)", "OCR\nto text", "Semantic\nchunking"], 80, 78, 140, 60,
          shapes=["document", None, None], ids=["rep", "ocr", "chk"])
VARIANTS = [dict(key="v1", name="swimlane_pipeline", size=(1100, 400), build=v1,
                 about="one line for the sheet", caption="Draft caption in the passage's words."), ...]

ルール: テーマロールのみ使用、同じカテゴリ = 3つすべてで同じスタイル; 同等のものはサイズと1つのギャップを共有(手調整の数値ではなくヘルパー); コネクタは接続、フィードバックは破線/二次的; ≤ ~25テキストアイテム、< ~150頂点(それ以上は2つの図に分割); 図内タイトルなし — caption を記述; ラベルは文章の表現で(削除による短縮、同義語は不可; 修飾語、数字、単位、頭字語はそのまま保持)。解釈的装置(評価、フロンティア、「最適」、軸の順序、テキストにない数学的事実)は INFERRED にリストされている場合のみ使用。

B4 プロトタイプ、検査、修正(≥ 2ラウンド): T prototype <passage dir> [--only v2] --note "…" で3つすべてをビルド、レンダリング、リント、忠実性チェックを実行、prototypes.png/.md を書き込み、err/warn/missをログ。各PNGとシートを表示。すべてのリント警告を修正するか、意図的な LINT_IGNORE を追加。各NOT-IN-PASSAGE単語を解決(文章の用語で言い換え · 構造的な場合は ALLOWED_TERMS · 解釈の場合は INFERRED)。リントではチェックできないものを確認: ラベルを横切る矢印、混雑したコーナー、弱い階層、不均衡な空白、2つのプロトタイプが似すぎている、インベントリに対するすべての矢印の方向。0/0/0(または許容警告)で完了し、実サイズでクリーン。

B5 提示: prototypes.png を表示; プロトタイプごとにその強調点、ドラフトキャプション、INFERREDアイテムについて1行; ソースの奇妙さ(タイプミス、矛盾した名前)を静かに修正するのではなく指摘。ユーザーに選択を依頼(または変更/組み合わせのリクエスト → build.pyを編集、再実行)。

B6 最終化: T finalize <passage dir> --pick v2 [--name rag_pipeline] [--clean] → <name>.drawio(+ .png)と CHOSEN.md(キャプション、推論)。--clean は他のプロトタイプを削除するが _work/ は保持。会場固有の磨きにはモードCを提供します。


モードC — 出版用に.drawioを拡張

1つの意図的なパス: 図の役割を理解 → 印刷サイズで計測 → その役割を果たすように変更 → 確認 → エクスポート。 インタビューの前に決して編集しない。

C1 開始: T start_enhance path/FIG.drawio [--source-image] [--text] [--artifacts DIR] [--theme]。コンテキストを発見(モードAの作業ディレクトリ: ソース画像、build.py、テーマ、NOTES; モードBの文章フォルダ: passage.md、build.py VARIANTS、CHOSEN.md、キャプション、INFERRED)、生成後の手動編集を検出、ルートを推奨、「before」を監査し、<stem>_enhance_work/ を書き込む(context.md、before_audit.md、brief.yaml、questions.md、theme.yaml、build_enhanced.py(もし…)

関連スキル