annofabcli 1.111.1__py3-none-any.whl → 1.112.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- annofabcli/__main__.py +1 -2
- annofabcli/annotation/annotation_query.py +10 -10
- annofabcli/annotation/change_annotation_attributes.py +9 -9
- annofabcli/annotation/change_annotation_attributes_per_annotation.py +3 -4
- annofabcli/annotation/change_annotation_properties.py +13 -13
- annofabcli/annotation/copy_annotation.py +5 -5
- annofabcli/annotation/create_classification_annotation.py +6 -6
- annofabcli/annotation/delete_annotation.py +8 -8
- annofabcli/annotation/download_annotation_zip.py +1 -3
- annofabcli/annotation/dump_annotation.py +7 -7
- annofabcli/annotation/import_annotation.py +12 -12
- annofabcli/annotation/list_annotation.py +8 -8
- annofabcli/annotation/list_annotation_count.py +1 -2
- annofabcli/annotation/merge_segmentation.py +5 -5
- annofabcli/annotation/remove_segmentation_overlap.py +4 -4
- annofabcli/annotation/restore_annotation.py +6 -6
- annofabcli/annotation/subcommand_annotation.py +1 -2
- annofabcli/annotation_specs/add_attribute_restriction.py +4 -5
- annofabcli/annotation_specs/attribute_restriction.py +8 -8
- annofabcli/annotation_specs/export_annotation_specs.py +4 -5
- annofabcli/annotation_specs/get_annotation_specs_with_attribute_id_replaced.py +3 -4
- annofabcli/annotation_specs/get_annotation_specs_with_choice_id_replaced.py +3 -4
- annofabcli/annotation_specs/get_annotation_specs_with_label_id_replaced.py +3 -4
- annofabcli/annotation_specs/list_annotation_specs_attribute.py +9 -10
- annofabcli/annotation_specs/list_annotation_specs_choice.py +9 -10
- annofabcli/annotation_specs/list_annotation_specs_history.py +2 -2
- annofabcli/annotation_specs/list_annotation_specs_label.py +8 -9
- annofabcli/annotation_specs/list_annotation_specs_label_attribute.py +10 -11
- annofabcli/annotation_specs/list_attribute_restriction.py +2 -4
- annofabcli/annotation_specs/list_label_color.py +2 -3
- annofabcli/annotation_specs/put_label_color.py +3 -4
- annofabcli/annotation_specs/subcommand_annotation_specs.py +1 -3
- annofabcli/annotation_zip/list_annotation_3d_bounding_box.py +365 -0
- annofabcli/annotation_zip/list_annotation_bounding_box_2d.py +11 -12
- annofabcli/annotation_zip/list_range_annotation.py +24 -14
- annofabcli/annotation_zip/list_single_point_annotation.py +11 -12
- annofabcli/annotation_zip/subcommand_annotation_zip.py +3 -2
- annofabcli/annotation_zip/validate_annotation.py +8 -7
- annofabcli/comment/delete_comment.py +4 -6
- annofabcli/comment/download_comment_json.py +4 -6
- annofabcli/comment/list_all_comment.py +5 -6
- annofabcli/comment/list_comment.py +3 -4
- annofabcli/comment/put_comment.py +9 -10
- annofabcli/comment/put_comment_simply.py +5 -6
- annofabcli/comment/put_inspection_comment.py +1 -3
- annofabcli/comment/put_inspection_comment_simply.py +1 -3
- annofabcli/comment/put_onhold_comment.py +1 -3
- annofabcli/comment/put_onhold_comment_simply.py +1 -3
- annofabcli/comment/subcommand_comment.py +1 -3
- annofabcli/common/bokeh.py +4 -4
- annofabcli/common/cli.py +17 -17
- annofabcli/common/download.py +28 -29
- annofabcli/common/facade.py +37 -38
- annofabcli/common/image.py +14 -14
- annofabcli/common/utils.py +8 -8
- annofabcli/common/visualize.py +13 -13
- annofabcli/experimental/list_out_of_range_annotation_for_movie.py +3 -4
- annofabcli/experimental/subcommand_experimental.py +1 -3
- annofabcli/filesystem/draw_annotation.py +26 -26
- annofabcli/filesystem/filter_annotation.py +9 -10
- annofabcli/filesystem/mask_user_info.py +14 -14
- annofabcli/filesystem/merge_annotation.py +8 -8
- annofabcli/filesystem/subcommand_filesystem.py +1 -3
- annofabcli/input_data/copy_input_data.py +8 -9
- annofabcli/input_data/delete_input_data.py +2 -2
- annofabcli/input_data/delete_metadata_key_of_input_data.py +3 -5
- annofabcli/input_data/download_input_data_json.py +4 -6
- annofabcli/input_data/list_all_input_data.py +8 -8
- annofabcli/input_data/list_all_input_data_merged_task.py +4 -4
- annofabcli/input_data/list_input_data.py +4 -4
- annofabcli/input_data/put_input_data.py +5 -5
- annofabcli/input_data/put_input_data_with_zip.py +2 -3
- annofabcli/input_data/subcommand_input_data.py +1 -3
- annofabcli/input_data/update_input_data.py +6 -8
- annofabcli/input_data/update_metadata_of_input_data.py +3 -5
- annofabcli/instruction/copy_instruction.py +4 -5
- annofabcli/instruction/download_instruction.py +4 -5
- annofabcli/instruction/list_instruction_history.py +2 -2
- annofabcli/instruction/subcommand_instruction.py +1 -3
- annofabcli/instruction/upload_instruction.py +2 -3
- annofabcli/job/delete_job.py +1 -2
- annofabcli/job/list_job.py +4 -4
- annofabcli/job/list_last_job.py +3 -3
- annofabcli/job/subcommand_job.py +1 -3
- annofabcli/job/wait_job.py +4 -5
- annofabcli/my_account/get_my_account.py +1 -2
- annofabcli/my_account/subcommand_my_account.py +1 -3
- annofabcli/organization/list_organization.py +1 -2
- annofabcli/organization/subcommand_organization.py +1 -3
- annofabcli/organization_member/change_organization_member.py +3 -4
- annofabcli/organization_member/delete_organization_member.py +3 -4
- annofabcli/organization_member/invite_organization_member.py +1 -3
- annofabcli/organization_member/list_organization_member.py +2 -2
- annofabcli/organization_member/subcommand_organization_member.py +1 -3
- annofabcli/project/change_organization_of_project.py +3 -3
- annofabcli/project/change_project_status.py +3 -3
- annofabcli/project/copy_project.py +4 -4
- annofabcli/project/create_project.py +7 -7
- annofabcli/project/diff_projects.py +4 -5
- annofabcli/project/list_project.py +4 -4
- annofabcli/project/put_project.py +1 -2
- annofabcli/project/subcommand_project.py +1 -2
- annofabcli/project/update_configuration.py +3 -3
- annofabcli/project/update_project.py +6 -8
- annofabcli/project_member/change_project_members.py +7 -7
- annofabcli/project_member/copy_project_members.py +3 -3
- annofabcli/project_member/drop_project_members.py +1 -2
- annofabcli/project_member/invite_project_members.py +1 -3
- annofabcli/project_member/list_users.py +1 -2
- annofabcli/project_member/put_project_members.py +5 -5
- annofabcli/project_member/subcommand_project_member.py +1 -3
- annofabcli/stat_visualization/mask_visualization_dir.py +8 -9
- annofabcli/stat_visualization/merge_visualization_dir.py +6 -7
- annofabcli/stat_visualization/subcommand_stat_visualization.py +1 -2
- annofabcli/stat_visualization/summarize_whole_performance_csv.py +1 -2
- annofabcli/stat_visualization/write_graph.py +2 -3
- annofabcli/stat_visualization/write_performance_rating_csv.py +20 -27
- annofabcli/statistics/histogram.py +5 -6
- annofabcli/statistics/linegraph.py +13 -14
- annofabcli/statistics/list_annotation_area.py +38 -13
- annofabcli/statistics/list_annotation_attribute.py +9 -10
- annofabcli/statistics/list_annotation_attribute_filled_count.py +30 -31
- annofabcli/statistics/list_annotation_count.py +57 -58
- annofabcli/statistics/list_annotation_duration.py +33 -34
- annofabcli/statistics/list_video_duration.py +4 -5
- annofabcli/statistics/list_worktime.py +3 -3
- annofabcli/statistics/scatter.py +9 -8
- annofabcli/statistics/subcommand_statistics.py +1 -4
- annofabcli/statistics/summarize_task_count.py +4 -6
- annofabcli/statistics/summarize_task_count_by_task_id_group.py +2 -4
- annofabcli/statistics/summarize_task_count_by_user.py +1 -3
- annofabcli/statistics/visualization/dataframe/annotation_count.py +5 -4
- annofabcli/statistics/visualization/dataframe/annotation_duration.py +6 -7
- annofabcli/statistics/visualization/dataframe/cumulative_productivity.py +15 -17
- annofabcli/statistics/visualization/dataframe/productivity_per_date.py +17 -19
- annofabcli/statistics/visualization/dataframe/project_performance.py +3 -12
- annofabcli/statistics/visualization/dataframe/task.py +11 -12
- annofabcli/statistics/visualization/dataframe/task_worktime_by_phase_user.py +9 -10
- annofabcli/statistics/visualization/dataframe/user_performance.py +21 -19
- annofabcli/statistics/visualization/dataframe/whole_performance.py +3 -4
- annofabcli/statistics/visualization/dataframe/whole_productivity_per_date.py +12 -14
- annofabcli/statistics/visualization/dataframe/worktime_per_date.py +11 -13
- annofabcli/statistics/visualization/filtering_query.py +7 -7
- annofabcli/statistics/visualization/project_dir.py +27 -14
- annofabcli/statistics/visualization/visualization_source_files.py +49 -0
- annofabcli/statistics/visualize_annotation_count.py +22 -23
- annofabcli/statistics/visualize_annotation_duration.py +21 -22
- annofabcli/statistics/visualize_statistics.py +126 -69
- annofabcli/statistics/visualize_video_duration.py +18 -20
- annofabcli/supplementary/delete_supplementary_data.py +4 -4
- annofabcli/supplementary/list_supplementary_data.py +3 -3
- annofabcli/supplementary/put_supplementary_data.py +8 -8
- annofabcli/supplementary/subcommand_supplementary.py +1 -3
- annofabcli/task/cancel_acceptance.py +16 -17
- annofabcli/task/change_operator.py +10 -12
- annofabcli/task/change_status_to_break.py +7 -9
- annofabcli/task/change_status_to_on_hold.py +10 -12
- annofabcli/task/complete_tasks.py +17 -18
- annofabcli/task/copy_tasks.py +3 -5
- annofabcli/task/delete_metadata_key_of_task.py +4 -6
- annofabcli/task/delete_tasks.py +6 -6
- annofabcli/task/download_task_json.py +4 -6
- annofabcli/task/list_all_tasks.py +7 -7
- annofabcli/task/list_all_tasks_added_task_history.py +12 -12
- annofabcli/task/list_tasks.py +6 -6
- annofabcli/task/list_tasks_added_task_history.py +9 -9
- annofabcli/task/put_tasks.py +4 -5
- annofabcli/task/put_tasks_by_count.py +1 -2
- annofabcli/task/reject_tasks.py +18 -20
- annofabcli/task/subcommand_task.py +1 -3
- annofabcli/task/update_metadata_of_task.py +5 -6
- annofabcli/task_history/download_task_history_json.py +4 -6
- annofabcli/task_history/list_all_task_history.py +5 -6
- annofabcli/task_history/list_task_history.py +3 -4
- annofabcli/task_history/subcommand_task_history.py +1 -3
- annofabcli/task_history_event/download_task_history_event_json.py +4 -6
- annofabcli/task_history_event/list_all_task_history_event.py +6 -6
- annofabcli/task_history_event/list_worktime.py +15 -15
- annofabcli/task_history_event/subcommand_task_history_event.py +1 -2
- {annofabcli-1.111.1.dist-info → annofabcli-1.112.0.dist-info}/METADATA +9 -15
- annofabcli-1.112.0.dist-info/RECORD +229 -0
- {annofabcli-1.111.1.dist-info → annofabcli-1.112.0.dist-info}/WHEEL +1 -1
- annofabcli-1.111.1.dist-info/RECORD +0 -228
- {annofabcli-1.111.1.dist-info → annofabcli-1.112.0.dist-info}/entry_points.txt +0 -0
- {annofabcli-1.111.1.dist-info → annofabcli-1.112.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -14,7 +14,7 @@ from collections.abc import Collection, Iterator
|
|
|
14
14
|
from dataclasses import dataclass, field
|
|
15
15
|
from enum import Enum
|
|
16
16
|
from pathlib import Path
|
|
17
|
-
from typing import Any
|
|
17
|
+
from typing import Any
|
|
18
18
|
|
|
19
19
|
import annofabapi
|
|
20
20
|
import pandas
|
|
@@ -26,7 +26,6 @@ from annofabapi.parser import (
|
|
|
26
26
|
)
|
|
27
27
|
from dataclasses_json import DataClassJsonMixin, config
|
|
28
28
|
|
|
29
|
-
import annofabcli
|
|
30
29
|
import annofabcli.common.cli
|
|
31
30
|
from annofabcli.common.cli import (
|
|
32
31
|
COMMAND_LINE_ERROR_STATUS_CODE,
|
|
@@ -117,10 +116,10 @@ class AnnotationDuration(DataClassJsonMixin):
|
|
|
117
116
|
input_data_id: str
|
|
118
117
|
input_data_name: str
|
|
119
118
|
|
|
120
|
-
updated_datetime:
|
|
119
|
+
updated_datetime: str | None
|
|
121
120
|
"""アノテーションJSONに格納されているアノテーションの更新日時"""
|
|
122
121
|
|
|
123
|
-
video_duration_second:
|
|
122
|
+
video_duration_second: float | None
|
|
124
123
|
"""動画の長さ[秒]"""
|
|
125
124
|
|
|
126
125
|
annotation_duration_second: float
|
|
@@ -158,17 +157,17 @@ class ListAnnotationDurationByInputData:
|
|
|
158
157
|
def __init__(
|
|
159
158
|
self,
|
|
160
159
|
*,
|
|
161
|
-
target_labels:
|
|
162
|
-
non_target_labels:
|
|
163
|
-
target_attribute_names:
|
|
164
|
-
non_target_attribute_names:
|
|
160
|
+
target_labels: Collection[str] | None = None,
|
|
161
|
+
non_target_labels: Collection[str] | None = None,
|
|
162
|
+
target_attribute_names: Collection[AttributeNameKey] | None = None,
|
|
163
|
+
non_target_attribute_names: Collection[AttributeNameKey] | None = None,
|
|
165
164
|
) -> None:
|
|
166
165
|
self.target_labels = set(target_labels) if target_labels is not None else None
|
|
167
166
|
self.target_attribute_names = set(target_attribute_names) if target_attribute_names is not None else None
|
|
168
167
|
self.non_target_labels = set(non_target_labels) if non_target_labels is not None else None
|
|
169
168
|
self.non_target_attribute_names = set(non_target_attribute_names) if non_target_attribute_names is not None else None
|
|
170
169
|
|
|
171
|
-
def get_annotation_duration(self, simple_annotation: dict[str, Any], video_duration_second:
|
|
170
|
+
def get_annotation_duration(self, simple_annotation: dict[str, Any], video_duration_second: float | None = None) -> AnnotationDuration:
|
|
172
171
|
"""
|
|
173
172
|
1個のアノテーションJSONに対して、ラベルごと/属性ごとの区間アノテーションの長さを取得する。
|
|
174
173
|
|
|
@@ -181,7 +180,7 @@ class ListAnnotationDurationByInputData:
|
|
|
181
180
|
"""区間アノテーションのdetail情報から、区間アノテーションの長さ(秒)を計算する"""
|
|
182
181
|
return (detail["data"]["end"] - detail["data"]["begin"]) / 1000
|
|
183
182
|
|
|
184
|
-
def convert_attribute_value_to_key(value:
|
|
183
|
+
def convert_attribute_value_to_key(value: bool | str | float) -> str: # noqa: FBT001
|
|
185
184
|
"""
|
|
186
185
|
アノテーションJSONに格納されている属性値を、dict用のkeyに変換する。
|
|
187
186
|
|
|
@@ -257,9 +256,9 @@ class ListAnnotationDurationByInputData:
|
|
|
257
256
|
self,
|
|
258
257
|
annotation_path: Path,
|
|
259
258
|
*,
|
|
260
|
-
input_data_json_path:
|
|
261
|
-
target_task_ids:
|
|
262
|
-
task_query:
|
|
259
|
+
input_data_json_path: Path | None = None,
|
|
260
|
+
target_task_ids: Collection[str] | None = None,
|
|
261
|
+
task_query: TaskQuery | None = None,
|
|
263
262
|
) -> list[AnnotationDuration]:
|
|
264
263
|
"""
|
|
265
264
|
アノテーションzipまたはそれを展開したディレクトリから、ラベルごと/属性ごとの区間アノテーションの長さを取得する。
|
|
@@ -267,7 +266,7 @@ class ListAnnotationDurationByInputData:
|
|
|
267
266
|
Args:
|
|
268
267
|
input_data_json_path: 入力データ全件ファイルのパス。動画の長さを取得するのに利用します。
|
|
269
268
|
"""
|
|
270
|
-
dict_input_data:
|
|
269
|
+
dict_input_data: dict[str, dict[str, Any]] | None = None
|
|
271
270
|
if input_data_json_path is not None:
|
|
272
271
|
with input_data_json_path.open() as f:
|
|
273
272
|
input_data_list = json.load(f)
|
|
@@ -292,7 +291,7 @@ class ListAnnotationDurationByInputData:
|
|
|
292
291
|
if not match_annotation_with_task_query(simple_annotation_dict, task_query):
|
|
293
292
|
continue
|
|
294
293
|
|
|
295
|
-
video_duration_second:
|
|
294
|
+
video_duration_second: float | None = None
|
|
296
295
|
if dict_input_data is not None:
|
|
297
296
|
input_data = dict_input_data[parser.input_data_id]
|
|
298
297
|
video_duration_second = input_data["system_metadata"]["input_duration"]
|
|
@@ -331,7 +330,7 @@ class AnnotationDurationCsvByAttribute:
|
|
|
331
330
|
|
|
332
331
|
return [(label, attribute_name, attribute_value) for (label, attribute_name, attribute_value) in columns if (label, attribute_name) not in non_selective_attribute_names]
|
|
333
332
|
|
|
334
|
-
def _value_columns(self, annotation_duration_list: Collection[AnnotationDuration], prior_attribute_columns:
|
|
333
|
+
def _value_columns(self, annotation_duration_list: Collection[AnnotationDuration], prior_attribute_columns: list[AttributeValueKey] | None) -> list[AttributeValueKey]:
|
|
335
334
|
all_attr_key_set = {attr_key for c in annotation_duration_list for attr_key in c.annotation_duration_second_by_attribute}
|
|
336
335
|
if prior_attribute_columns is not None:
|
|
337
336
|
remaining_columns = sorted(all_attr_key_set - set(prior_attribute_columns))
|
|
@@ -364,7 +363,7 @@ class AnnotationDurationCsvByAttribute:
|
|
|
364
363
|
def get_columns(
|
|
365
364
|
self,
|
|
366
365
|
annotation_duration_list: list[AnnotationDuration],
|
|
367
|
-
prior_attribute_columns:
|
|
366
|
+
prior_attribute_columns: list[AttributeValueKey] | None = None,
|
|
368
367
|
) -> list[AttributeValueKey]:
|
|
369
368
|
basic_columns = [
|
|
370
369
|
("project_id", "", ""),
|
|
@@ -383,7 +382,7 @@ class AnnotationDurationCsvByAttribute:
|
|
|
383
382
|
def create_df(
|
|
384
383
|
self,
|
|
385
384
|
annotation_duration_list: list[AnnotationDuration],
|
|
386
|
-
prior_attribute_columns:
|
|
385
|
+
prior_attribute_columns: list[AttributeValueKey] | None = None,
|
|
387
386
|
) -> pandas.DataFrame:
|
|
388
387
|
def to_cell(c: AnnotationDuration) -> dict[tuple[str, str, str], Any]:
|
|
389
388
|
cell: dict[AttributeValueKey, Any] = {
|
|
@@ -415,7 +414,7 @@ class AnnotationDurationCsvByLabel:
|
|
|
415
414
|
ラベルごとのアノテーション長さをCSVとして出力するためのクラス。
|
|
416
415
|
"""
|
|
417
416
|
|
|
418
|
-
def _value_columns(self, annotation_duration_list: list[AnnotationDuration], prior_label_columns:
|
|
417
|
+
def _value_columns(self, annotation_duration_list: list[AnnotationDuration], prior_label_columns: list[str] | None) -> list[str]:
|
|
419
418
|
all_attr_key_set = {attr_key for elm in annotation_duration_list for attr_key in elm.annotation_duration_second_by_label.keys()} # noqa: SIM118
|
|
420
419
|
if prior_label_columns is not None:
|
|
421
420
|
remaining_columns = sorted(all_attr_key_set - set(prior_label_columns))
|
|
@@ -429,7 +428,7 @@ class AnnotationDurationCsvByLabel:
|
|
|
429
428
|
def get_columns(
|
|
430
429
|
self,
|
|
431
430
|
annotation_duration_list: list[AnnotationDuration],
|
|
432
|
-
prior_label_columns:
|
|
431
|
+
prior_label_columns: list[str] | None = None,
|
|
433
432
|
) -> list[str]:
|
|
434
433
|
basic_columns = [
|
|
435
434
|
"project_id",
|
|
@@ -449,7 +448,7 @@ class AnnotationDurationCsvByLabel:
|
|
|
449
448
|
def create_df(
|
|
450
449
|
self,
|
|
451
450
|
annotation_duration_list: list[AnnotationDuration],
|
|
452
|
-
prior_label_columns:
|
|
451
|
+
prior_label_columns: list[str] | None = None,
|
|
453
452
|
) -> pandas.DataFrame:
|
|
454
453
|
def to_dict(c: AnnotationDuration) -> dict[str, Any]:
|
|
455
454
|
d: dict[str, Any] = {
|
|
@@ -481,16 +480,16 @@ class ListAnnotationDurationMain:
|
|
|
481
480
|
def __init__(self, service: annofabapi.Resource) -> None:
|
|
482
481
|
self.service = service
|
|
483
482
|
|
|
484
|
-
def print_annotation_duration_csv(self, annotation_duration_list: list[AnnotationDuration], csv_type: CsvType, output_file: Path, *, annotation_specs:
|
|
483
|
+
def print_annotation_duration_csv(self, annotation_duration_list: list[AnnotationDuration], csv_type: CsvType, output_file: Path, *, annotation_specs: AnnotationSpecs | None) -> None:
|
|
485
484
|
if csv_type == CsvType.LABEL:
|
|
486
485
|
# ラベル名の列順が、アノテーション仕様にあるラベル名の順番に対応するようにする。
|
|
487
|
-
label_columns:
|
|
486
|
+
label_columns: list[str] | None = None
|
|
488
487
|
if annotation_specs is not None:
|
|
489
488
|
label_columns = annotation_specs.label_keys()
|
|
490
489
|
|
|
491
490
|
df = AnnotationDurationCsvByLabel().create_df(annotation_duration_list, prior_label_columns=label_columns)
|
|
492
491
|
elif csv_type == CsvType.ATTRIBUTE:
|
|
493
|
-
attribute_columns:
|
|
492
|
+
attribute_columns: list[AttributeValueKey] | None = None
|
|
494
493
|
if annotation_specs is not None:
|
|
495
494
|
attribute_columns = annotation_specs.selective_attribute_value_keys()
|
|
496
495
|
|
|
@@ -507,14 +506,14 @@ class ListAnnotationDurationMain:
|
|
|
507
506
|
output_file: Path,
|
|
508
507
|
arg_format: FormatArgument,
|
|
509
508
|
*,
|
|
510
|
-
project_id:
|
|
511
|
-
input_data_json_path:
|
|
512
|
-
target_task_ids:
|
|
513
|
-
task_query:
|
|
514
|
-
csv_type:
|
|
509
|
+
project_id: str | None = None,
|
|
510
|
+
input_data_json_path: Path | None = None,
|
|
511
|
+
target_task_ids: Collection[str] | None = None,
|
|
512
|
+
task_query: TaskQuery | None = None,
|
|
513
|
+
csv_type: CsvType | None = None,
|
|
515
514
|
) -> None:
|
|
516
|
-
annotation_specs:
|
|
517
|
-
non_selective_attribute_name_keys:
|
|
515
|
+
annotation_specs: AnnotationSpecs | None = None
|
|
516
|
+
non_selective_attribute_name_keys: list[AttributeNameKey] | None = None
|
|
518
517
|
if project_id is not None:
|
|
519
518
|
annotation_specs = AnnotationSpecs(self.service, project_id, annotation_type=DefaultAnnotationType.RANGE.value)
|
|
520
519
|
non_selective_attribute_name_keys = annotation_specs.non_selective_attribute_name_keys()
|
|
@@ -565,7 +564,7 @@ class ListAnnotationDuration(CommandLine):
|
|
|
565
564
|
if not self.validate(args):
|
|
566
565
|
sys.exit(COMMAND_LINE_ERROR_STATUS_CODE)
|
|
567
566
|
|
|
568
|
-
project_id:
|
|
567
|
+
project_id: str | None = args.project_id
|
|
569
568
|
if project_id is not None:
|
|
570
569
|
super().validate_project(project_id, project_member_roles=[ProjectMemberRole.OWNER, ProjectMemberRole.TRAINING_DATA_USER])
|
|
571
570
|
project, _ = self.service.api.get_project(project_id)
|
|
@@ -584,7 +583,7 @@ class ListAnnotationDuration(CommandLine):
|
|
|
584
583
|
|
|
585
584
|
downloading_obj = DownloadingFile(self.service)
|
|
586
585
|
|
|
587
|
-
def download_and_print_annotation_duration(project_id: str, temp_dir: Path, *, is_latest: bool, annotation_path:
|
|
586
|
+
def download_and_print_annotation_duration(project_id: str, temp_dir: Path, *, is_latest: bool, annotation_path: Path | None) -> None:
|
|
588
587
|
if annotation_path is None:
|
|
589
588
|
annotation_path = downloading_obj.download_annotation_zip_to_dir(
|
|
590
589
|
project_id,
|
|
@@ -697,7 +696,7 @@ def main(args: argparse.Namespace) -> None:
|
|
|
697
696
|
ListAnnotationDuration(service, facade, args).main()
|
|
698
697
|
|
|
699
698
|
|
|
700
|
-
def add_parser(subparsers:
|
|
699
|
+
def add_parser(subparsers: argparse._SubParsersAction | None = None) -> argparse.ArgumentParser:
|
|
701
700
|
subcommand_name = "list_annotation_duration"
|
|
702
701
|
subcommand_help = "ラベルごとまたは属性値ごとに区間アノテーションの長さ(秒)を出力します。"
|
|
703
702
|
epilog = "オーナロールまたはアノテーションユーザロールを持つユーザで実行してください。"
|
|
@@ -7,12 +7,11 @@ import sys
|
|
|
7
7
|
import tempfile
|
|
8
8
|
from functools import partial
|
|
9
9
|
from pathlib import Path
|
|
10
|
-
from typing import Any
|
|
10
|
+
from typing import Any
|
|
11
11
|
|
|
12
12
|
import pandas
|
|
13
13
|
from annofabapi.models import InputDataType, ProjectMemberRole
|
|
14
14
|
|
|
15
|
-
import annofabcli
|
|
16
15
|
import annofabcli.common.cli
|
|
17
16
|
from annofabcli.common.cli import (
|
|
18
17
|
COMMAND_LINE_ERROR_STATUS_CODE,
|
|
@@ -83,7 +82,7 @@ class ListVideoDuration(CommandLine):
|
|
|
83
82
|
task_json: Path,
|
|
84
83
|
input_data_json: Path,
|
|
85
84
|
output_format: FormatArgument,
|
|
86
|
-
output_file:
|
|
85
|
+
output_file: Path | None,
|
|
87
86
|
) -> None:
|
|
88
87
|
with task_json.open(encoding="utf-8") as f:
|
|
89
88
|
task_list = json.load(f)
|
|
@@ -115,7 +114,7 @@ class ListVideoDuration(CommandLine):
|
|
|
115
114
|
if not self.validate(args):
|
|
116
115
|
sys.exit(COMMAND_LINE_ERROR_STATUS_CODE)
|
|
117
116
|
|
|
118
|
-
project_id:
|
|
117
|
+
project_id: str | None = args.project_id
|
|
119
118
|
if project_id is not None:
|
|
120
119
|
super().validate_project(project_id, project_member_roles=[ProjectMemberRole.OWNER, ProjectMemberRole.TRAINING_DATA_USER])
|
|
121
120
|
project, _ = self.service.api.get_project(project_id)
|
|
@@ -218,7 +217,7 @@ def main(args: argparse.Namespace) -> None:
|
|
|
218
217
|
ListVideoDuration(service, facade, args).main()
|
|
219
218
|
|
|
220
219
|
|
|
221
|
-
def add_parser(subparsers:
|
|
220
|
+
def add_parser(subparsers: argparse._SubParsersAction | None = None) -> argparse.ArgumentParser:
|
|
222
221
|
subcommand_name = "list_video_duration"
|
|
223
222
|
subcommand_help = "各タスクの動画の長さを出力します。"
|
|
224
223
|
epilog = "オーナロールまたはアノテーションユーザロールを持つユーザで実行してください。"
|
|
@@ -5,7 +5,7 @@ import datetime
|
|
|
5
5
|
import logging
|
|
6
6
|
from collections import defaultdict
|
|
7
7
|
from pathlib import Path
|
|
8
|
-
from typing import Any
|
|
8
|
+
from typing import Any
|
|
9
9
|
|
|
10
10
|
import pandas
|
|
11
11
|
from dateutil.parser import parse
|
|
@@ -110,7 +110,7 @@ class ListWorktimeFromTaskHistoryEvent(CommandLine):
|
|
|
110
110
|
def print_worktime_list(
|
|
111
111
|
self,
|
|
112
112
|
project_id: str,
|
|
113
|
-
task_history_event_json:
|
|
113
|
+
task_history_event_json: Path | None,
|
|
114
114
|
) -> None:
|
|
115
115
|
super().validate_project(project_id, project_member_roles=None)
|
|
116
116
|
|
|
@@ -160,7 +160,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
160
160
|
parser.set_defaults(subcommand_func=main)
|
|
161
161
|
|
|
162
162
|
|
|
163
|
-
def add_parser(subparsers:
|
|
163
|
+
def add_parser(subparsers: argparse._SubParsersAction | None = None) -> argparse.ArgumentParser:
|
|
164
164
|
subcommand_name = "list_worktime"
|
|
165
165
|
subcommand_help = "日ごとユーザごとの作業時間の一覧を出力します。"
|
|
166
166
|
description = "タスク履歴イベント全件ファイルから、日ごとユーザごとの作業時間の一覧を出力します。"
|
annofabcli/statistics/scatter.py
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
+
from collections.abc import Callable
|
|
4
5
|
from pathlib import Path
|
|
5
|
-
from typing import Any,
|
|
6
|
+
from typing import Any, Literal
|
|
6
7
|
|
|
7
8
|
import bokeh
|
|
8
9
|
import bokeh.layouts
|
|
@@ -62,10 +63,10 @@ class ScatterGraph:
|
|
|
62
63
|
y_axis_label: str,
|
|
63
64
|
width: int = 1200,
|
|
64
65
|
height: int = 1000,
|
|
65
|
-
tooltip_columns:
|
|
66
|
+
tooltip_columns: list[str] | None = None,
|
|
66
67
|
**figure_kwargs, # noqa: ANN003
|
|
67
68
|
) -> None:
|
|
68
|
-
fig = figure(
|
|
69
|
+
fig = figure( # type: ignore[call-arg]
|
|
69
70
|
title=title,
|
|
70
71
|
x_axis_label=x_axis_label,
|
|
71
72
|
y_axis_label=y_axis_label,
|
|
@@ -82,7 +83,7 @@ class ScatterGraph:
|
|
|
82
83
|
|
|
83
84
|
self.figure = fig
|
|
84
85
|
|
|
85
|
-
self.finding_user_widget:
|
|
86
|
+
self.finding_user_widget: MultiChoice | None = None
|
|
86
87
|
"""ユーザーを探すためのWidget"""
|
|
87
88
|
|
|
88
89
|
self.text_glyphs: dict[str, GlyphRenderer] = {}
|
|
@@ -146,7 +147,7 @@ class ScatterGraph:
|
|
|
146
147
|
|
|
147
148
|
# 1点ごとに`text`で名前を表示している理由:
|
|
148
149
|
# `add_multi_choice_widget_for_searching_user`関数で追加したMultiChoice Widgetで、名前の表示スタイルを変更するため
|
|
149
|
-
for x, y, username, user_id in zip(source.data[x_column_name], source.data[y_column_name], source.data[username_column_name], source.data[user_id_column_name]):
|
|
150
|
+
for x, y, username, user_id in zip(source.data[x_column_name], source.data[y_column_name], source.data[username_column_name], source.data[user_id_column_name], strict=False):
|
|
150
151
|
self.text_glyphs[user_id] = self.figure.text(
|
|
151
152
|
x=x,
|
|
152
153
|
y=y,
|
|
@@ -200,7 +201,7 @@ class ScatterGraph:
|
|
|
200
201
|
|
|
201
202
|
# 1点ごとに`text`で名前を表示している理由:
|
|
202
203
|
# `add_multi_choice_widget_for_searching_user`関数で追加したMultiChoice Widgetで、名前の表示スタイルを変更するため
|
|
203
|
-
for x, y, username, user_id in zip(source.data[x_column_name], source.data[y_column_name], source.data[username_column_name], source.data[user_id_column_name]):
|
|
204
|
+
for x, y, username, user_id in zip(source.data[x_column_name], source.data[y_column_name], source.data[username_column_name], source.data[user_id_column_name], strict=False):
|
|
204
205
|
self.text_glyphs[user_id] = self.figure.text(
|
|
205
206
|
x=x,
|
|
206
207
|
y=y,
|
|
@@ -228,7 +229,7 @@ class ScatterGraph:
|
|
|
228
229
|
# 理由:名前の表示は`ColumnDataSource`を使っていない(`plot_scatter`メソッド参照)ため、ツールチップには値が"???"と表示される。
|
|
229
230
|
# ユーザーが混乱しないようにするため、名前にカーソルを当てたときはツールチップが表示されないようにする。
|
|
230
231
|
if self._hover_tool is not None and self._scatter_glyphs is not None:
|
|
231
|
-
self._hover_tool.renderers = list(self._scatter_glyphs.values())
|
|
232
|
+
self._hover_tool.renderers = list(self._scatter_glyphs.values())
|
|
232
233
|
|
|
233
234
|
def configure_legend(self): # noqa: ANN201
|
|
234
235
|
"""
|
|
@@ -275,7 +276,7 @@ class ScatterGraph:
|
|
|
275
276
|
"""
|
|
276
277
|
code = code % (self.DEFAULT_USER_TEXT_FONT_STYLE, self.DEFAULT_USER_TEXT_FONT_SIZE)
|
|
277
278
|
options = [(user_id, f"{user_id}:{username}") for user_id, username in users]
|
|
278
|
-
multi_choice = MultiChoice(options=options, title="Find User:", width=300)
|
|
279
|
+
multi_choice = MultiChoice(options=options, title="Find User:", width=300) # type: ignore[arg-type]
|
|
279
280
|
multi_choice.js_on_change(
|
|
280
281
|
"value",
|
|
281
282
|
CustomJS(code=code, args=args),
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import argparse
|
|
2
|
-
from typing import Optional
|
|
3
2
|
|
|
4
|
-
import annofabcli
|
|
5
3
|
import annofabcli.common.cli
|
|
6
|
-
import annofabcli.stat_visualization.merge_visualization_dir
|
|
7
4
|
import annofabcli.statistics.list_annotation_area
|
|
8
5
|
import annofabcli.statistics.list_annotation_attribute
|
|
9
6
|
import annofabcli.statistics.list_annotation_attribute_filled_count
|
|
@@ -41,7 +38,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
41
38
|
annofabcli.statistics.visualize_video_duration.add_parser(subparsers)
|
|
42
39
|
|
|
43
40
|
|
|
44
|
-
def add_parser(subparsers:
|
|
41
|
+
def add_parser(subparsers: argparse._SubParsersAction | None = None) -> argparse.ArgumentParser:
|
|
45
42
|
subcommand_name = "statistics"
|
|
46
43
|
subcommand_help = "統計関係のサブコマンド"
|
|
47
44
|
description = "統計関係のサブコマンド"
|
|
@@ -5,13 +5,11 @@ import sys
|
|
|
5
5
|
import tempfile
|
|
6
6
|
from enum import Enum
|
|
7
7
|
from pathlib import Path
|
|
8
|
-
from typing import Optional
|
|
9
8
|
|
|
10
9
|
import pandas
|
|
11
10
|
from annofabapi.models import ProjectMemberRole, Task, TaskPhase, TaskStatus
|
|
12
11
|
from annofabapi.utils import get_number_of_rejections
|
|
13
12
|
|
|
14
|
-
import annofabcli
|
|
15
13
|
import annofabcli.common.cli
|
|
16
14
|
from annofabcli.common.cli import (
|
|
17
15
|
ArgumentParser,
|
|
@@ -136,7 +134,7 @@ class SummarizeTaskCount(CommandLine):
|
|
|
136
134
|
project, _ = self.service.api.get_project(project_id)
|
|
137
135
|
return project["configuration"]["number_of_inspections"]
|
|
138
136
|
|
|
139
|
-
def summarize_task_count(self, project_id: str, *, task_json_path:
|
|
137
|
+
def summarize_task_count(self, project_id: str, *, task_json_path: Path | None, is_latest: bool, temp_dir: Path | None = None) -> None:
|
|
140
138
|
# タスク全件ファイルをダウンロードするので、オーナロールかアノテーションユーザロールであることを確認する。
|
|
141
139
|
super().validate_project(project_id, project_member_roles=[ProjectMemberRole.OWNER, ProjectMemberRole.TRAINING_DATA_USER])
|
|
142
140
|
|
|
@@ -150,7 +148,7 @@ class SummarizeTaskCount(CommandLine):
|
|
|
150
148
|
task_count_df = create_task_count_summary(task_list, number_of_inspections=number_of_inspections)
|
|
151
149
|
annofabcli.common.utils.print_csv(task_count_df, output=self.output)
|
|
152
150
|
|
|
153
|
-
def get_task_list_with_downloading_file(self, project_id: str, task_json_path:
|
|
151
|
+
def get_task_list_with_downloading_file(self, project_id: str, task_json_path: Path | None, is_latest: bool, temp_dir: Path | None = None) -> list[Task]: # noqa: FBT001
|
|
154
152
|
if task_json_path is None:
|
|
155
153
|
if temp_dir is not None:
|
|
156
154
|
downloading_obj = DownloadingFile(self.service)
|
|
@@ -188,7 +186,7 @@ class SummarizeTaskCount(CommandLine):
|
|
|
188
186
|
project_id = args.project_id
|
|
189
187
|
task_json_path = Path(args.task_json) if args.task_json is not None else None
|
|
190
188
|
|
|
191
|
-
def process_task_count(temp_dir:
|
|
189
|
+
def process_task_count(temp_dir: Path | None) -> None:
|
|
192
190
|
self.summarize_task_count(
|
|
193
191
|
project_id,
|
|
194
192
|
task_json_path=task_json_path,
|
|
@@ -237,7 +235,7 @@ def main(args: argparse.Namespace) -> None:
|
|
|
237
235
|
SummarizeTaskCount(service, facade, args).main()
|
|
238
236
|
|
|
239
237
|
|
|
240
|
-
def add_parser(subparsers:
|
|
238
|
+
def add_parser(subparsers: argparse._SubParsersAction | None = None) -> argparse.ArgumentParser:
|
|
241
239
|
subcommand_name = "summarize_task_count"
|
|
242
240
|
subcommand_help = "タスクのフェーズ、ステータス、ステップごとにタスク数を出力します。"
|
|
243
241
|
description = "タスクのフェーズ、ステータス、ステップごとにタスク数を、CSV形式で出力します。"
|
|
@@ -6,12 +6,10 @@ import logging
|
|
|
6
6
|
import tempfile
|
|
7
7
|
from enum import Enum
|
|
8
8
|
from pathlib import Path
|
|
9
|
-
from typing import Optional
|
|
10
9
|
|
|
11
10
|
import pandas
|
|
12
11
|
from annofabapi.models import ProjectMemberRole, Task, TaskPhase, TaskStatus
|
|
13
12
|
|
|
14
|
-
import annofabcli
|
|
15
13
|
import annofabcli.common.cli
|
|
16
14
|
from annofabcli.common.cli import (
|
|
17
15
|
ArgumentParser,
|
|
@@ -99,7 +97,7 @@ def get_task_id_prefix(task_id: str, delimiter: str) -> str:
|
|
|
99
97
|
return delimiter.join(tmp_list[0 : len(tmp_list) - 1])
|
|
100
98
|
|
|
101
99
|
|
|
102
|
-
def create_task_count_summary_df(task_list: list[Task], task_id_delimiter:
|
|
100
|
+
def create_task_count_summary_df(task_list: list[Task], task_id_delimiter: str | None, task_id_groups: dict[str, list[str]] | None) -> pandas.DataFrame:
|
|
103
101
|
"""
|
|
104
102
|
タスク数を集計したDataFrameを生成する。
|
|
105
103
|
|
|
@@ -228,7 +226,7 @@ def main(args: argparse.Namespace) -> None:
|
|
|
228
226
|
SummarizeTaskCountByTaskId(service, facade, args).main()
|
|
229
227
|
|
|
230
228
|
|
|
231
|
-
def add_parser(subparsers:
|
|
229
|
+
def add_parser(subparsers: argparse._SubParsersAction | None = None) -> argparse.ArgumentParser:
|
|
232
230
|
subcommand_name = "summarize_task_count_by_task_id_group"
|
|
233
231
|
subcommand_help = "task_idのグループごとにタスク数を集計します。"
|
|
234
232
|
epilog = "アノテーションユーザまたはオーナロールを持つユーザで実行してください。"
|
|
@@ -4,12 +4,10 @@ import logging
|
|
|
4
4
|
import tempfile
|
|
5
5
|
from enum import Enum
|
|
6
6
|
from pathlib import Path
|
|
7
|
-
from typing import Optional
|
|
8
7
|
|
|
9
8
|
import pandas
|
|
10
9
|
from annofabapi.models import ProjectMemberRole, Task, TaskPhase, TaskStatus
|
|
11
10
|
|
|
12
|
-
import annofabcli
|
|
13
11
|
import annofabcli.common.cli
|
|
14
12
|
from annofabcli.common.cli import (
|
|
15
13
|
ArgumentParser,
|
|
@@ -185,7 +183,7 @@ def main(args: argparse.Namespace) -> None:
|
|
|
185
183
|
SummarizeTaskCountByUser(service, facade, args).main()
|
|
186
184
|
|
|
187
185
|
|
|
188
|
-
def add_parser(subparsers:
|
|
186
|
+
def add_parser(subparsers: argparse._SubParsersAction | None = None) -> argparse.ArgumentParser:
|
|
189
187
|
subcommand_name = "summarize_task_count_by_user"
|
|
190
188
|
subcommand_help = "ユーザごとに、担当しているタスク数を出力します。"
|
|
191
189
|
description = "ユーザごとに、担当しているタスク数をCSV形式で出力します。"
|
|
@@ -2,8 +2,9 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
4
|
from collections import defaultdict
|
|
5
|
+
from collections.abc import Callable
|
|
5
6
|
from pathlib import Path
|
|
6
|
-
from typing import Any
|
|
7
|
+
from typing import Any
|
|
7
8
|
|
|
8
9
|
import pandas
|
|
9
10
|
from annofabapi.parser import lazy_parse_simple_annotation_zip
|
|
@@ -47,9 +48,9 @@ class AnnotationCount:
|
|
|
47
48
|
annotation_zip: Path,
|
|
48
49
|
project_id: str,
|
|
49
50
|
*,
|
|
50
|
-
get_annotation_count_func:
|
|
51
|
-
include_labels:
|
|
52
|
-
exclude_labels:
|
|
51
|
+
get_annotation_count_func: Callable[[dict[str, Any]], int] | None = None,
|
|
52
|
+
include_labels: list[str] | None = None,
|
|
53
|
+
exclude_labels: list[str] | None = None,
|
|
53
54
|
) -> AnnotationCount:
|
|
54
55
|
"""
|
|
55
56
|
アノテーションZIPファイルからインスタンスを生成します。
|
|
@@ -3,7 +3,6 @@ from __future__ import annotations
|
|
|
3
3
|
import logging
|
|
4
4
|
from collections import defaultdict
|
|
5
5
|
from pathlib import Path
|
|
6
|
-
from typing import Optional
|
|
7
6
|
|
|
8
7
|
import pandas
|
|
9
8
|
from annofabapi.parser import lazy_parse_simple_annotation_zip
|
|
@@ -23,7 +22,7 @@ class AnnotationDuration:
|
|
|
23
22
|
return [
|
|
24
23
|
"project_id",
|
|
25
24
|
"task_id",
|
|
26
|
-
"
|
|
25
|
+
"annotation_duration_minute",
|
|
27
26
|
]
|
|
28
27
|
|
|
29
28
|
@classmethod
|
|
@@ -47,8 +46,8 @@ class AnnotationDuration:
|
|
|
47
46
|
annotation_zip: Path,
|
|
48
47
|
project_id: str,
|
|
49
48
|
*,
|
|
50
|
-
include_labels:
|
|
51
|
-
exclude_labels:
|
|
49
|
+
include_labels: list[str] | None = None,
|
|
50
|
+
exclude_labels: list[str] | None = None,
|
|
52
51
|
) -> AnnotationDuration:
|
|
53
52
|
"""
|
|
54
53
|
アノテーションZIPファイルからインスタンスを生成します。
|
|
@@ -62,7 +61,7 @@ class AnnotationDuration:
|
|
|
62
61
|
"""
|
|
63
62
|
logger.debug(f"アノテーションZIPファイルから区間アノテーションの長さを計算します。 :: project_id='{project_id}', file='{annotation_zip!s}'")
|
|
64
63
|
|
|
65
|
-
result: dict[tuple[str, str], float] = defaultdict(float) # key:(project_id, task_id), value
|
|
64
|
+
result: dict[tuple[str, str], float] = defaultdict(float) # key:(project_id, task_id), value:合計アノテーション時間(分)
|
|
66
65
|
|
|
67
66
|
for index, parser in enumerate(lazy_parse_simple_annotation_zip(annotation_zip)):
|
|
68
67
|
simple_annotation = parser.load_json()
|
|
@@ -83,7 +82,7 @@ class AnnotationDuration:
|
|
|
83
82
|
# 区間アノテーションの場合
|
|
84
83
|
begin = data["begin"]
|
|
85
84
|
end = data["end"]
|
|
86
|
-
total_duration += (end - begin) / 1000.0 #
|
|
85
|
+
total_duration += (end - begin) / 1000.0 / 60.0 # ミリ秒から分に変換
|
|
87
86
|
|
|
88
87
|
result[(project_id, parser.task_id)] += total_duration
|
|
89
88
|
|
|
@@ -114,7 +113,7 @@ class AnnotationDuration:
|
|
|
114
113
|
df_dtype: dict[str, str] = {
|
|
115
114
|
"project_id": "string",
|
|
116
115
|
"task_id": "string",
|
|
117
|
-
"
|
|
116
|
+
"annotation_duration_minute": "float64",
|
|
118
117
|
}
|
|
119
118
|
|
|
120
119
|
df = pandas.DataFrame(columns=cls.columns()).astype(df_dtype)
|
|
@@ -9,11 +9,9 @@ import abc
|
|
|
9
9
|
import itertools
|
|
10
10
|
import logging
|
|
11
11
|
from pathlib import Path
|
|
12
|
-
from typing import Any
|
|
12
|
+
from typing import Any
|
|
13
13
|
|
|
14
|
-
import bokeh
|
|
15
14
|
import bokeh.layouts
|
|
16
|
-
import bokeh.palettes
|
|
17
15
|
import pandas
|
|
18
16
|
from annofabapi.models import TaskPhase
|
|
19
17
|
from bokeh.models.ui import UIElement
|
|
@@ -68,7 +66,7 @@ def _create_cumulative_dataframe(task_worktime_by_phase_user: TaskWorktimeByPhas
|
|
|
68
66
|
class AbstractPhaseCumulativeProductivity(abc.ABC):
|
|
69
67
|
"""ロールごとの累積の生産性をプロットするための抽象クラス"""
|
|
70
68
|
|
|
71
|
-
def __init__(self, df: pandas.DataFrame, phase: TaskPhase, *, custom_production_volume_list:
|
|
69
|
+
def __init__(self, df: pandas.DataFrame, phase: TaskPhase, *, custom_production_volume_list: list[ProductionVolumeColumn] | None = None) -> None:
|
|
72
70
|
self.df = df
|
|
73
71
|
self.phase = phase
|
|
74
72
|
self.phase_name = self._get_phase_name(phase)
|
|
@@ -110,7 +108,7 @@ class AbstractPhaseCumulativeProductivity(abc.ABC):
|
|
|
110
108
|
user_id_list: list[str],
|
|
111
109
|
output_file: Path,
|
|
112
110
|
*,
|
|
113
|
-
metadata:
|
|
111
|
+
metadata: dict[str, Any] | None,
|
|
114
112
|
) -> None:
|
|
115
113
|
"""
|
|
116
114
|
折れ線グラフを、HTMLファイルに出力します。
|
|
@@ -150,7 +148,7 @@ class AbstractPhaseCumulativeProductivity(abc.ABC):
|
|
|
150
148
|
username = df_subset.iloc[0]["username"]
|
|
151
149
|
|
|
152
150
|
line_count += 1
|
|
153
|
-
for line_graph, (x_column, y_column) in zip(line_graph_list, columns_list):
|
|
151
|
+
for line_graph, (x_column, y_column) in zip(line_graph_list, columns_list, strict=False):
|
|
154
152
|
line_graph.add_line(source, x_column=x_column, y_column=y_column, legend_label=username, color=color)
|
|
155
153
|
|
|
156
154
|
plotted_users.append((user_id, username))
|
|
@@ -184,14 +182,14 @@ class AbstractPhaseCumulativeProductivity(abc.ABC):
|
|
|
184
182
|
production_volume_name: str,
|
|
185
183
|
output_file: Path,
|
|
186
184
|
*,
|
|
187
|
-
target_user_id_list:
|
|
188
|
-
metadata:
|
|
185
|
+
target_user_id_list: list[str] | None = None,
|
|
186
|
+
metadata: dict[str, Any] | None = None,
|
|
189
187
|
) -> None:
|
|
190
188
|
raise NotImplementedError()
|
|
191
189
|
|
|
192
190
|
|
|
193
191
|
class AnnotatorCumulativeProductivity(AbstractPhaseCumulativeProductivity):
|
|
194
|
-
def __init__(self, df: pandas.DataFrame, *, custom_production_volume_list:
|
|
192
|
+
def __init__(self, df: pandas.DataFrame, *, custom_production_volume_list: list[ProductionVolumeColumn] | None = None) -> None:
|
|
195
193
|
super().__init__(df, phase=TaskPhase.ANNOTATION, custom_production_volume_list=custom_production_volume_list)
|
|
196
194
|
|
|
197
195
|
@classmethod
|
|
@@ -205,8 +203,8 @@ class AnnotatorCumulativeProductivity(AbstractPhaseCumulativeProductivity):
|
|
|
205
203
|
production_volume_name: str,
|
|
206
204
|
output_file: Path,
|
|
207
205
|
*,
|
|
208
|
-
target_user_id_list:
|
|
209
|
-
metadata:
|
|
206
|
+
target_user_id_list: list[str] | None = None,
|
|
207
|
+
metadata: dict[str, Any] | None = None,
|
|
210
208
|
) -> None:
|
|
211
209
|
"""
|
|
212
210
|
生産性を教師付作業者ごとにプロットする。
|
|
@@ -267,7 +265,7 @@ class AnnotatorCumulativeProductivity(AbstractPhaseCumulativeProductivity):
|
|
|
267
265
|
|
|
268
266
|
|
|
269
267
|
class InspectorCumulativeProductivity(AbstractPhaseCumulativeProductivity):
|
|
270
|
-
def __init__(self, df: pandas.DataFrame, *, custom_production_volume_list:
|
|
268
|
+
def __init__(self, df: pandas.DataFrame, *, custom_production_volume_list: list[ProductionVolumeColumn] | None = None) -> None:
|
|
271
269
|
super().__init__(df, phase=TaskPhase.INSPECTION, custom_production_volume_list=custom_production_volume_list)
|
|
272
270
|
|
|
273
271
|
@classmethod
|
|
@@ -281,8 +279,8 @@ class InspectorCumulativeProductivity(AbstractPhaseCumulativeProductivity):
|
|
|
281
279
|
production_volume_name: str,
|
|
282
280
|
output_file: Path,
|
|
283
281
|
*,
|
|
284
|
-
target_user_id_list:
|
|
285
|
-
metadata:
|
|
282
|
+
target_user_id_list: list[str] | None = None,
|
|
283
|
+
metadata: dict[str, Any] | None = None,
|
|
286
284
|
) -> None:
|
|
287
285
|
"""
|
|
288
286
|
生産性を検査作業者ごとにプロットする。
|
|
@@ -329,7 +327,7 @@ class InspectorCumulativeProductivity(AbstractPhaseCumulativeProductivity):
|
|
|
329
327
|
|
|
330
328
|
|
|
331
329
|
class AcceptorCumulativeProductivity(AbstractPhaseCumulativeProductivity):
|
|
332
|
-
def __init__(self, df: pandas.DataFrame, *, custom_production_volume_list:
|
|
330
|
+
def __init__(self, df: pandas.DataFrame, *, custom_production_volume_list: list[ProductionVolumeColumn] | None = None) -> None:
|
|
333
331
|
super().__init__(df, phase=TaskPhase.ACCEPTANCE, custom_production_volume_list=custom_production_volume_list)
|
|
334
332
|
|
|
335
333
|
@classmethod
|
|
@@ -343,8 +341,8 @@ class AcceptorCumulativeProductivity(AbstractPhaseCumulativeProductivity):
|
|
|
343
341
|
production_volume_name: str,
|
|
344
342
|
output_file: Path,
|
|
345
343
|
*,
|
|
346
|
-
target_user_id_list:
|
|
347
|
-
metadata:
|
|
344
|
+
target_user_id_list: list[str] | None = None,
|
|
345
|
+
metadata: dict[str, Any] | None = None,
|
|
348
346
|
) -> None:
|
|
349
347
|
"""
|
|
350
348
|
生産性を受入作業者ごとにプロットする。
|