Skip to content

Add annotation_zip diff command#1634

Open
yuji38kwmt wants to merge 2 commits into
mainfrom
feature/annotation-zip-diff
Open

Add annotation_zip diff command#1634
yuji38kwmt wants to merge 2 commits into
mainfrom
feature/annotation-zip-diff

Conversation

@yuji38kwmt

Copy link
Copy Markdown
Collaborator

Summary

  • Add annofabcli annotation_zip diff for comparing two annotation ZIPs or expanded annotation directories
  • Support summary/detail CSV and JSON/pretty JSON output
  • Add command reference docs and tests for added/deleted/changed/unchanged behavior

Tests

  • make format
  • make lint
  • uv run pytest tests/annotation_zip

Copilot AI review requested due to automatic review settings May 22, 2026 05:55
@kci-pr-agent

kci-pr-agent Bot commented May 22, 2026

Copy link
Copy Markdown
Contributor

Title

Add annotation_zip diff command


Description

  • 新コマンド annotation_zip diff を追加
  • CSV/JSON形式の差分出力に対応
  • アノテーション種別ごとのメトリック計算実装
  • テストとドキュメントを追加

Changes walkthrough 📝

Relevant files
Enhancement
diff_annotation.py
アノテーションZIP差分機能の実装                                                                               

annofabcli/annotation_zip/diff_annotation.py

  • 新規コマンド実装、差分ロジック追加
  • アノテーション種別別メトリック計算関数実装
  • CSV/JSON出力用 DataFrame 作成関数追加
  • CLI 引数解析と実行フロー実装
  • +635/-0 
    Configuration changes
    subcommand_annotation_zip.py
    diff サブコマンド登録                                                                                       

    annofabcli/annotation_zip/subcommand_annotation_zip.py

    • diff サブコマンドをインポート追加
    • サブパーサーに diff コマンド登録
    +2/-0     
    Tests
    test_diff_annotation.py
    diff 機能のテスト追加                                                                                       

    tests/annotation_zip/test_diff_annotation.py

    • 差分作成ロジックのユニットテスト追加
    • CSV/JSON 出力と CLI テスト実装
    +166/-0 
    Documentation
    diff.rst
    diff コマンドリファレンス追加                                                                               

    docs/command_reference/annotation_zip/diff.rst

    • annotation_zip diff コマンドドキュメント追加
    • 使い方、出力フォーマット詳細を記載
    +128/-0 
    index.rst
    diff を index に追加                                                                                 

    docs/command_reference/annotation_zip/index.rst

    • index.rst に diff コマンドを追加
    +1/-1     

    Need help?
  • Type /help how to ... in the comments thread for any questions about PR-Agent usage.
  • Check out the documentation for more information.
  • @kci-pr-agent

    kci-pr-agent Bot commented May 22, 2026

    Copy link
    Copy Markdown
    Contributor

    PR Reviewer Guide 🔍

    Here are some key observations to aid the review process:

    ⏱️ Estimated effort to review: 4 🔵🔵🔵🔵⚪
    🧪 PR contains tests
    🔒 No security concerns identified
    ⚡ Recommended focus areas for review

    アノテーションタイプ判定

    _get_annotation_type 関数で data_type"Points" の場合に常に "points" を返しています。polygonpolyline の判別ができず、該当メトリクスが計算されない可能性があります。

    annotation_type_dict = {
        "BoundingBox": "bounding_box",
        "SinglePoint": "single_point",
        "Range": "range",
        "Points": "points",
    }
    if data_type in annotation_type_dict:
        return annotation_type_dict[data_type]
    if data_type == "Unknown" and _get_cuboid_data(data) is not None:
        return "3d_bounding_box"
    CSV属性キーのシリアライズ

    詳細CSV出力時に changed_attribute_keys を JSON 文字列として埋め込んでおり、CSV 消費側でのパースやフィルタリングが難しくなる可能性があります。

    row = detail.model_dump(exclude={"metrics"})
    row["changed_attribute_keys"] = _json_dumps(row["changed_attribute_keys"]) if row["changed_attribute_keys"] is not None else None
    row.update({metric_column: detail.metrics.get(metric_column) for metric_column in metric_columns})
    rows.append(row)

    from shapely.errors import ShapelyError
    from shapely.geometry import Polygon

    import annofabcli.common.cli
    Comment on lines +364 to +372
    annotation_type_dict = {
    "BoundingBox": "bounding_box",
    "SinglePoint": "single_point",
    "Range": "range",
    "Points": "points",
    }
    if data_type in annotation_type_dict:
    return annotation_type_dict[data_type]
    if data_type == "Unknown" and _get_cuboid_data(data) is not None:

    Copy link
    Copy Markdown
    Contributor

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    Suggestion: data_type "Points" はサポートされない annotation_type "points" にマッピングされており、polygon と polyline が区別できません。"Points" を削除するか、polygon と polyline を判別するロジックを追加してください。 [general, importance: 9]

    Suggested change
    annotation_type_dict = {
    "BoundingBox": "bounding_box",
    "SinglePoint": "single_point",
    "Range": "range",
    "Points": "points",
    }
    if data_type in annotation_type_dict:
    return annotation_type_dict[data_type]
    if data_type == "Unknown" and _get_cuboid_data(data) is not None:
    annotation_type_dict = {
    "BoundingBox": "bounding_box",
    "SinglePoint": "single_point",
    "Range": "range",
    }
    # "Points" は annotation_type 指定がない場合に
    # polygon または polyline として扱うため、明示的な判別処理を追加してください

    Comment on lines +288 to +296
    left_points = left_data["points"]
    right_points = right_data["points"]
    left_length = _point_list_length(left_points)
    right_length = _point_list_length(right_points)
    return {
    "length_change_ratio": _change_ratio(left_length, right_length),
    "start_point_distance": _euclidean_distance(left_points[0], right_points[0], keys=["x", "y"]),
    "end_point_distance": _euclidean_distance(left_points[-1], right_points[-1], keys=["x", "y"]),
    "midpoint_distance": _euclidean_distance(_point_list_center(left_points), _point_list_center(right_points), keys=["x", "y"]),

    Copy link
    Copy Markdown
    Contributor

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    Suggestion: 空のポイントリストや要素数1のケースでインデックスエラーが発生する可能性があるため、リスト長をチェックして安全に処理してください。 [possible issue, importance: 5]

    Suggested change
    left_points = left_data["points"]
    right_points = right_data["points"]
    left_length = _point_list_length(left_points)
    right_length = _point_list_length(right_points)
    return {
    "length_change_ratio": _change_ratio(left_length, right_length),
    "start_point_distance": _euclidean_distance(left_points[0], right_points[0], keys=["x", "y"]),
    "end_point_distance": _euclidean_distance(left_points[-1], right_points[-1], keys=["x", "y"]),
    "midpoint_distance": _euclidean_distance(_point_list_center(left_points), _point_list_center(right_points), keys=["x", "y"]),
    left_points = left_data["points"]
    right_points = right_data["points"]
    if len(left_points) < 2 or len(right_points) < 2:
    return {k: None for k in [
    "length_change_ratio",
    "start_point_distance",
    "end_point_distance",
    "midpoint_distance",
    "point_count_diff",
    ]}
    start_point_distance = _euclidean_distance(left_points[0], right_points[0], keys=["x", "y"])
    end_point_distance = _euclidean_distance(left_points[-1], right_points[-1], keys=["x", "y"])
    midpoint_distance = _euclidean_distance(_point_list_center(left_points), _point_list_center(right_points), keys=["x", "y"])

    Copilot AI left a comment

    Copy link
    Copy Markdown
    Contributor

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    Pull request overview

    annofabcli annotation_zip diff サブコマンドを追加し、2つのアノテーションZIP(または展開ディレクトリ)間で、アノテーションの追加・削除・変更差分を集計/詳細として出力できるようにするPRです。

    Changes:

    • 差分算出ロジック(サマリ/詳細、各種メトリクス算出)とCLI出力(CSV/JSON/pretty JSON)を追加
    • annotation_zip 配下に diff サブコマンドを登録
    • コマンドリファレンスと単体テストを追加

    Reviewed changes

    Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

    Show a summary per file
    File Description
    annofabcli/annotation_zip/diff_annotation.py 差分生成・メトリクス計算・CSV/JSON出力・CLI引数定義を追加
    annofabcli/annotation_zip/subcommand_annotation_zip.py annotation_zipdiff サブコマンドを追加登録
    docs/command_reference/annotation_zip/diff.rst annotation_zip diff の使用方法/出力項目を追加
    docs/command_reference/annotation_zip/index.rst diff をコマンド一覧に追加
    tests/annotation_zip/test_diff_annotation.py 差分コアロジックとCLI呼び出しのテストを追加

    Comment on lines +364 to +374
    annotation_type_dict = {
    "BoundingBox": "bounding_box",
    "SinglePoint": "single_point",
    "Range": "range",
    "Points": "points",
    }
    if data_type in annotation_type_dict:
    return annotation_type_dict[data_type]
    if data_type == "Unknown" and _get_cuboid_data(data) is not None:
    return "3d_bounding_box"
    return None
    Comment on lines +141 to +142


    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.

    2 participants