diff --git a/annofabcli/stat_visualization/mask_visualization_dir.py b/annofabcli/stat_visualization/mask_visualization_dir.py index 87d3105c..ac4549ab 100755 --- a/annofabcli/stat_visualization/mask_visualization_dir.py +++ b/annofabcli/stat_visualization/mask_visualization_dir.py @@ -33,7 +33,7 @@ from annofabcli.statistics.visualization.dataframe.task_worktime_by_phase_user import TaskWorktimeByPhaseUser from annofabcli.statistics.visualization.dataframe.user_performance import UserPerformance from annofabcli.statistics.visualization.dataframe.worktime_per_date import WorktimePerDate -from annofabcli.statistics.visualization.model import ProductionVolumeColumn +from annofabcli.statistics.visualization.model import ProductionVolumeColumn, TaskCompletionCriteria from annofabcli.statistics.visualization.project_dir import ProjectDir logger = logging.getLogger(__name__) @@ -223,12 +223,15 @@ def main(args: argparse.Namespace) -> None: create_custom_production_volume_list(args.custom_production_volume) if args.custom_production_volume is not None else None ) + task_completion_criteria = TaskCompletionCriteria(args.task_completion_criteria) input_project_dir = ProjectDir( args.dir, + task_completion_criteria, custom_production_volume_list=custom_production_volume_list, ) output_project_dir = ProjectDir( args.output_dir, + task_completion_criteria, metadata=input_project_dir.read_metadata(), ) mask_visualization_dir( @@ -271,6 +274,16 @@ def parse_args(parser: argparse.ArgumentParser) -> None: "column_list": [{"value": "video_duration_minute", "name": "動画長さ"}], } + parser.add_argument( + "--task_completion_criteria", + type=str, + choices=[e.value for e in TaskCompletionCriteria], + default=TaskCompletionCriteria.ACCEPTANCE_COMPLETED.value, + help="タスクの完了条件を指定します。\n" + "* ``acceptance_completed``: タスクが受入フェーズの完了状態であれば「タスクの完了」とみなす\n" + "* ``acceptance_reached``: タスクが受入フェーズに到達したら「タスクの完了」とみなす\n", + ) + parser.add_argument( "--custom_production_volume", type=str, diff --git a/annofabcli/stat_visualization/merge_visualization_dir.py b/annofabcli/stat_visualization/merge_visualization_dir.py index cd5b4add..fd359d83 100755 --- a/annofabcli/stat_visualization/merge_visualization_dir.py +++ b/annofabcli/stat_visualization/merge_visualization_dir.py @@ -35,7 +35,7 @@ WholeProductivityPerFirstAnnotationStartedDate, ) from annofabcli.statistics.visualization.dataframe.worktime_per_date import WorktimePerDate -from annofabcli.statistics.visualization.model import ProductionVolumeColumn +from annofabcli.statistics.visualization.model import ProductionVolumeColumn, TaskCompletionCriteria from annofabcli.statistics.visualization.project_dir import MergingInfo, ProjectDir logger = logging.getLogger(__name__) @@ -45,11 +45,13 @@ class WritingVisualizationFile: def __init__( self, output_project_dir: ProjectDir, + task_completion_criteria: TaskCompletionCriteria, *, user_id_list: Optional[List[str]] = None, minimal_output: bool = False, ) -> None: self.output_project_dir = output_project_dir + self.task_completion_criteria = task_completion_criteria self.user_id_list = user_id_list self.minimal_output = minimal_output @@ -126,13 +128,13 @@ def write_task_worktime_by_phase_user(self, task_worktime_by_phase_user: TaskWor @_catch_exception def write_performance_per_first_annotation_started_date(self, task: Task) -> None: - obj = WholeProductivityPerFirstAnnotationStartedDate.from_task(task) + obj = WholeProductivityPerFirstAnnotationStartedDate.from_task(task, self.task_completion_criteria) self.output_project_dir.write_whole_productivity_per_first_annotation_started_date(obj) self.output_project_dir.write_whole_productivity_line_graph_per_annotation_started_date(obj) @_catch_exception def write_merge_performance_per_date(self, task: Task, worktime_per_date: WorktimePerDate) -> None: - obj = WholeProductivityPerCompletedDate.from_df_wrapper(task, worktime_per_date) + obj = WholeProductivityPerCompletedDate.from_df_wrapper(task, worktime_per_date, task_completion_criteria=self.task_completion_criteria) self.output_project_dir.write_whole_productivity_per_date(obj) self.output_project_dir.write_whole_productivity_line_graph_per_date(obj) @@ -176,7 +178,7 @@ def merge_task_worktime_by_phase_user(self) -> TaskWorktimeByPhaseUser: merged_obj = TaskWorktimeByPhaseUser.merge(*tmp_list, custom_production_volume_list=self.custom_production_volume_list) return merged_obj - def create_merging_info(self) -> MergingInfo: + def create_merging_info(self, task_completion_criteria: TaskCompletionCriteria) -> MergingInfo: """ `project_info.json`の内容から、どのようにマージしたかを示す情報を作成する。 """ @@ -186,12 +188,15 @@ def create_merging_info(self) -> MergingInfo: project_info = project_dir.read_project_info() project_info_list.append(project_info) - merge_info = MergingInfo(target_dir_list=target_dir_list, project_info_list=project_info_list) + merge_info = MergingInfo( + target_dir_list=target_dir_list, project_info_list=project_info_list, task_completion_criteria=task_completion_criteria + ) return merge_info def merge_visualization_dir( # pylint: disable=too-many-statements project_dir_list: List[ProjectDir], + task_completion_criteria: TaskCompletionCriteria, output_project_dir: ProjectDir, *, custom_production_volume_list: Optional[list[ProductionVolumeColumn]] = None, @@ -200,7 +205,7 @@ def merge_visualization_dir( # pylint: disable=too-many-statements ) -> None: merging_obj = MergingVisualizationFile(project_dir_list, custom_production_volume_list=custom_production_volume_list) - merging_info = merging_obj.create_merging_info() + merging_info = merging_obj.create_merging_info(task_completion_criteria) output_project_dir.metadata = merging_info.to_dict(encode_json=True) # 基本となるCSVファイルを読み込みマージする @@ -210,7 +215,9 @@ def merge_visualization_dir( # pylint: disable=too-many-statements user_performance = UserPerformance.from_df_wrapper(task_worktime_by_phase_user=task_worktime_by_phase_user, worktime_per_date=worktime_per_date) whole_performance = WholePerformance.from_df_wrapper(task_worktime_by_phase_user=task_worktime_by_phase_user, worktime_per_date=worktime_per_date) - writing_obj = WritingVisualizationFile(output_project_dir, user_id_list=user_id_list, minimal_output=minimal_output) + writing_obj = WritingVisualizationFile( + output_project_dir, user_id_list=user_id_list, minimal_output=minimal_output, task_completion_criteria=task_completion_criteria + ) writing_obj.write_task_list_and_histogram(task) writing_obj.write_worktime_per_date(worktime_per_date) @@ -258,13 +265,14 @@ def main(args: argparse.Namespace) -> None: custom_production_volume_list = ( create_custom_production_volume_list(args.custom_production_volume) if args.custom_production_volume is not None else None ) - + task_completion_criteria = TaskCompletionCriteria(args.task_completion_criteria) merge_visualization_dir( - project_dir_list=[ProjectDir(e) for e in args.dir], + project_dir_list=[ProjectDir(e, task_completion_criteria) for e in args.dir], + task_completion_criteria=task_completion_criteria, user_id_list=user_id_list, custom_production_volume_list=custom_production_volume_list, minimal_output=args.minimal, - output_project_dir=ProjectDir(args.output_dir), + output_project_dir=ProjectDir(args.output_dir, task_completion_criteria), ) @@ -272,6 +280,16 @@ def parse_args(parser: argparse.ArgumentParser) -> None: parser.add_argument("--dir", type=Path, nargs="+", required=True, help="マージ対象ディレクトリ。2つ以上指定してください。") parser.add_argument("-o", "--output_dir", type=Path, required=True, help="出力先ディレクトリ。配下にプロジェクト名のディレクトリが出力される。") + parser.add_argument( + "--task_completion_criteria", + type=str, + choices=[e.value for e in TaskCompletionCriteria], + default=TaskCompletionCriteria.ACCEPTANCE_COMPLETED.value, + help="タスクの完了条件を指定します。\n" + "* ``acceptance_completed``: タスクが受入フェーズの完了状態であれば「タスクの完了」とみなす\n" + "* ``acceptance_reached``: タスクが受入フェーズに到達したら「タスクの完了」とみなす\n", + ) + parser.add_argument( "-u", "--user_id", diff --git a/annofabcli/stat_visualization/summarize_whole_performance_csv.py b/annofabcli/stat_visualization/summarize_whole_performance_csv.py index a7926eef..d01aa61c 100644 --- a/annofabcli/stat_visualization/summarize_whole_performance_csv.py +++ b/annofabcli/stat_visualization/summarize_whole_performance_csv.py @@ -11,7 +11,7 @@ get_json_from_args, ) from annofabcli.statistics.visualization.dataframe.project_performance import ProjectPerformance -from annofabcli.statistics.visualization.model import ProductionVolumeColumn +from annofabcli.statistics.visualization.model import ProductionVolumeColumn, TaskCompletionCriteria from annofabcli.statistics.visualization.project_dir import ProjectDir logger = logging.getLogger(__name__) @@ -31,7 +31,10 @@ def create_custom_production_volume_list(cli_value: str) -> list[ProductionVolum def main(args: argparse.Namespace) -> None: root_dir: Path = args.dir - project_dir_list = [ProjectDir(elm) for elm in root_dir.iterdir() if elm.is_dir()] + # task_completion_criteriaは何でもよいので、とりあえずACCEPTANCE_COMPLETEDを指定 + project_dir_list = [ + ProjectDir(elm, task_completion_criteria=TaskCompletionCriteria.ACCEPTANCE_COMPLETED) for elm in root_dir.iterdir() if elm.is_dir() + ] custom_production_volume_list = ( create_custom_production_volume_list(args.custom_production_volume) if args.custom_production_volume is not None else None diff --git a/annofabcli/stat_visualization/write_graph.py b/annofabcli/stat_visualization/write_graph.py index 89192b7f..ac2ec245 100755 --- a/annofabcli/stat_visualization/write_graph.py +++ b/annofabcli/stat_visualization/write_graph.py @@ -21,7 +21,7 @@ InspectorProductivityPerDate, ) from annofabcli.statistics.visualization.dataframe.task import Task -from annofabcli.statistics.visualization.model import ProductionVolumeColumn +from annofabcli.statistics.visualization.model import ProductionVolumeColumn, TaskCompletionCriteria from annofabcli.statistics.visualization.project_dir import ProjectDir logger = logging.getLogger(__name__) @@ -129,8 +129,9 @@ def main(args: argparse.Namespace) -> None: create_custom_production_volume_list(args.custom_production_volume) if args.custom_production_volume is not None else None ) - input_project_dir = ProjectDir(args.dir, custom_production_volume_list=custom_production_volume_list) - output_project_dir = ProjectDir(args.output_dir, metadata=input_project_dir.read_metadata()) + task_completion_criteria = TaskCompletionCriteria(args.task_completion_criteria) + input_project_dir = ProjectDir(args.dir, task_completion_criteria, custom_production_volume_list=custom_production_volume_list) + output_project_dir = ProjectDir(args.output_dir, task_completion_criteria, metadata=input_project_dir.read_metadata()) main_obj = WritingGraph( project_dir=input_project_dir, output_project_dir=output_project_dir, @@ -164,6 +165,16 @@ def parse_args(parser: argparse.ArgumentParser) -> None: help="必要最小限のファイルを出力します。", ) + parser.add_argument( + "--task_completion_criteria", + type=str, + choices=[e.value for e in TaskCompletionCriteria], + default=TaskCompletionCriteria.ACCEPTANCE_COMPLETED.value, + help="タスクの完了条件を指定します。\n" + "* ``acceptance_completed``: タスクが受入フェーズの完了状態であれば「タスクの完了」とみなす\n" + "* ``acceptance_reached``: タスクが受入フェーズに到達したら「タスクの完了」とみなす\n", + ) + custom_production_volume_sample = { "column_list": [{"value": "video_duration_minute", "name": "動画長さ"}], } diff --git a/annofabcli/stat_visualization/write_performance_rating_csv.py b/annofabcli/stat_visualization/write_performance_rating_csv.py index 1696364c..573c62b0 100755 --- a/annofabcli/stat_visualization/write_performance_rating_csv.py +++ b/annofabcli/stat_visualization/write_performance_rating_csv.py @@ -21,7 +21,7 @@ ProjectPerformance, ProjectWorktimePerMonth, ) -from annofabcli.statistics.visualization.model import ProductionVolumeColumn, WorktimeColumn +from annofabcli.statistics.visualization.model import ProductionVolumeColumn, TaskCompletionCriteria, WorktimeColumn from annofabcli.statistics.visualization.project_dir import ProjectDir logger = logging.getLogger(__name__) @@ -326,7 +326,11 @@ def create_rating_df( custom_production_volume_list_by_directory.get(p_project_dir.name) if custom_production_volume_list_by_directory is not None else None ) project_title = p_project_dir.name - project_dir = ProjectDir(p_project_dir, custom_production_volume_list=custom_production_volume_list) + project_dir = ProjectDir( + p_project_dir, + task_completion_criteria=TaskCompletionCriteria.ACCEPTANCE_COMPLETED, + custom_production_volume_list=custom_production_volume_list, + ) project_dir_list.append(project_dir) try: @@ -471,7 +475,8 @@ def create_user_df(target_dir: Path) -> pandas.DataFrame: if not p_project_dir.is_dir(): continue - project_dir = ProjectDir(p_project_dir) + # task_completion_criteriaは何でもよいので、とりあえずACCEPTANCE_COMPLETEDを指定 + project_dir = ProjectDir(p_project_dir, task_completion_criteria=TaskCompletionCriteria.ACCEPTANCE_COMPLETED) try: user_performance = project_dir.read_user_performance() diff --git a/annofabcli/statistics/visualization/dataframe/task.py b/annofabcli/statistics/visualization/dataframe/task.py index fa7939f0..e6064edd 100644 --- a/annofabcli/statistics/visualization/dataframe/task.py +++ b/annofabcli/statistics/visualization/dataframe/task.py @@ -110,7 +110,8 @@ def columns(self) -> list[str]: "first_acceptance_username", "first_acceptance_worktime_hour", "first_acceptance_started_datetime", - # 最後の受入 + # 受入フェーズの日時 + "first_acceptance_reached_datetime", "first_acceptance_completed_datetime", # 作業時間に関する内容 "worktime_hour", @@ -229,6 +230,7 @@ def empty(cls, *, custom_production_volume_list: Optional[list[ProductionVolumeC "first_acceptance_user_id", "first_acceptance_username", "first_acceptance_started_datetime", + "first_acceptance_reached_datetime", "first_acceptance_completed_datetime", ] diff --git a/annofabcli/statistics/visualization/dataframe/whole_productivity_per_date.py b/annofabcli/statistics/visualization/dataframe/whole_productivity_per_date.py index b7a8e877..510f2f1e 100644 --- a/annofabcli/statistics/visualization/dataframe/whole_productivity_per_date.py +++ b/annofabcli/statistics/visualization/dataframe/whole_productivity_per_date.py @@ -14,7 +14,7 @@ import bokeh.layouts import bokeh.palettes import pandas -from annofabapi.models import TaskStatus +from annofabapi.models import TaskPhase, TaskStatus from bokeh.models import DataRange1d from bokeh.models.ui import UIElement from bokeh.models.widgets.markups import Div @@ -22,6 +22,7 @@ from dateutil.parser import parse from annofabcli.common.bokeh import create_pretext_from_metadata +from annofabcli.common.type_util import assert_noreturn from annofabcli.common.utils import datetime_to_date, print_csv from annofabcli.statistics.linegraph import ( LineGraph, @@ -32,7 +33,7 @@ ) from annofabcli.statistics.visualization.dataframe.task import Task from annofabcli.statistics.visualization.dataframe.worktime_per_date import WorktimePerDate -from annofabcli.statistics.visualization.model import ProductionVolumeColumn +from annofabcli.statistics.visualization.model import ProductionVolumeColumn, TaskCompletionCriteria logger = logging.getLogger(__name__) @@ -91,10 +92,17 @@ def _plot_and_moving_average( class WholeProductivityPerCompletedDate: - """受入完了日ごとの全体の生産量と生産性に関する情報""" + """完了日ごとの全体の生産量と生産性に関する情報""" - def __init__(self, df: pandas.DataFrame, *, custom_production_volume_list: Optional[list[ProductionVolumeColumn]] = None) -> None: + def __init__( + self, + df: pandas.DataFrame, + task_completion_criteria: TaskCompletionCriteria, + *, + custom_production_volume_list: Optional[list[ProductionVolumeColumn]] = None, + ) -> None: self.df = df + self.task_completion_criteria = task_completion_criteria self.custom_production_volume_list = custom_production_volume_list if custom_production_volume_list is not None else [] def _validate_df_for_output(self, output_file: Path) -> bool: @@ -105,11 +113,15 @@ def _validate_df_for_output(self, output_file: Path) -> bool: @classmethod def from_csv( - cls, csv_file: Path, *, custom_production_volume_list: Optional[list[ProductionVolumeColumn]] = None + cls, + csv_file: Path, + task_completion_criteria: TaskCompletionCriteria, + *, + custom_production_volume_list: Optional[list[ProductionVolumeColumn]] = None, ) -> WholeProductivityPerCompletedDate: """CSVファイルからインスタンスを生成します。""" df = pandas.read_csv(str(csv_file)) - return cls(df, custom_production_volume_list=custom_production_volume_list) + return cls(df, task_completion_criteria, custom_production_volume_list=custom_production_volume_list) @staticmethod def _create_df_date(date_index1: pandas.Index, date_index2: pandas.Index) -> pandas.DataFrame: @@ -129,9 +141,11 @@ def _create_df_date(date_index1: pandas.Index, date_index2: pandas.Index) -> pan return pandas.DataFrame(index=[e.strftime("%Y-%m-%d") for e in pandas.date_range(start_date, end_date)]) @classmethod - def from_df_wrapper(cls, task: Task, worktime_per_date: WorktimePerDate) -> WholeProductivityPerCompletedDate: + def from_df_wrapper( + cls, task: Task, worktime_per_date: WorktimePerDate, task_completion_criteria: TaskCompletionCriteria + ) -> WholeProductivityPerCompletedDate: """ - 受入完了日毎の全体の生産量、生産性を算出する。 + 完了日毎の全体の生産量、生産性を算出する。 Args: task: タスク情報が格納されたDataFrameをラップするクラスのインスタンス @@ -148,21 +162,25 @@ def from_df_wrapper(cls, task: Task, worktime_per_date: WorktimePerDate) -> Whol # 生産量を表す列名 production_volume_columns = ["input_data_count", "annotation_count", *[e.value for e in task.custom_production_volume_list]] - df_sub_task = task.df[["task_id", "first_acceptance_completed_datetime", *production_volume_columns]].copy() - df_sub_task["first_acceptance_completed_date"] = df_sub_task["first_acceptance_completed_datetime"].map( - lambda e: datetime_to_date(e) if not pandas.isna(e) else None - ) + if task_completion_criteria == TaskCompletionCriteria.ACCEPTANCE_COMPLETED: + datetime_column = "first_acceptance_completed_datetime" + elif task_completion_criteria == TaskCompletionCriteria.ACCEPTANCE_REACHED: + datetime_column = "first_acceptance_reached_datetime" + else: + assert_noreturn(task_completion_criteria) + + df_sub_task = task.df[["task_id", datetime_column, *production_volume_columns]].copy() + date_column = datetime_column.replace("_datetime", "_date") + df_sub_task[date_column] = df_sub_task[datetime_column].map(lambda e: datetime_to_date(e) if not pandas.isna(e) else None) - # タスク完了日を軸にして集計する + # 完了日を軸にして集計する df_agg_sub_task = df_sub_task.pivot_table( values=production_volume_columns, - index="first_acceptance_completed_date", + index=date_column, aggfunc="sum", ).fillna(0) if len(df_agg_sub_task) > 0: - df_agg_sub_task["task_count"] = df_sub_task.pivot_table( - values=["task_id"], index="first_acceptance_completed_date", aggfunc="count" - ).fillna(0) + df_agg_sub_task["task_count"] = df_sub_task.pivot_table(values=["task_id"], index=date_column, aggfunc="count").fillna(0) else: # 列だけ作る df_agg_sub_task = df_agg_sub_task.assign(**{key: 0 for key in production_volume_columns}, task_count=0) @@ -212,7 +230,7 @@ def from_df_wrapper(cls, task: Task, worktime_per_date: WorktimePerDate) -> Whol df_date["date"] = df_date.index cls._add_velocity_columns(df_date, production_volume_columns) - return cls(df_date, custom_production_volume_list=task.custom_production_volume_list) + return cls(df_date, task_completion_criteria, custom_production_volume_list=task.custom_production_volume_list) @classmethod def _add_velocity_columns(cls, df: pandas.DataFrame, production_volume_columns: list[str]) -> None: @@ -248,16 +266,17 @@ def add_velocity_column(df: pandas.DataFrame, numerator_column: str, denominator for unit in production_volume_columns: add_velocity_column(df, numerator_column=f"{category}_worktime_hour", denominator_column=unit) - @staticmethod - def _create_div_element() -> Div: + def _create_div_element(self) -> Div: """ HTMLページの先頭に付与するdiv要素を生成する。 """ - return Div( - text="""

用語

-

「X日のタスク数」とは、X日に初めて受入完了状態になったタスクの個数です。

- """ - ) + if self.task_completion_criteria == TaskCompletionCriteria.ACCEPTANCE_COMPLETED: + str_task = "受入フェーズ完了状態" + elif self.task_completion_criteria == TaskCompletionCriteria.ACCEPTANCE_REACHED: + str_task = "受入フェーズ" + else: + assert_noreturn(self.task_completion_criteria) + return Div(text="

注意

" f"

「X日のタスク数」は、X日に初めて{str_task}になったタスクの個数です。

") def plot( self, @@ -735,9 +754,11 @@ def create_worktime_line_graph() -> LineGraph: write_bokeh_graph(bokeh.layouts.column(element_list), output_file) @classmethod - def empty(cls, *, custom_production_volume_list: Optional[list[ProductionVolumeColumn]] = None) -> WholeProductivityPerCompletedDate: + def empty( + cls, *, task_completion_criteria: TaskCompletionCriteria, custom_production_volume_list: Optional[list[ProductionVolumeColumn]] = None + ) -> WholeProductivityPerCompletedDate: df = pandas.DataFrame(columns=cls.get_columns(custom_production_volume_list=custom_production_volume_list)) - return cls(df, custom_production_volume_list=custom_production_volume_list) + return cls(df, task_completion_criteria, custom_production_volume_list=custom_production_volume_list) @property def columns(self) -> list[str]: @@ -807,17 +828,28 @@ def to_csv(self, output_file: Path) -> None: class WholeProductivityPerFirstAnnotationStartedDate: """教師付開始日ごとの全体の生産量と生産性に関する情報""" - def __init__(self, df: pandas.DataFrame, *, custom_production_volume_list: Optional[list[ProductionVolumeColumn]] = None) -> None: + def __init__( + self, + df: pandas.DataFrame, + task_completion_criteria: TaskCompletionCriteria, + *, + custom_production_volume_list: Optional[list[ProductionVolumeColumn]] = None, + ) -> None: + self.task_completion_criteria = task_completion_criteria self.custom_production_volume_list = custom_production_volume_list if custom_production_volume_list is not None else [] self.df = df @classmethod def from_csv( - cls, csv_file: Path, *, custom_production_volume_list: Optional[list[ProductionVolumeColumn]] = None + cls, + csv_file: Path, + task_completion_criteria: TaskCompletionCriteria, + *, + custom_production_volume_list: Optional[list[ProductionVolumeColumn]] = None, ) -> WholeProductivityPerFirstAnnotationStartedDate: """CSVファイルからインスタンスを生成します。""" df = pandas.read_csv(str(csv_file)) - return cls(df, custom_production_volume_list=custom_production_volume_list) + return cls(df, task_completion_criteria, custom_production_volume_list=custom_production_volume_list) @classmethod def _add_velocity_columns(cls, df: pandas.DataFrame, production_volume_columns: list[str]) -> None: @@ -840,12 +872,19 @@ def add_velocity_column(df: pandas.DataFrame, numerator_column: str, denominator add_velocity_column(df, numerator_column="acceptance_worktime_hour", denominator_column=column) @classmethod - def from_task(cls, task: Task) -> WholeProductivityPerFirstAnnotationStartedDate: + def from_task(cls, task: Task, task_completion_criteria: TaskCompletionCriteria) -> WholeProductivityPerFirstAnnotationStartedDate: # 生産量を表す列名 production_volume_columns = ["input_data_count", "annotation_count", *[e.value for e in task.custom_production_volume_list]] df_task = task.df - df_sub_task = df_task[df_task["status"] == TaskStatus.COMPLETE.value][ + if task_completion_criteria == TaskCompletionCriteria.ACCEPTANCE_COMPLETED: + df_sub_task = df_task[df_task["status"] == TaskStatus.COMPLETE.value] + elif task_completion_criteria == TaskCompletionCriteria.ACCEPTANCE_REACHED: + df_sub_task = df_task[df_task["phase"] == TaskPhase.ACCEPTANCE.value] + else: + assert_noreturn(task_completion_criteria) + + df_sub_task = df_sub_task[ [ "task_id", "first_annotation_started_datetime", @@ -893,7 +932,7 @@ def from_task(cls, task: Task) -> WholeProductivityPerFirstAnnotationStartedDate df_date["first_annotation_started_date"] = df_date.index # 生産性情報などの列を追加する cls._add_velocity_columns(df_date, production_volume_columns) - return cls(df_date, custom_production_volume_list=task.custom_production_volume_list) + return cls(df_date, task_completion_criteria, custom_production_volume_list=task.custom_production_volume_list) def _validate_df_for_output(self, output_file: Path) -> bool: if len(self.df) == 0: @@ -902,9 +941,11 @@ def _validate_df_for_output(self, output_file: Path) -> bool: return True @classmethod - def empty(cls, *, custom_production_volume_list: Optional[list[ProductionVolumeColumn]] = None) -> WholeProductivityPerFirstAnnotationStartedDate: + def empty( + cls, task_completion_criteria: TaskCompletionCriteria, *, custom_production_volume_list: Optional[list[ProductionVolumeColumn]] = None + ) -> WholeProductivityPerFirstAnnotationStartedDate: df = pandas.DataFrame(columns=cls.get_columns(custom_production_volume_list=custom_production_volume_list)) - return cls(df, custom_production_volume_list=custom_production_volume_list) + return cls(df, task_completion_criteria, custom_production_volume_list=custom_production_volume_list) @staticmethod def get_columns(*, custom_production_volume_list: Optional[list[ProductionVolumeColumn]] = None) -> list[str]: @@ -973,12 +1014,16 @@ def create_div_element() -> Div: """ HTMLページの先頭に付与するdiv要素を生成する。 """ + if self.task_completion_criteria == TaskCompletionCriteria.ACCEPTANCE_COMPLETED: + str_task = "受入フェーズ完了状態" + elif self.task_completion_criteria == TaskCompletionCriteria.ACCEPTANCE_REACHED: + str_task = "受入フェーズ" + else: + assert_noreturn(self.task_completion_criteria) return Div( - text="""

注意

-

「X日の作業時間」とは、「X日に教師付開始したタスクにかけた作業時間」です。 - 「X日に作業した時間」ではありません。 -

- """ + text="

注意

" + f"

「X日のタスク数」は、X日に教師付フェーズを開始したタスクの内、{str_task}であるタスクの個数です。

" + f"

「X日の作業時間」は、X日のタスク数にかけた作業時間です。X日に作業した時間ではないことに注意してください。

" ) def create_line_graph(title: str, y_axis_label: str, tooltip_columns: list[str]) -> LineGraph: diff --git a/annofabcli/statistics/visualization/model.py b/annofabcli/statistics/visualization/model.py index 75a60c29..fe9a01ae 100644 --- a/annofabcli/statistics/visualization/model.py +++ b/annofabcli/statistics/visualization/model.py @@ -21,3 +21,14 @@ class ProductionVolumeColumn: """CSVの列名""" name: str """列の名前。グラフに表示する名前などに使用する""" + + +class TaskCompletionCriteria(Enum): + """ + タスクの完了の条件 + """ + + ACCEPTANCE_COMPLETED = "acceptance_completed" + """タスクが受入フェーズの完了状態であれば「タスクの完了」とみなす""" + ACCEPTANCE_REACHED = "acceptance_reached" + """タスクが受入フェーズに到達したら「タスクの完了」とみなす""" diff --git a/annofabcli/statistics/visualization/project_dir.py b/annofabcli/statistics/visualization/project_dir.py index 8d5a4e0c..274a89b6 100644 --- a/annofabcli/statistics/visualization/project_dir.py +++ b/annofabcli/statistics/visualization/project_dir.py @@ -25,7 +25,7 @@ ) from annofabcli.statistics.visualization.dataframe.worktime_per_date import WorktimePerDate from annofabcli.statistics.visualization.filtering_query import FilteringQuery -from annofabcli.statistics.visualization.model import ProductionVolumeColumn +from annofabcli.statistics.visualization.model import ProductionVolumeColumn, TaskCompletionCriteria logger = logging.getLogger(__name__) @@ -53,11 +53,13 @@ class ProjectDir(DataClassJsonMixin): def __init__( self, project_dir: Path, + task_completion_criteria: TaskCompletionCriteria, *, metadata: Optional[dict[str, Any]] = None, custom_production_volume_list: Optional[list[ProductionVolumeColumn]] = None, ) -> None: self.project_dir = project_dir + self.task_completion_criteria = task_completion_criteria self.metadata = metadata self.custom_production_volume_list = custom_production_volume_list @@ -223,10 +225,14 @@ def read_whole_productivity_per_date(self) -> WholeProductivityPerCompletedDate: file = self.project_dir / self.FILENAME_WHOLE_PRODUCTIVITY_PER_DATE if file.exists(): return WholeProductivityPerCompletedDate.from_csv( - self.project_dir / self.FILENAME_WHOLE_PRODUCTIVITY_PER_DATE, custom_production_volume_list=self.custom_production_volume_list + self.project_dir / self.FILENAME_WHOLE_PRODUCTIVITY_PER_DATE, + task_completion_criteria=self.task_completion_criteria, + custom_production_volume_list=self.custom_production_volume_list, ) else: - return WholeProductivityPerCompletedDate.empty(custom_production_volume_list=self.custom_production_volume_list) + return WholeProductivityPerCompletedDate.empty( + task_completion_criteria=self.task_completion_criteria, custom_production_volume_list=self.custom_production_volume_list + ) def write_whole_productivity_per_date(self, obj: WholeProductivityPerCompletedDate) -> None: """ @@ -249,10 +255,13 @@ def read_whole_productivity_per_first_annotation_started_date(self) -> WholeProd if file.exists(): return WholeProductivityPerFirstAnnotationStartedDate.from_csv( file, + self.task_completion_criteria, custom_production_volume_list=self.custom_production_volume_list, ) else: - return WholeProductivityPerFirstAnnotationStartedDate.empty(custom_production_volume_list=self.custom_production_volume_list) + return WholeProductivityPerFirstAnnotationStartedDate.empty( + self.task_completion_criteria, custom_production_volume_list=self.custom_production_volume_list + ) def write_whole_productivity_per_first_annotation_started_date(self, obj: WholeProductivityPerFirstAnnotationStartedDate) -> None: """ @@ -453,6 +462,8 @@ class ProjectInfo(DataClassJsonMixin): """入力データの種類""" measurement_datetime: str """計測日時。(2004-04-01T12:00+09:00形式)""" + task_completion_criteria: TaskCompletionCriteria + """タスクの完了条件""" query: FilteringQuery """集計対象を絞り込むためのクエリ""" @@ -465,3 +476,5 @@ class MergingInfo(DataClassJsonMixin): """マージ対象のディレクトリ名""" project_info_list: List[ProjectInfo] """マージ対象のプロジェクト情報""" + task_completion_criteria: TaskCompletionCriteria + """タスクの完了条件""" diff --git a/annofabcli/statistics/visualize_statistics.py b/annofabcli/statistics/visualize_statistics.py index b0d4b4e1..8e01a723 100644 --- a/annofabcli/statistics/visualize_statistics.py +++ b/annofabcli/statistics/visualize_statistics.py @@ -48,7 +48,7 @@ ) from annofabcli.statistics.visualization.dataframe.worktime_per_date import WorktimePerDate from annofabcli.statistics.visualization.filtering_query import FilteringQuery, filter_tasks -from annofabcli.statistics.visualization.model import ProductionVolumeColumn, WorktimeColumn +from annofabcli.statistics.visualization.model import ProductionVolumeColumn, TaskCompletionCriteria, WorktimeColumn from annofabcli.statistics.visualization.project_dir import ProjectDir, ProjectInfo from annofabcli.statistics.visualization.visualization_source_files import VisualizationSourceFiles @@ -60,10 +60,11 @@ def get_project_output_dir(project_title: str) -> str: class WriteCsvGraph: - def __init__( + def __init__( # noqa: PLR0913 self, service: annofabapi.Resource, project_id: str, + task_completion_criteria: TaskCompletionCriteria, filtering_query: FilteringQuery, visualization_source_files: VisualizationSourceFiles, project_dir: ProjectDir, @@ -76,6 +77,7 @@ def __init__( ) -> None: self.service = service self.project_id = project_id + self.task_completion_criteria = task_completion_criteria self.project_dir = project_dir self.filtering_query = filtering_query self.visualize_source_files = visualization_source_files @@ -212,11 +214,15 @@ def write_worktime_per_date(self, user_id_list: Optional[List[str]] = None) -> N self.project_dir.write_worktime_per_date_user(worktime_per_date_obj) task = self._get_task() - productivity_per_completed_date_obj = WholeProductivityPerCompletedDate.from_df_wrapper(task, worktime_per_date_obj) + productivity_per_completed_date_obj = WholeProductivityPerCompletedDate.from_df_wrapper( + task, worktime_per_date_obj, task_completion_criteria=self.task_completion_criteria + ) self.project_dir.write_whole_productivity_per_date(productivity_per_completed_date_obj) - productivity_per_started_date_obj = WholeProductivityPerFirstAnnotationStartedDate.from_task(task) + productivity_per_started_date_obj = WholeProductivityPerFirstAnnotationStartedDate.from_task( + task, task_completion_criteria=self.task_completion_criteria + ) self.project_dir.write_whole_productivity_per_first_annotation_started_date(productivity_per_started_date_obj) if not self.output_only_text: @@ -250,6 +256,7 @@ def __init__( # noqa: PLR0913 *, temp_dir: Path, # タスクの絞り込み関係 + task_completion_criteria: TaskCompletionCriteria, task_query: Optional[TaskQuery], start_date: Optional[str] = None, end_date: Optional[str] = None, @@ -268,7 +275,7 @@ def __init__( # noqa: PLR0913 self.service = service self.facade = AnnofabApiFacade(service) self.temp_dir = temp_dir - + self.task_completion_criteria = task_completion_criteria self.filtering_query = FilteringQuery(task_query=task_query, start_date=start_date, end_date=end_date) self.minimal_output = minimal_output self.output_only_text = output_only_text @@ -289,6 +296,7 @@ def get_project_info(self, project_id: str) -> ProjectInfo: project_title=project_title, input_data_type=project_info["input_data_type"], measurement_datetime=annofabapi.utils.str_now(), + task_completion_criteria=self.task_completion_criteria, query=self.filtering_query, ) return project_summary @@ -307,7 +315,7 @@ def visualize_statistics(self, project_id: str, output_project_dir: Path) -> Non project_info = self.get_project_info(project_id) logger.info(f"project_title='{project_info.project_title}'") - project_dir = ProjectDir(output_project_dir, metadata=project_info.to_dict(encode_json=True)) + project_dir = ProjectDir(output_project_dir, self.task_completion_criteria, metadata=project_info.to_dict(encode_json=True)) project_dir.write_project_info(project_info) if self.actual_worktime is not None: @@ -347,6 +355,7 @@ def visualize_statistics(self, project_id: str, output_project_dir: Path) -> Non write_obj = WriteCsvGraph( self.service, project_id, + task_completion_criteria=self.task_completion_criteria, filtering_query=self.filtering_query, visualization_source_files=visualization_source_files, project_dir=project_dir, @@ -452,6 +461,7 @@ def visualize_statistics( # noqa: PLR0913 # pylint: disable=too-many-positiona self, temp_dir: Path, task_query: Optional[TaskQuery], + task_completion_criteria: TaskCompletionCriteria, user_id_list: Optional[list[str]], actual_worktime: ActualWorktime, annotation_count: Optional[AnnotationCount], @@ -470,6 +480,7 @@ def visualize_statistics( # noqa: PLR0913 # pylint: disable=too-many-positiona main_obj = VisualizingStatisticsMain( service=self.service, temp_dir=temp_dir, + task_completion_criteria=task_completion_criteria, task_query=task_query, user_ids=user_id_list, actual_worktime=actual_worktime, @@ -496,7 +507,7 @@ def visualize_statistics( # noqa: PLR0913 # pylint: disable=too-many-positiona ) if len(output_project_dir_list) > 0: - project_dir_list = [ProjectDir(e) for e in output_project_dir_list] + project_dir_list = [ProjectDir(e, task_completion_criteria) for e in output_project_dir_list] custom_production_volume_list = ( custom_production_volume.custom_production_volume_list if custom_production_volume is not None else None ) @@ -554,11 +565,13 @@ def main(self) -> None: # pylint: disable=too-many-branches create_custom_production_volume(args.custom_production_volume) if args.custom_production_volume is not None else None ) + task_completion_criteria = TaskCompletionCriteria(args.task_completion_criteria) if args.temp_dir is None: with tempfile.TemporaryDirectory() as str_temp_dir: self.visualize_statistics( temp_dir=Path(str_temp_dir), task_query=task_query, + task_completion_criteria=task_completion_criteria, user_id_list=user_id_list, actual_worktime=actual_worktime, annotation_count=annotation_count, @@ -578,6 +591,7 @@ def main(self) -> None: # pylint: disable=too-many-branches else: self.visualize_statistics( temp_dir=args.temp_dir, + task_completion_criteria=task_completion_criteria, task_query=task_query, user_id_list=user_id_list, actual_worktime=actual_worktime, @@ -614,6 +628,16 @@ def parse_args(parser: argparse.ArgumentParser) -> None: ), ) + parser.add_argument( + "--task_completion_criteria", + type=str, + choices=[e.value for e in TaskCompletionCriteria], + default=TaskCompletionCriteria.ACCEPTANCE_COMPLETED.value, + help="タスクの完了条件を指定します。\n" + "* ``acceptance_completed``: タスクが受入フェーズの完了状態であれば「タスクの完了」とみなす\n" + "* ``acceptance_reached``: タスクが受入フェーズに到達したら「タスクの完了」とみなす\n", + ) + parser.add_argument("-o", "--output_dir", type=Path, required=True, help="出力先ディレクトリのパスを指定してください。") parser.add_argument( diff --git a/annofabcli/task/list_tasks_added_task_history.py b/annofabcli/task/list_tasks_added_task_history.py index bfcad902..78ccd5ad 100644 --- a/annofabcli/task/list_tasks_added_task_history.py +++ b/annofabcli/task/list_tasks_added_task_history.py @@ -115,6 +115,25 @@ def get_first_acceptance_completed_datetime(task_histories: list[TaskHistory]) - return None + @staticmethod + def get_first_acceptance_reached_datetime(task_histories: list[TaskHistory]) -> Optional[str]: + """はじめて受入フェーズに到達した日時を取得する。 + 受入フェーズを着手した日時とは異なる。 + 必ず`first_acceptance_started_datetime`よりも前の日時になる。 + + Args: + task_histories (List[TaskHistory]): [description] + + """ + for index, history in enumerate(task_histories): + if history["phase"] != TaskPhase.ACCEPTANCE.value: + continue + + first_acceptance_reached_datetime = task_histories[index - 1]["ended_datetime"] + assert first_acceptance_reached_datetime is not None + return first_acceptance_reached_datetime + return None + @staticmethod def is_acceptance_phase_skipped(task_histories: list[TaskHistory]) -> bool: """抜取受入によって、受入フェーズでスキップされたことがあるかを取得する。 @@ -269,6 +288,7 @@ def add_task_history_additional_info_to_task(self, task: dict[str, Any], task_hi self._add_task_history_info_by_phase(task, task_histories, phase=TaskPhase.ACCEPTANCE) # 初めて受入が完了した日時 + task["first_acceptance_reached_datetime"] = self.get_first_acceptance_reached_datetime(task_histories) task["first_acceptance_completed_datetime"] = self.get_first_acceptance_completed_datetime(task_histories) # 受入完了日時を設定 @@ -339,6 +359,7 @@ def _get_output_target_columns() -> List[str]: # 差し戻し回数 "number_of_rejections_by_inspection", "number_of_rejections_by_acceptance", + "first_acceptance_reached_datetime", "first_acceptance_completed_datetime", "completed_datetime", "inspection_is_skipped", diff --git "a/docs/command_reference/statistics/visualize_output_rst/\346\212\230\343\202\214\347\267\232-\346\250\252\350\273\270_\346\227\245-\345\205\250\344\275\223_html.rst" "b/docs/command_reference/statistics/visualize_output_rst/\346\212\230\343\202\214\347\267\232-\346\250\252\350\273\270_\346\227\245-\345\205\250\344\275\223_html.rst" index 58578f1b..111f12fe 100644 --- "a/docs/command_reference/statistics/visualize_output_rst/\346\212\230\343\202\214\347\267\232-\346\250\252\350\273\270_\346\227\245-\345\205\250\344\275\223_html.rst" +++ "b/docs/command_reference/statistics/visualize_output_rst/\346\212\230\343\202\214\347\267\232-\346\250\252\350\273\270_\346\227\245-\345\205\250\344\275\223_html.rst" @@ -4,7 +4,7 @@ line-graph/折れ線-横軸_日-全体.html タスク数や作業時間、生産性などを、日毎にプロットした折れ線グラフです。 -グラフのデータは ``日毎の生産量と生産性.csv`` を参照しています。 +グラフのデータは :doc:`日毎の生産量と生産性_csv` を参照しています。 日毎のタスク数や作業時間、生産性などをの推移が分かります。 diff --git "a/docs/command_reference/statistics/visualize_output_rst/\346\225\231\345\270\253\344\273\230\351\226\213\345\247\213\346\227\245\346\257\216\343\201\256\347\224\237\347\224\243\351\207\217\343\201\250\347\224\237\347\224\243\346\200\247_csv.rst" "b/docs/command_reference/statistics/visualize_output_rst/\346\225\231\345\270\253\344\273\230\351\226\213\345\247\213\346\227\245\346\257\216\343\201\256\347\224\237\347\224\243\351\207\217\343\201\250\347\224\237\347\224\243\346\200\247_csv.rst" index 1545334c..7f4c174a 100644 --- "a/docs/command_reference/statistics/visualize_output_rst/\346\225\231\345\270\253\344\273\230\351\226\213\345\247\213\346\227\245\346\257\216\343\201\256\347\224\237\347\224\243\351\207\217\343\201\250\347\224\237\347\224\243\346\200\247_csv.rst" +++ "b/docs/command_reference/statistics/visualize_output_rst/\346\225\231\345\270\253\344\273\230\351\226\213\345\247\213\346\227\245\346\257\216\343\201\256\347\224\237\347\224\243\351\207\217\343\201\250\347\224\237\347\224\243\346\200\247_csv.rst" @@ -9,13 +9,27 @@ 参照頻度が高い列の詳細を、以下に記載します。 -* worktime_hour: その日に教師付を開始したタスクにかけた作業時間[hour]。 -* task_count: その日に教師付開始したタスクの個数。 -* input_data_count: その日に教師付開始したタスクに含まれている入力データの個数。 -* worktime_hour/annotation_count: アノテーションあたりの計測作業時間[hour]。生産性の指標になる。 +* ``first_annotation_started_date`` : 教師付フェーズを開始した日 +* ``worktime_hour`` : その日に教師付フェーズを開始して、現在作業が完了したタスクにかけた計測作業時間(アノテーションエディタ画面を触っていた作業の時間)。単位は時間。 +* ``task_count`` : 作業が完了したタスクの数 +* ``input_data_count`` : 作業が完了したタスクに含まれている入力データの数 +* ``annotation_count`` : 作業が完了したタスクに含まれているアノテーションの数 +* ``worktime_hour/annotation_count`` : アノテーションあたりの計測作業時間。単位は時間。 + .. note:: + ``worktime`` は、その日に教師付フェーズを開始したタスクにかけた作業時間です。その日に作業した時間ではないことに注意してください。 + + +``task_count`` の算出方法 +================================= +``--task_completion_criteria`` で指定した値によって、 ``task_count`` の算出方法が異なります。 + +``--task_completion_criteria acceptance_completed`` を指定すると、 ``task_count`` は、受入フェーズ完了状態のタスクの数になります。 + +``--task_completion_criteria acceptance_reached`` を指定すると、 ``task_count`` は、受入フェーズタスクの数になります。 + + - ``worktime`` (作業時間)は、その日に教師付を開始したタスクにかけた作業時間です。その日に作業した時間ではないことに、注意してください。 diff --git "a/docs/command_reference/statistics/visualize_output_rst/\346\227\245\346\257\216\343\201\256\347\224\237\347\224\243\351\207\217\343\201\250\347\224\237\347\224\243\346\200\247_csv.rst" "b/docs/command_reference/statistics/visualize_output_rst/\346\227\245\346\257\216\343\201\256\347\224\237\347\224\243\351\207\217\343\201\250\347\224\237\347\224\243\346\200\247_csv.rst" index 245f88ac..cb3f9f38 100644 --- "a/docs/command_reference/statistics/visualize_output_rst/\346\227\245\346\257\216\343\201\256\347\224\237\347\224\243\351\207\217\343\201\250\347\224\237\347\224\243\346\200\247_csv.rst" +++ "b/docs/command_reference/statistics/visualize_output_rst/\346\227\245\346\257\216\343\201\256\347\224\237\347\224\243\351\207\217\343\201\250\347\224\237\347\224\243\346\200\247_csv.rst" @@ -7,17 +7,39 @@ `日毎の生産量と生産性.csv `_ -参照頻度が高い列の詳細を、以下に記載します。 -* monitored_worktime_hour: 計測作業時間[hour](アノテーションエディタ画面を触っていた作業時間) -* actual_worktime_hour: 実績作業時間[hour](労務管理画面から入力した作業時間) -* task_count: 作業したタスク数。タスクが初めて受入完了状態になったときに「作業した」とみなしている。 -* input_data_count: 作業したタスクに含まれている入力データ数 -* actual_worktime/annotation_count: アノテーションあたりの実績作業時間[hour]。生産性の指標になる。 +* ``actual_worktime_hour`` : 実績作業時間( ``--labor_csv`` で渡された実際の作業時間)。単位は時間。 +* ``monitored_worktime_hour`` : 計測作業時間(アノテーションエディタ画面を触っていた作業の時間)。単位は時間。 +* ``task_count`` : 作業が完了したタスクの数 +* ``input_data_count`` : 作業が完了したタスクに含まれている入力データの数 +* ``annotation_count`` : 作業が完了したタスクに含まれているアノテーションの数 +* ``actual_worktime_hour/annotation_count`` : アノテーションあたりの実績作業時間。単位は時間。 +* ``working_user_count`` : 作業したユーザーの数 -.. note:: - task_count は「その日に初めて受入完了状態になったタスクの個数」です。受入完了状態のタスクが差し戻されても、task_countは変わりません。 - 受入完了状態の差し戻し後の作業量が多い場合、task_countの値が実際と合わないケースがあります。 +``task_count`` の算出方法 +================================= +``--task_completion_criteria`` で指定した値によって、 ``task_count`` の算出方法が異なります。 + +``--task_completion_criteria acceptance_completed`` を指定すると、 ``task_count`` は、初めて受入フェーズ完了状態になったタスクの数になります。 +受入取消によって完了状態でないタスクも、「作業が完了したタスク」に含まれます。 + +``--task_completion_criteria acceptance_reached`` を指定すると、 ``task_count`` は、初めて受入フェーズになったタスクの数になります。 +受入フェーズでの差し戻しによって受入フェーズでないタスクも、「作業が完了したタスク」に含まれます。 + + + +.. note:: + + + 以下のタスクが多いと、 ``task_count`` の推移は実際よりも早い日にタスクが完了したように見えます。 + + * 受入取消されたタスク( ``--task_completion_criteria acceptance_completed`` の場合) + * 受入フェーズで差し戻されたタスク( ``--task_completion_criteria acceptance_reached`` の場合) + + その場合は :doc:`教師付開始日毎の生産量と生産性_csv` も参照することをお勧めします。 + :doc:`教師付開始日毎の生産量と生産性_csv` の ``task_count`` は、教師付フェーズを開始した日ごとに集計しています。 + 一度に大量のタスクの教師付けフェーズを開始する運用でなければ、 :doc:`教師付開始日毎の生産量と生産性_csv` の方が生産量の推移を正しく表しているかもしれません。 + \ No newline at end of file diff --git "a/docs/command_reference/statistics/visualize_output_rst/\347\264\257\347\251\215\346\212\230\343\202\214\347\267\232-\346\250\252\350\273\270_\346\227\245-\345\205\250\344\275\223_html.rst" "b/docs/command_reference/statistics/visualize_output_rst/\347\264\257\347\251\215\346\212\230\343\202\214\347\267\232-\346\250\252\350\273\270_\346\227\245-\345\205\250\344\275\223_html.rst" index fbf7f673..e9dd14bf 100644 --- "a/docs/command_reference/statistics/visualize_output_rst/\347\264\257\347\251\215\346\212\230\343\202\214\347\267\232-\346\250\252\350\273\270_\346\227\245-\345\205\250\344\275\223_html.rst" +++ "b/docs/command_reference/statistics/visualize_output_rst/\347\264\257\347\251\215\346\212\230\343\202\214\347\267\232-\346\250\252\350\273\270_\346\227\245-\345\205\250\344\275\223_html.rst" @@ -3,7 +3,7 @@ line-graph/累積折れ線-横軸_日-全体.html ========================================== タスク数や作業時間の累積値をプロットした折れ線グラフです。 -グラフのデータは ``日毎の生産量と生産性.csv`` を参照しています。 +グラフのデータは :doc:`日毎の生産量と生産性_csv` を参照しています。 `累積折れ線-横軸_日-全体.html `_ diff --git a/docs/command_reference/task/list_added_task_history.rst b/docs/command_reference/task/list_added_task_history.rst index 570db835..a85ff3f1 100644 --- a/docs/command_reference/task/list_added_task_history.rst +++ b/docs/command_reference/task/list_added_task_history.rst @@ -123,6 +123,7 @@ JSON出力 "first_acceptance_user_id": "alice", "first_acceptance_username": "Alice", "acceptance_worktime_hour": 0.16520972222222222, + "first_acceptance_reached_datetime": "2022-10-24T15:14:18.967+09:00", "first_acceptance_completed_datetime": "2022-10-25T15:14:18.967+09:00", "completed_datetime": "2022-10-25T15:14:18.967+09:00", "inspection_is_skipped": false, @@ -139,6 +140,7 @@ JSON出力 * annotation_worktime_hour: 教師付フェーズの作業時間[hour] * inspection_worktime_hour: 検査フェーズの作業時間[hour] * acceptance_worktime_hour: 受入フェーズの作業時間[hour] +* first_acceptance_reached_datetime: はじめて受入フェーズに到達した日時。 ``first_annotation_started_datetime`` より前の日時になる * first_acceptance_completed_datetime: はじめて受入完了状態になった日時 * completed_datetime: 受入完了状態になった日時 * inspection_is_skipped: 抜取検査により検査フェーズがスキップされたかどうか @@ -147,9 +149,6 @@ JSON出力 * first_annotation_username: 最初の教師付フェーズを担当したユーザの名前 * first_annotation_started_datetime: 最初の教師付フェーズを開始した日時 * ... -* last_acceptance_user_id: 最後の受入フェーズを担当したユーザのuser_id -* last_acceptance_username: 最後の受入フェーズを担当したユーザの名前 -* last_acceptance_started_datetime: 最後の受入フェーズを開始した日時 diff --git "a/tests/data/stat_visualization/mask_visualization_dir/visualization1/\343\202\277\343\202\271\343\202\257list.csv" "b/tests/data/stat_visualization/mask_visualization_dir/visualization1/\343\202\277\343\202\271\343\202\257list.csv" index 606db397..0a6ef3e4 100644 --- "a/tests/data/stat_visualization/mask_visualization_dir/visualization1/\343\202\277\343\202\271\343\202\257list.csv" +++ "b/tests/data/stat_visualization/mask_visualization_dir/visualization1/\343\202\277\343\202\271\343\202\257list.csv" @@ -1,4 +1,4 @@ -project_id,task_id,phase,phase_stage,status,number_of_rejections_by_inspection,number_of_rejections_by_acceptance,created_datetime,first_annotation_user_id,first_annotation_username,first_annotation_worktime_hour,first_annotation_started_datetime,first_inspection_user_id,first_inspection_username,first_inspection_worktime_hour,first_inspection_started_datetime,first_acceptance_user_id,first_acceptance_username,first_acceptance_worktime_hour,first_acceptance_started_datetime,first_acceptance_completed_datetime,worktime_hour,annotation_worktime_hour,inspection_worktime_hour,acceptance_worktime_hour,input_data_count,annotation_count,inspection_comment_count,inspection_comment_count_in_inspection_phase,inspection_comment_count_in_acceptance_phase,inspection_is_skipped,acceptance_is_skipped -prj1,task1,acceptance,1,complete,0,0,2023-12-27T21:53:53.72+09:00,bob,bob,0.185208888888889,2024-01-09T11:27:00.015+09:00,,,,,alice,alice,0.547898611111111,2024-01-09T13:03:11.715+09:00,2024-01-11T13:04:01.134+09:00,0.7331075,0.185208888888889,0,0.547898611111111,10,20,0,0,0,False,False -prj1,task2,acceptance,1,complete,0,1,2023-12-27T21:54:09.075+09:00,bob,bob,0.214761944444444,2024-01-09T11:43:19.68+09:00,,,,,alice,alice,0.267357222222222,2024-01-10T15:10:43.647+09:00,2024-01-11T14:23:30.968+09:00,0.538455555555556,0.220598611111111,0,0.317856944444444,10,20,1,0,1,False,False -prj1,task3,acceptance,1,complete,0,1,2023-12-27T21:54:24.099+09:00,bob,bob,0.195141111111111,2024-01-09T11:56:20.118+09:00,,,,,chris,chris,0.573847777777778,2024-01-09T15:23:53.291+09:00,2024-01-16T11:14:02.961+09:00,1.3610325,0.324384722222222,0,1.03664777777778,10,20,2,0,2,False,False +project_id,task_id,phase,phase_stage,status,number_of_rejections_by_inspection,number_of_rejections_by_acceptance,created_datetime,first_annotation_user_id,first_annotation_username,first_annotation_worktime_hour,first_annotation_started_datetime,first_inspection_user_id,first_inspection_username,first_inspection_worktime_hour,first_inspection_started_datetime,first_acceptance_user_id,first_acceptance_username,first_acceptance_worktime_hour,first_acceptance_reached_datetime,first_acceptance_started_datetime,first_acceptance_completed_datetime,worktime_hour,annotation_worktime_hour,inspection_worktime_hour,acceptance_worktime_hour,input_data_count,annotation_count,inspection_comment_count,inspection_comment_count_in_inspection_phase,inspection_comment_count_in_acceptance_phase,inspection_is_skipped,acceptance_is_skipped +prj1,task1,acceptance,1,complete,0,0,2023-12-27T21:53:53.72+09:00,bob,bob,0.185208888888889,2024-01-09T11:27:00.015+09:00,,,,,alice,alice,0.547898611111111,2024-01-08T13:03:11.715+09:00,2024-01-09T13:03:11.715+09:00,2024-01-11T13:04:01.134+09:00,0.7331075,0.185208888888889,0,0.547898611111111,10,20,0,0,0,False,False +prj1,task2,acceptance,1,complete,0,1,2023-12-27T21:54:09.075+09:00,bob,bob,0.214761944444444,2024-01-09T11:43:19.68+09:00,,,,,alice,alice,0.267357222222222,2024-01-09T15:10:43.647+09:00,2024-01-10T15:10:43.647+09:00,2024-01-11T14:23:30.968+09:00,0.538455555555556,0.220598611111111,0,0.317856944444444,10,20,1,0,1,False,False +prj1,task3,acceptance,1,complete,0,1,2023-12-27T21:54:24.099+09:00,bob,bob,0.195141111111111,2024-01-09T11:56:20.118+09:00,,,,,chris,chris,0.573847777777778,2024-01-08T15:23:53.291+09:00,2024-01-09T15:23:53.291+09:00,2024-01-16T11:14:02.961+09:00,1.3610325,0.324384722222222,0,1.03664777777778,10,20,2,0,2,False,False diff --git a/tests/data/stat_visualization/merge_visualization_dir/visualization1/project_info.json b/tests/data/stat_visualization/merge_visualization_dir/visualization1/project_info.json index 5633a5b6..65c20f00 100644 --- a/tests/data/stat_visualization/merge_visualization_dir/visualization1/project_info.json +++ b/tests/data/stat_visualization/merge_visualization_dir/visualization1/project_info.json @@ -3,6 +3,7 @@ "project_title": "PRJECT1", "input_data_type": "image", "measurement_datetime": "2024-02-17T01:22:54.025+09:00", + "task_completion_criteria": "acceptance_completed", "query": { "task_query": null, "task_ids": null, diff --git "a/tests/data/stat_visualization/merge_visualization_dir/visualization1/\343\202\277\343\202\271\343\202\257list.csv" "b/tests/data/stat_visualization/merge_visualization_dir/visualization1/\343\202\277\343\202\271\343\202\257list.csv" index 606db397..0a6ef3e4 100644 --- "a/tests/data/stat_visualization/merge_visualization_dir/visualization1/\343\202\277\343\202\271\343\202\257list.csv" +++ "b/tests/data/stat_visualization/merge_visualization_dir/visualization1/\343\202\277\343\202\271\343\202\257list.csv" @@ -1,4 +1,4 @@ -project_id,task_id,phase,phase_stage,status,number_of_rejections_by_inspection,number_of_rejections_by_acceptance,created_datetime,first_annotation_user_id,first_annotation_username,first_annotation_worktime_hour,first_annotation_started_datetime,first_inspection_user_id,first_inspection_username,first_inspection_worktime_hour,first_inspection_started_datetime,first_acceptance_user_id,first_acceptance_username,first_acceptance_worktime_hour,first_acceptance_started_datetime,first_acceptance_completed_datetime,worktime_hour,annotation_worktime_hour,inspection_worktime_hour,acceptance_worktime_hour,input_data_count,annotation_count,inspection_comment_count,inspection_comment_count_in_inspection_phase,inspection_comment_count_in_acceptance_phase,inspection_is_skipped,acceptance_is_skipped -prj1,task1,acceptance,1,complete,0,0,2023-12-27T21:53:53.72+09:00,bob,bob,0.185208888888889,2024-01-09T11:27:00.015+09:00,,,,,alice,alice,0.547898611111111,2024-01-09T13:03:11.715+09:00,2024-01-11T13:04:01.134+09:00,0.7331075,0.185208888888889,0,0.547898611111111,10,20,0,0,0,False,False -prj1,task2,acceptance,1,complete,0,1,2023-12-27T21:54:09.075+09:00,bob,bob,0.214761944444444,2024-01-09T11:43:19.68+09:00,,,,,alice,alice,0.267357222222222,2024-01-10T15:10:43.647+09:00,2024-01-11T14:23:30.968+09:00,0.538455555555556,0.220598611111111,0,0.317856944444444,10,20,1,0,1,False,False -prj1,task3,acceptance,1,complete,0,1,2023-12-27T21:54:24.099+09:00,bob,bob,0.195141111111111,2024-01-09T11:56:20.118+09:00,,,,,chris,chris,0.573847777777778,2024-01-09T15:23:53.291+09:00,2024-01-16T11:14:02.961+09:00,1.3610325,0.324384722222222,0,1.03664777777778,10,20,2,0,2,False,False +project_id,task_id,phase,phase_stage,status,number_of_rejections_by_inspection,number_of_rejections_by_acceptance,created_datetime,first_annotation_user_id,first_annotation_username,first_annotation_worktime_hour,first_annotation_started_datetime,first_inspection_user_id,first_inspection_username,first_inspection_worktime_hour,first_inspection_started_datetime,first_acceptance_user_id,first_acceptance_username,first_acceptance_worktime_hour,first_acceptance_reached_datetime,first_acceptance_started_datetime,first_acceptance_completed_datetime,worktime_hour,annotation_worktime_hour,inspection_worktime_hour,acceptance_worktime_hour,input_data_count,annotation_count,inspection_comment_count,inspection_comment_count_in_inspection_phase,inspection_comment_count_in_acceptance_phase,inspection_is_skipped,acceptance_is_skipped +prj1,task1,acceptance,1,complete,0,0,2023-12-27T21:53:53.72+09:00,bob,bob,0.185208888888889,2024-01-09T11:27:00.015+09:00,,,,,alice,alice,0.547898611111111,2024-01-08T13:03:11.715+09:00,2024-01-09T13:03:11.715+09:00,2024-01-11T13:04:01.134+09:00,0.7331075,0.185208888888889,0,0.547898611111111,10,20,0,0,0,False,False +prj1,task2,acceptance,1,complete,0,1,2023-12-27T21:54:09.075+09:00,bob,bob,0.214761944444444,2024-01-09T11:43:19.68+09:00,,,,,alice,alice,0.267357222222222,2024-01-09T15:10:43.647+09:00,2024-01-10T15:10:43.647+09:00,2024-01-11T14:23:30.968+09:00,0.538455555555556,0.220598611111111,0,0.317856944444444,10,20,1,0,1,False,False +prj1,task3,acceptance,1,complete,0,1,2023-12-27T21:54:24.099+09:00,bob,bob,0.195141111111111,2024-01-09T11:56:20.118+09:00,,,,,chris,chris,0.573847777777778,2024-01-08T15:23:53.291+09:00,2024-01-09T15:23:53.291+09:00,2024-01-16T11:14:02.961+09:00,1.3610325,0.324384722222222,0,1.03664777777778,10,20,2,0,2,False,False diff --git a/tests/data/stat_visualization/summarize_whole_performance_csv/visualization1/project_info.json b/tests/data/stat_visualization/summarize_whole_performance_csv/visualization1/project_info.json index 5633a5b6..65c20f00 100644 --- a/tests/data/stat_visualization/summarize_whole_performance_csv/visualization1/project_info.json +++ b/tests/data/stat_visualization/summarize_whole_performance_csv/visualization1/project_info.json @@ -3,6 +3,7 @@ "project_title": "PRJECT1", "input_data_type": "image", "measurement_datetime": "2024-02-17T01:22:54.025+09:00", + "task_completion_criteria": "acceptance_completed", "query": { "task_query": null, "task_ids": null, diff --git a/tests/data/stat_visualization/write_performance_rating_csv/visualization1/project_info.json b/tests/data/stat_visualization/write_performance_rating_csv/visualization1/project_info.json index 5633a5b6..d50fcd34 100644 --- a/tests/data/stat_visualization/write_performance_rating_csv/visualization1/project_info.json +++ b/tests/data/stat_visualization/write_performance_rating_csv/visualization1/project_info.json @@ -3,6 +3,7 @@ "project_title": "PRJECT1", "input_data_type": "image", "measurement_datetime": "2024-02-17T01:22:54.025+09:00", + "task_completion_criteria": "acceptance_completed", "query": { "task_query": null, "task_ids": null, diff --git "a/tests/data/stat_visualization/write_performance_rating_csv/visualization1/\343\203\241\343\203\263\343\203\220\343\201\224\343\201\250\343\201\256\347\224\237\347\224\243\346\200\247\343\201\250\345\223\201\350\263\252.csv" "b/tests/data/stat_visualization/write_performance_rating_csv/visualization1/\343\203\241\343\203\263\343\203\220\343\201\224\343\201\250\343\201\256\347\224\237\347\224\243\346\200\247\343\201\250\345\223\201\350\263\252.csv" index a532e995..d4def0e8 100644 --- "a/tests/data/stat_visualization/write_performance_rating_csv/visualization1/\343\203\241\343\203\263\343\203\220\343\201\224\343\201\250\343\201\256\347\224\237\347\224\243\346\200\247\343\201\250\345\223\201\350\263\252.csv" +++ "b/tests/data/stat_visualization/write_performance_rating_csv/visualization1/\343\203\241\343\203\263\343\203\220\343\201\224\343\201\250\343\201\256\347\224\237\347\224\243\346\200\247\343\201\250\345\223\201\350\263\252.csv" @@ -1,14 +1,14 @@ -account_id,user_id,username,biography,first_working_date,last_working_date,working_days,real_monitored_worktime_hour,real_monitored_worktime_hour,real_monitored_worktime_hour,real_monitored_worktime_hour,monitored_worktime_hour,monitored_worktime_hour,monitored_worktime_hour,monitored_worktime_ratio,monitored_worktime_ratio,task_count,task_count,input_data_count,input_data_count,annotation_count,annotation_count,real_actual_worktime_hour,real_monitored_worktime_hour/real_actual_worktime_hour,actual_worktime_hour,actual_worktime_hour,actual_worktime_hour,monitored_worktime_hour/input_data_count,monitored_worktime_hour/input_data_count,actual_worktime_hour/input_data_count,actual_worktime_hour/input_data_count,monitored_worktime_hour/annotation_count,monitored_worktime_hour/annotation_count,actual_worktime_hour/annotation_count,actual_worktime_hour/annotation_count,pointed_out_inspection_comment_count,pointed_out_inspection_comment_count/input_data_count,pointed_out_inspection_comment_count/annotation_count,rejected_count,rejected_count/task_count,stdev__monitored_worktime_hour/input_data_count,stdev__monitored_worktime_hour/input_data_count,stdev__actual_worktime_hour/input_data_count,stdev__actual_worktime_hour/input_data_count,stdev__monitored_worktime_hour/annotation_count,stdev__monitored_worktime_hour/annotation_count,stdev__actual_worktime_hour/annotation_count,stdev__actual_worktime_hour/annotation_count -,,,,,,,sum,annotation,inspection,acceptance,sum,annotation,acceptance,annotation,acceptance,annotation,acceptance,annotation,acceptance,annotation,acceptance,sum,sum,sum,annotation,acceptance,annotation,acceptance,annotation,acceptance,annotation,acceptance,annotation,acceptance,annotation,annotation,annotation,annotation,annotation,annotation,acceptance,annotation,acceptance,annotation,acceptance,annotation,acceptance -BW,BW,BW,category-KT,2023-11-21,2023-11-22,2,6.851844166666666,6.851844166666666,0.0,0.0,6.851844166666667,6.851844166666667,0.0,1.0,0.0,6.8896269504352485,0.0,106.31642764870466,0.0,704.6874322762493,0.0,7.083333333,0.9673191765161091,7.083333333000001,7.083333333000001,0.0,0.06444765233559979,,0.06662501261239756,,0.009723238776281494,,0.010051737846550973,,17.751501370050605,0.1669685650904852,0.025190603034753314,5.8896269504352485,0.8548542602968038,0.026679475026360432,,0.027580839576083944,,0.003011881696243145,,0.00311363794842848, -CW,CW,CW,category-KT,2023-12-29,2023-12-29,1,0.1918455555555555,0.0,0.0,0.1918455555555555,0.1918455555555554,0.0,0.1918455555555554,0.0,1.0,0.0,0.5081261027073752,0.0,7.950989195100896,0.0,49.951637418952345,0.0,inf,0.0,0.0,0.0,,0.024128514182079824,,0.0,,0.0038406259627991003,,0.0,0.0,,,0.0,,,0.006901641498016899,,0.0,,0.0010296655042690527,,0.0 -DB,DB,DB,category-AH,2023-10-26,2023-11-22,11,40.81871361111111,19.350416666666668,0.0,21.46829694444444,40.81871361111111,19.350416666666668,21.468296944444443,0.4740574838056475,0.5259425161943526,24.37134758126235,75.50248589269926,381.31605181319634,1165.1062617307773,2933.576654251046,7997.957713291435,47.0,0.8684832683215129,47.0,22.28070173886543,24.719298261134572,0.050746399409763845,0.01842604202689038,0.05843106166897104,0.021216346588347916,0.0065961857988697786,0.002684222362012152,0.007595063761698017,0.003090701294913665,20.144676943152188,0.05282934418145319,0.006866933889032876,14.180195040232665,0.581838775757109,0.0205619883671736,0.010859332868754762,0.023675744965027397,0.012503790533284785,0.0017076237220000545,0.0011590161490904949,0.001966213724877301,0.001334529047785209 -EM,EM,EM,category-KT,2023-10-25,2024-01-11,9,14.509523055555555,11.46961361111111,0.0,3.039909444444444,14.509523055555555,11.46961361111111,3.0399094444444437,0.7904886719704758,0.20951132802952419,10.0,12.768327488075311,153.0,202.03695764154702,923.0,1640.040348797696,15.000000001,0.9673015369725502,15.000000001,11.857330080347625,3.142669920652374,0.07496479484386347,0.015046303804662492,0.07749888941403676,0.01555492597660317,0.012426450282893945,0.0018535577168409202,0.01284651146299851,0.0019162150022444552,30.0,0.19607843137254902,0.032502708559046585,12.0,1.2,0.028652605322638077,0.008824855452095989,0.029621172124169974,0.009123169058240026,0.0035644133299973977,0.0010819754887946894,0.0036849040281205997,0.001118550366601344 -ML,ML,ML,category-MK,2023-10-27,2024-01-09,9,15.325856111111111,15.325856111111111,0.0,0.0,15.325856111111111,15.325856111111111,0.0,1.0,0.0,9.0,0.0,140.0,0.0,1178.0,0.0,15.399999999,0.9951854618250842,15.399999999,15.399999999,0.0,0.1094704007936508,,0.10999999999285714,,0.013010064610450858,,0.013073005092529712,,39.0,0.2785714285714286,0.03310696095076401,12.0,1.3333333333333333,0.05252036437899548,,0.05277444897826146,,0.0016837689578328727,,0.001691914745966029, -ND,ND,ND,category-KT,2023-10-26,2023-12-31,7,4.471973055555556,4.471973055555556,0.0,0.0,4.471973055555556,4.471973055555556,0.0,1.0,0.0,6.0881462418786745,0.0,95.3521360018727,0.0,510.08979562286163,0.0,7.75,0.5770287813620072,7.75,7.75,0.0,0.0468995582381891,,0.08127767583358375,,0.008767031008912672,,0.015193403331146063,,9.20623485744993,0.09654985450214898,0.018048263141999067,5.0881462418786745,0.8357463897431904,0.018154105632067503,,0.03146135204766894,,0.0012317972708939186,,0.0021347241431985573, -NQ,NQ,NQ,category-MK,2023-11-16,2024-01-09,7,8.284593888888889,8.284593888888889,0.0,0.0,8.284593888888889,8.284593888888889,0.0,1.0,0.0,7.075329646405803,0.0,109.15792130391111,0.0,681.6541185465711,0.0,8.866666667,0.9343526942004629,8.866666667,8.866666667,0.0,0.07589548967155033,,0.08122788123011197,,0.012153662192423002,,0.013007574407245693,,23.0753296464058,0.21139400027745872,0.03385196248151074,8.075329646405802,1.1413361708889407,0.03639715076641981,,0.0389544023283042,,0.002675968505040457,,0.0028639811514968834, -QE,QE,QE,category-KT,2023-10-26,2024-01-10,10,19.636556666666667,19.636556666666667,0.0,0.0,19.636556666666667,19.636556666666667,0.0,1.0,0.0,13.069062790192323,0.0,204.03594185288483,0.0,1534.3594185288484,0.0,20.383333334,0.963363368733823,20.383333334,20.383333334,0.0,0.09624067450246158,,0.09990069959682352,,0.012797885834007717,,0.013284588400769647,,11.207188370576967,0.054927520459398464,0.00730414806025206,7.069062790192322,0.5409005147253022,0.02715101838851306,,0.02818356942946507,,0.006019410129269445,,0.006248327811323088, -RQ,RQ,RQ,category-MK,2023-11-17,2024-01-03,6,11.732706666666667,11.732706666666667,0.0,0.0,11.732706666666667,11.732706666666667,0.0,1.0,0.0,11.0,0.0,171.0,0.0,1272.0,0.0,12.1,0.9696451790633609,12.1,12.1,0.0,0.06861231968810916,,0.07076023391812865,,0.009223825995807127,,0.009512578616352201,,43.0,0.25146198830409355,0.03380503144654088,11.0,1.0,0.020828611429587012,,0.021480652798899727,,0.0018650764116650278,,0.001923462779928033, -SK,SK,SK,category-KT,2023-10-27,2024-01-13,11,5.926304444444445,0.6270641666666666,0.0,5.299240277777778,5.926304444444443,0.6270641666666662,5.299240277777777,0.10581031949084246,0.8941896805091576,1.5064867898256038,19.88416237028506,22.821521379430365,309.4089089788781,79.63258077442372,2141.0393928747303,7.416666666999999,0.7990522846082824,7.416666666999998,0.7847598695923514,6.631906797407646,0.027476878348340773,0.017126980264616527,0.034386834100362654,0.02143411713416557,0.00787446746756782,0.0024750783640008576,0.0098547587176077,0.0030975174111594083,0.6150688123645079,0.026951262456975614,0.007723833717091521,0.6976393308552876,0.46309024119358444,0.02150022289202632,0.015643948555234398,0.026907154020048042,0.019578128811562685,0.0014024817882802457,0.0012862304348123643,0.0017551815010050074,0.00160969495937667 -TR,TR,TR,category-KT,2023-10-26,2023-11-22,9,19.23942138888889,19.23942138888889,0.0,0.0,19.23942138888889,19.23942138888889,0.0,1.0,0.0,9.0,0.0,139.0,0.0,1098.0,0.0,19.683333333,0.9774473186730587,19.683333333,19.683333333,0.0,0.13841310351718625,,0.14160671462589927,,0.0175222417020846,,0.017926533090163933,,49.0,0.35251798561151076,0.044626593806921674,11.0,1.2222222222222223,0.08909981711510603,,0.09115562078175651,,0.004185852612146469,,0.0042824329579511326, -XT,XT,XT,category-MK,2023-10-26,2024-01-15,11,18.969883333333332,18.536526388888888,0.0,0.4333569444444443,18.969883333333332,18.536526388888888,0.43335694444444434,0.9771555292760835,0.022844470723916474,12.0,1.3368981462329987,183.0,20.496882453696607,1077.0,163.01090761718706,20.683333334,0.9171579371178997,20.683333334,20.21083353117843,0.4724998028215687,0.10129249392835457,0.021142578410322518,0.11044171328512803,0.023052276554201223,0.01721125941401011,0.0026584536628808594,0.018765862145940976,0.002898577829719112,39.0,0.21311475409836064,0.036211699164345405,10.0,0.8333333333333334,0.03824212262251798,0.006231775179058627,0.04169633285046956,0.006794658724364872,0.0024773018750205403,0.00026103198405534356,0.002701063551611706,0.00028460963318446223 +account_id,user_id,username,biography,first_working_date,last_working_date,working_days,first_working_date,first_working_date,first_working_date,last_working_date,last_working_date,last_working_date,working_days,working_days,working_days,real_monitored_worktime_hour,real_monitored_worktime_hour,real_monitored_worktime_hour,real_monitored_worktime_hour,monitored_worktime_hour,monitored_worktime_hour,monitored_worktime_hour,monitored_worktime_ratio,monitored_worktime_ratio,task_count,task_count,input_data_count,input_data_count,annotation_count,annotation_count,real_actual_worktime_hour,real_monitored_worktime_hour/real_actual_worktime_hour,actual_worktime_hour,actual_worktime_hour,actual_worktime_hour,monitored_worktime_hour/input_data_count,monitored_worktime_hour/input_data_count,actual_worktime_hour/input_data_count,actual_worktime_hour/input_data_count,monitored_worktime_hour/annotation_count,monitored_worktime_hour/annotation_count,actual_worktime_hour/annotation_count,actual_worktime_hour/annotation_count,pointed_out_inspection_comment_count,pointed_out_inspection_comment_count/input_data_count,pointed_out_inspection_comment_count/annotation_count,rejected_count,rejected_count/task_count,stdev__monitored_worktime_hour/input_data_count,stdev__monitored_worktime_hour/input_data_count,stdev__actual_worktime_hour/input_data_count,stdev__actual_worktime_hour/input_data_count,stdev__monitored_worktime_hour/annotation_count,stdev__monitored_worktime_hour/annotation_count,stdev__actual_worktime_hour/annotation_count,stdev__actual_worktime_hour/annotation_count +,,,,,,,annotation,inspection,acceptance,annotation,inspection,acceptance,annotation,inspection,acceptance,sum,annotation,inspection,acceptance,sum,annotation,acceptance,annotation,acceptance,annotation,acceptance,annotation,acceptance,annotation,acceptance,sum,sum,sum,annotation,acceptance,annotation,acceptance,annotation,acceptance,annotation,acceptance,annotation,acceptance,annotation,annotation,annotation,annotation,annotation,annotation,acceptance,annotation,acceptance,annotation,acceptance,annotation,acceptance +BW,BW,BW,category-KT,2023-11-21,2023-11-22,2,,,,,,,,,,6.85184416666667,6.85184416666667,0,0,6.85184416666667,6.85184416666667,0,1,0,6.88962695043525,0,106.316427648705,0,704.687432276249,0,7.083333333,0.967319176516109,7.083333333,7.083333333,0,0.0644476523355998,,0.0666250126123976,,0.00972323877628149,,0.010051737846551,,17.7515013700506,0.166968565090485,0.0251906030347533,5.88962695043525,0.854854260296804,0.0266794750263604,,0.0275808395760839,,0.00301188169624315,,0.00311363794842848, +CW,CW,CW,category-KT,2023-12-29,2023-12-29,1,,,,,,,,,,0.191845555555556,0,0,0.191845555555556,0.191845555555555,0,0.191845555555555,0,1,0,0.508126102707375,0,7.9509891951009,0,49.9516374189523,0,inf,0,0,0,,0.0241285141820798,,0,,0.0038406259627991,,0,0,,,0,,,0.0069016414980169,,0,,0.00102966550426905,,0 +DB,DB,DB,category-AH,2023-10-26,2023-11-22,11,,,,,,,,,,40.8187136111111,19.3504166666667,0,21.4682969444444,40.8187136111111,19.3504166666667,21.4682969444444,0.474057483805648,0.525942516194353,24.3713475812624,75.5024858926993,381.316051813196,1165.10626173078,2933.57665425105,7997.95771329144,47,0.868483268321513,47,22.2807017388654,24.7192982611346,0.0507463994097638,0.0184260420268904,0.058431061668971,0.0212163465883479,0.00659618579886978,0.00268422236201215,0.00759506376169802,0.00309070129491367,20.1446769431522,0.0528293441814532,0.00686693388903288,14.1801950402327,0.581838775757109,0.0205619883671736,0.0108593328687548,0.0236757449650274,0.0125037905332848,0.00170762372200005,0.00115901614909049,0.0019662137248773,0.00133452904778521 +EM,EM,EM,category-KT,2023-10-25,2024-01-11,9,,,,,,,,,,14.5095230555556,11.4696136111111,0,3.03990944444444,14.5095230555556,11.4696136111111,3.03990944444444,0.790488671970476,0.209511328029524,10,12.7683274880753,153,202.036957641547,923,1640.0403487977,15.000000001,0.96730153697255,15.000000001,11.8573300803476,3.14266992065237,0.0749647948438635,0.0150463038046625,0.0774988894140368,0.0155549259766032,0.0124264502828939,0.00185355771684092,0.0128465114629985,0.00191621500224446,30,0.196078431372549,0.0325027085590466,12,1.2,0.0286526053226381,0.00882485545209599,0.02962117212417,0.00912316905824003,0.0035644133299974,0.00108197548879469,0.0036849040281206,0.00111855036660134 +ML,ML,ML,category-MK,2023-10-27,2024-01-09,9,,,,,,,,,,15.3258561111111,15.3258561111111,0,0,15.3258561111111,15.3258561111111,0,1,0,9,0,140,0,1178,0,15.399999999,0.995185461825084,15.399999999,15.399999999,0,0.109470400793651,,0.109999999992857,,0.0130100646104509,,0.0130730050925297,,39,0.278571428571429,0.033106960950764,12,1.33333333333333,0.0525203643789955,,0.0527744489782615,,0.00168376895783287,,0.00169191474596603, +ND,ND,ND,category-KT,2023-10-26,2023-12-31,7,,,,,,,,,,4.47197305555556,4.47197305555556,0,0,4.47197305555556,4.47197305555556,0,1,0,6.08814624187867,0,95.3521360018727,0,510.089795622862,0,7.75,0.577028781362007,7.75,7.75,0,0.0468995582381891,,0.0812776758335838,,0.00876703100891267,,0.0151934033311461,,9.20623485744993,0.096549854502149,0.0180482631419991,5.08814624187867,0.83574638974319,0.0181541056320675,,0.0314613520476689,,0.00123179727089392,,0.00213472414319856, +NQ,NQ,NQ,category-MK,2023-11-16,2024-01-09,7,,,,,,,,,,8.28459388888889,8.28459388888889,0,0,8.28459388888889,8.28459388888889,0,1,0,7.0753296464058,0,109.157921303911,0,681.654118546571,0,8.866666667,0.934352694200463,8.866666667,8.866666667,0,0.0758954896715503,,0.081227881230112,,0.012153662192423,,0.0130075744072457,,23.0753296464058,0.211394000277459,0.0338519624815107,8.0753296464058,1.14133617088894,0.0363971507664198,,0.0389544023283042,,0.00267596850504046,,0.00286398115149688, +QE,QE,QE,category-KT,2023-10-26,2024-01-10,10,,,,,,,,,,19.6365566666667,19.6365566666667,0,0,19.6365566666667,19.6365566666667,0,1,0,13.0690627901923,0,204.035941852885,0,1534.35941852885,0,20.383333334,0.963363368733823,20.383333334,20.383333334,0,0.0962406745024616,,0.0999006995968235,,0.0127978858340077,,0.0132845884007696,,11.207188370577,0.0549275204593985,0.00730414806025206,7.06906279019232,0.540900514725302,0.0271510183885131,,0.0281835694294651,,0.00601941012926945,,0.00624832781132309, +RQ,RQ,RQ,category-MK,2023-11-17,2024-01-03,6,,,,,,,,,,11.7327066666667,11.7327066666667,0,0,11.7327066666667,11.7327066666667,0,1,0,11,0,171,0,1272,0,12.1,0.969645179063361,12.1,12.1,0,0.0686123196881092,,0.0707602339181287,,0.00922382599580713,,0.0095125786163522,,43,0.251461988304094,0.0338050314465409,11,1,0.020828611429587,,0.0214806527988997,,0.00186507641166503,,0.00192346277992803, +SK,SK,SK,category-KT,2023-10-27,2024-01-13,11,,,,,,,,,,5.92630444444445,0.627064166666667,0,5.29924027777778,5.92630444444444,0.627064166666666,5.29924027777778,0.105810319490842,0.894189680509158,1.5064867898256,19.8841623702851,22.8215213794304,309.408908978878,79.6325807744237,2141.03939287473,7.416666667,0.799052284608282,7.416666667,0.784759869592351,6.63190679740765,0.0274768783483408,0.0171269802646165,0.0343868341003627,0.0214341171341656,0.00787446746756782,0.00247507836400086,0.0098547587176077,0.00309751741115941,0.615068812364508,0.0269512624569756,0.00772383371709152,0.697639330855288,0.463090241193584,0.0215002228920263,0.0156439485552344,0.026907154020048,0.0195781288115627,0.00140248178828025,0.00128623043481236,0.00175518150100501,0.00160969495937667 +TR,TR,TR,category-KT,2023-10-26,2023-11-22,9,,,,,,,,,,19.2394213888889,19.2394213888889,0,0,19.2394213888889,19.2394213888889,0,1,0,9,0,139,0,1098,0,19.683333333,0.977447318673059,19.683333333,19.683333333,0,0.138413103517186,,0.141606714625899,,0.0175222417020846,,0.0179265330901639,,49,0.352517985611511,0.0446265938069217,11,1.22222222222222,0.089099817115106,,0.0911556207817565,,0.00418585261214647,,0.00428243295795113, +XT,XT,XT,category-MK,2023-10-26,2024-01-15,11,,,,,,,,,,18.9698833333333,18.5365263888889,0,0.433356944444444,18.9698833333333,18.5365263888889,0.433356944444444,0.977155529276084,0.0228444707239165,12,1.336898146233,183,20.4968824536966,1077,163.010907617187,20.683333334,0.9171579371179,20.683333334,20.2108335311784,0.472499802821569,0.101292493928355,0.0211425784103225,0.110441713285128,0.0230522765542012,0.0172112594140101,0.00265845366288086,0.018765862145941,0.00289857782971911,39,0.213114754098361,0.0362116991643454,10,0.833333333333333,0.038242122622518,0.00623177517905863,0.0416963328504696,0.00679465872436487,0.00247730187502054,0.000261031984055344,0.00270106355161171,0.000284609633184462 diff --git a/tests/data/statistics/task.csv b/tests/data/statistics/task.csv index c385a556..e11ba999 100644 --- a/tests/data/statistics/task.csv +++ b/tests/data/statistics/task.csv @@ -1,6 +1,6 @@ -project_id,task_id,phase,phase_stage,status,number_of_rejections,number_of_rejections_by_inspection,number_of_rejections_by_acceptance,created_datetime,started_datetime,updated_datetime,first_acceptance_completed_datetime,sampling,first_annotation_user_id,first_annotation_username,first_annotation_worktime_hour,first_annotation_started_datetime,first_inspection_user_id,first_inspection_username,first_inspection_worktime_hour,first_inspection_started_datetime,first_acceptance_user_id,first_acceptance_username,first_acceptance_worktime_hour,first_acceptance_started_datetime,worktime_hour,annotation_worktime_hour,inspection_worktime_hour,acceptance_worktime_hour,input_data_count,annotation_count,inspection_comment_count,inspection_comment_count_in_inspection_phase,inspection_comment_count_in_acceptance_phase,inspection_is_skipped,acceptance_is_skipped,diff_days_to_first_inspection_started,diff_days_to_first_acceptance_started,diff_days_to_first_acceptance_completed,custom_production_volume1,custom_production_volume2 -12345678-abcd-1234-abcd-1234abcd5678,task1,acceptance,1,complete,1,0,1,2019-11-01T00:00:00.000+09:00,2019-11-25T04:18:05.8+09:00,2019-11-25T04:21:32.721+09:00,2019-11-25T04:21:32.56+09:00,,user1,user1,0.458071666666667,2019-11-21T22:35:32.238+09:00,user1,user1,0,2019-11-22T20:26:36.833+09:00,user1,user1,0.209477777777778,2019-11-22T20:26:36.833+09:00,0.787161388888889,0.520250277777778,1,0.266911111111111,10,41,9,0,9,False,True,,0.910469849537037,3.24028150462963,400,50 -12345678-abcd-1234-abcd-1234abcd5678,task2,acceptance,1,complete,2,0,2,2019-11-01T00:00:00.000+09:00,2019-11-15T13:40:32.074+09:00,2019-11-15T13:43:35.02+09:00,2019-11-15T13:43:34.974+09:00,,user1,user1,0.801513055555556,2019-11-13T14:46:41.236+09:00,user2,user2,0,2019-11-15T10:12:26.528+09:00,user2,user2,0.350685555555556,2019-11-15T10:12:26.528+09:00,1.70834722222222,1.25867722222222,2,0.44967,10,65,7,0,7,True,False,,1.80955199074074,1.95617752314815,600,70 -12345678-abcd-1234-abcd-1234abcd5678,task10,acceptance,1,complete,0,0,0,2019-11-01T00:00:00.000+09:00,2019-11-14T09:15:50.754+09:00,2019-11-14T09:18:49.676+09:00,2019-11-14T09:18:49.616+09:00,,user4,user4,0.217835277777778,2019-11-11T13:26:27.456+09:00,user4,user4,0,2019-11-14T09:15:50.754+09:00,user4,user4,0.049683888888889,2019-11-14T09:15:50.754+09:00,0.267519166666667,0.217835277777778,3,0.049683888888889,10,30,0,0,0,False,False,,2.82596409722222,2.82803425925926,300,20 -12345678-abcd-1234-abcd-1234abcd5678,task4,acceptance,1,not_started,0,0,0,2019-11-01T00:00:00.000+09:00,2019-11-25T22:05:23.501+09:00,2019-11-25T22:09:02.157+09:00,,,user4,user4,0.060726388888889,2019-11-25T22:05:23.501+09:00,,,0,,,,0,,0.060726388888889,0.060726388888889,0,0,10,10,0,0,0,False,False,,,,100,5 -12345678-abcd-1234-abcd-1234abcd5678,task5,annotation,1,not_started,0,0,0,2019-11-01T00:00:00.000+09:00,,2019-11-08T22:54:26.981+09:00,,,user5,user5,0.029444166666667,2019-11-26T09:27:22.776+09:00,,,0,,,,0,,0.029444166666667,0.029444166666667,0,0,10,0,0,0,0,False,False,,,,0,0 +project_id,task_id,phase,phase_stage,status,number_of_rejections,number_of_rejections_by_inspection,number_of_rejections_by_acceptance,created_datetime,started_datetime,updated_datetime,first_acceptance_completed_datetime,sampling,first_annotation_user_id,first_annotation_username,first_annotation_worktime_hour,first_annotation_started_datetime,first_inspection_user_id,first_inspection_username,first_inspection_worktime_hour,first_inspection_started_datetime,first_acceptance_reached_datetime,first_acceptance_user_id,first_acceptance_username,first_acceptance_worktime_hour,first_acceptance_started_datetime,worktime_hour,annotation_worktime_hour,inspection_worktime_hour,acceptance_worktime_hour,input_data_count,annotation_count,inspection_comment_count,inspection_comment_count_in_inspection_phase,inspection_comment_count_in_acceptance_phase,inspection_is_skipped,acceptance_is_skipped,diff_days_to_first_inspection_started,diff_days_to_first_acceptance_started,diff_days_to_first_acceptance_completed,custom_production_volume1,custom_production_volume2 +12345678-abcd-1234-abcd-1234abcd5678,task1,acceptance,1,complete,1,0,1,2019-11-01T00:00:00.000+09:00,2019-11-25T04:18:05.8+09:00,2019-11-25T04:21:32.721+09:00,2019-11-25T04:21:32.56+09:00,,user1,user1,0.458071666666667,2019-11-21T22:35:32.238+09:00,user1,user1,0,2019-11-22T20:26:36.833+09:00,2019-11-20T20:26:36.833+09:00,user1,user1,0.209477777777778,2019-11-22T20:26:36.833+09:00,0.787161388888889,0.520250277777778,1,0.266911111111111,10,41,9,0,9,False,True,,0.910469849537037,3.24028150462963,400,50 +12345678-abcd-1234-abcd-1234abcd5678,task2,acceptance,1,complete,2,0,2,2019-11-01T00:00:00.000+09:00,2019-11-15T13:40:32.074+09:00,2019-11-15T13:43:35.02+09:00,2019-11-15T13:43:34.974+09:00,,user1,user1,0.801513055555556,2019-11-13T14:46:41.236+09:00,user2,user2,0,2019-11-15T10:12:26.528+09:00,2019-11-14T10:12:26.528+09:00,user2,user2,0.350685555555556,2019-11-15T10:12:26.528+09:00,1.70834722222222,1.25867722222222,2,0.44967,10,65,7,0,7,True,False,,1.80955199074074,1.95617752314815,600,70 +12345678-abcd-1234-abcd-1234abcd5678,task10,acceptance,1,complete,0,0,0,2019-11-01T00:00:00.000+09:00,2019-11-14T09:15:50.754+09:00,2019-11-14T09:18:49.676+09:00,2019-11-14T09:18:49.616+09:00,,user4,user4,0.217835277777778,2019-11-11T13:26:27.456+09:00,user4,user4,0,2019-11-14T09:15:50.754+09:00,2019-11-13T09:15:50.754+09:00,user4,user4,0.049683888888889,2019-11-14T09:15:50.754+09:00,0.267519166666667,0.217835277777778,3,0.049683888888889,10,30,0,0,0,False,False,,2.82596409722222,2.82803425925926,300,20 +12345678-abcd-1234-abcd-1234abcd5678,task4,acceptance,1,not_started,0,0,0,2019-11-01T00:00:00.000+09:00,2019-11-25T22:05:23.501+09:00,2019-11-25T22:09:02.157+09:00,,,user4,user4,0.060726388888889,2019-11-25T22:05:23.501+09:00,,,0,,,,,0,,0.060726388888889,0.060726388888889,0,0,10,10,0,0,0,False,False,,,,100,5 +12345678-abcd-1234-abcd-1234abcd5678,task5,annotation,1,not_started,0,0,0,2019-11-01T00:00:00.000+09:00,,2019-11-08T22:54:26.981+09:00,,,user5,user5,0.029444166666667,2019-11-26T09:27:22.776+09:00,,,0,,,,,0,,0.029444166666667,0.029444166666667,0,0,10,0,0,0,0,False,False,,,,0,0 diff --git a/tests/data/statistics/visualization-dir1/project_info.json b/tests/data/statistics/visualization-dir1/project_info.json index c96a2dce..54cde007 100644 --- a/tests/data/statistics/visualization-dir1/project_info.json +++ b/tests/data/statistics/visualization-dir1/project_info.json @@ -3,6 +3,7 @@ "project_title": "test-project", "input_data_type": "image", "measurement_datetime": "2022-06-14T15:56:10.634+09:00", + "task_completion_criteria": "acceptance_reached", "query": { "task_query": null, "task_ids": null, diff --git a/tests/stat_visualization/test_mask_visualization_dir.py b/tests/stat_visualization/test_mask_visualization_dir.py index c953e420..32d45871 100644 --- a/tests/stat_visualization/test_mask_visualization_dir.py +++ b/tests/stat_visualization/test_mask_visualization_dir.py @@ -1,7 +1,7 @@ from pathlib import Path from annofabcli.stat_visualization.mask_visualization_dir import mask_visualization_dir -from annofabcli.statistics.visualization.project_dir import ProjectDir +from annofabcli.statistics.visualization.project_dir import ProjectDir, TaskCompletionCriteria output_dir = Path("./tests/out/stat_visualization/mask_visualization_dir") data_dir = Path("./tests/data/stat_visualization/mask_visualization_dir") @@ -10,7 +10,7 @@ def test__mask_visualization_dir__minimal(): mask_visualization_dir( - project_dir=ProjectDir(data_dir / "visualization1"), - output_project_dir=ProjectDir(output_dir / "masked-visualization"), + project_dir=ProjectDir(data_dir / "visualization1", TaskCompletionCriteria.ACCEPTANCE_COMPLETED), + output_project_dir=ProjectDir(output_dir / "masked-visualization", TaskCompletionCriteria.ACCEPTANCE_COMPLETED), minimal_output=True, ) diff --git a/tests/statistics/visualization/dataframe/test_project_performance.py b/tests/statistics/visualization/dataframe/test_project_performance.py index 8fec16b8..c093a7d2 100644 --- a/tests/statistics/visualization/dataframe/test_project_performance.py +++ b/tests/statistics/visualization/dataframe/test_project_performance.py @@ -6,7 +6,7 @@ ProjectPerformance, ProjectWorktimePerMonth, ) -from annofabcli.statistics.visualization.model import WorktimeColumn +from annofabcli.statistics.visualization.model import TaskCompletionCriteria, WorktimeColumn from annofabcli.statistics.visualization.project_dir import ProjectDir output_dir = Path("./tests/out/statistics/visualization/dataframe/project_performance") @@ -16,7 +16,7 @@ class TestProjectPerformance: def test__from_project_dirs__and__to_csv(self): - actual = ProjectPerformance.from_project_dirs([ProjectDir(data_dir / "visualization-dir1")]) + actual = ProjectPerformance.from_project_dirs([ProjectDir(data_dir / "visualization-dir1", TaskCompletionCriteria.ACCEPTANCE_COMPLETED)]) df = actual.df assert len(df) == 1 row = df.iloc[0] @@ -30,7 +30,7 @@ def test__from_project_dirs__and__to_csv(self): actual.to_csv(output_dir / "test__from_project_dirs__and__to_csv.csv") def test__from_project_dirs__空ディレクトから生成する(self): - actual = ProjectPerformance.from_project_dirs([ProjectDir(data_dir / "empty")]) + actual = ProjectPerformance.from_project_dirs([ProjectDir(data_dir / "empty", TaskCompletionCriteria.ACCEPTANCE_COMPLETED)]) df = actual.df assert len(df) == 1 row = df.iloc[0] @@ -46,7 +46,8 @@ def test__from_project_dirs__空ディレクトから生成する(self): class TestProjectWorktimePerMonth: def test__from_project_dirs__and_to_csv(self): actual_worktime = ProjectWorktimePerMonth.from_project_dirs( - [ProjectDir(data_dir / "visualization-dir1")], worktime_column=WorktimeColumn.ACTUAL_WORKTIME_HOUR + [ProjectDir(data_dir / "visualization-dir1", TaskCompletionCriteria.ACCEPTANCE_COMPLETED)], + worktime_column=WorktimeColumn.ACTUAL_WORKTIME_HOUR, ) df = actual_worktime.df assert len(df) == 1 @@ -59,7 +60,7 @@ def test__from_project_dirs__and_to_csv(self): def test__from_project_dirs__空ディレクトリから生成(self): actual_worktime = ProjectWorktimePerMonth.from_project_dirs( - [ProjectDir(data_dir / "empty")], worktime_column=WorktimeColumn.ACTUAL_WORKTIME_HOUR + [ProjectDir(data_dir / "empty", TaskCompletionCriteria.ACCEPTANCE_COMPLETED)], worktime_column=WorktimeColumn.ACTUAL_WORKTIME_HOUR ) df = actual_worktime.df assert len(df) == 1 diff --git a/tests/statistics/visualization/dataframe/test_whole_productivity_per_date.py b/tests/statistics/visualization/dataframe/test_whole_productivity_per_date.py index 51c7de5b..fced0c49 100644 --- a/tests/statistics/visualization/dataframe/test_whole_productivity_per_date.py +++ b/tests/statistics/visualization/dataframe/test_whole_productivity_per_date.py @@ -6,7 +6,7 @@ WholeProductivityPerFirstAnnotationStartedDate, ) from annofabcli.statistics.visualization.dataframe.worktime_per_date import WorktimePerDate -from annofabcli.statistics.visualization.model import ProductionVolumeColumn +from annofabcli.statistics.visualization.model import ProductionVolumeColumn, TaskCompletionCriteria output_dir = Path("./tests/out/statistics/visualization/dataframe/whole_productivity_per_date") data_dir = Path("./tests/data/statistics") @@ -27,22 +27,40 @@ def setup_class(cls) -> None: ], ) worktime_per_date = WorktimePerDate.from_csv(data_dir / "ユーザ_日付list-作業時間.csv") - cls.main_obj = WholeProductivityPerCompletedDate.from_df_wrapper(task, worktime_per_date) + cls.main_obj = WholeProductivityPerCompletedDate.from_df_wrapper(task, worktime_per_date, TaskCompletionCriteria.ACCEPTANCE_COMPLETED) cls.output_dir = output_dir / "WholeProductivityPerCompletedDate" cls.output_dir.mkdir(exist_ok=True, parents=True) - def test__from_df_wrapper(cls): + def test__from_df_wrapper__task_completion_criteria_is_acceptance_completed(cls): task = Task.from_csv( data_dir / "task.csv", ) worktime_per_date = WorktimePerDate.from_csv(data_dir / "ユーザ_日付list-作業時間.csv") - WholeProductivityPerCompletedDate.from_df_wrapper(task, worktime_per_date) + obj = WholeProductivityPerCompletedDate.from_df_wrapper(task, worktime_per_date, TaskCompletionCriteria.ACCEPTANCE_COMPLETED) + df_actual = obj.df + assert df_actual["task_count"].sum() == 3 + assert df_actual[df_actual["date"] == "2019-11-14"].iloc[0]["task_count"] == 1 + assert df_actual[df_actual["date"] == "2019-11-15"].iloc[0]["task_count"] == 1 + assert df_actual[df_actual["date"] == "2019-11-25"].iloc[0]["task_count"] == 1 + + def test__from_df_wrapper__task_completion_criteria_is_acceptance_reached(cls): + task = Task.from_csv( + data_dir / "task.csv", + ) + worktime_per_date = WorktimePerDate.from_csv(data_dir / "ユーザ_日付list-作業時間.csv") + obj = WholeProductivityPerCompletedDate.from_df_wrapper(task, worktime_per_date, TaskCompletionCriteria.ACCEPTANCE_REACHED) + df_actual = obj.df + + assert df_actual["task_count"].sum() == 3 + assert df_actual[df_actual["date"] == "2019-11-13"].iloc[0]["task_count"] == 1 + assert df_actual[df_actual["date"] == "2019-11-14"].iloc[0]["task_count"] == 1 + assert df_actual[df_actual["date"] == "2019-11-20"].iloc[0]["task_count"] == 1 def test_from_df__df_worktime引数が空でもインスタンスを生成できることを確認する(self): # 完了タスクが1つもない状態で試す task = Task.from_csv(data_dir / "task.csv") - obj = WholeProductivityPerCompletedDate.from_df_wrapper(task, WorktimePerDate.empty()) + obj = WholeProductivityPerCompletedDate.from_df_wrapper(task, WorktimePerDate.empty(), TaskCompletionCriteria.ACCEPTANCE_COMPLETED) df_actual = obj.df # 日毎の完了したタスク数が一致していることの確認 @@ -73,6 +91,22 @@ def setup_class(cls) -> None: cls.output_dir = output_dir / "WholeProductivityPerFirstAnnotationStartedDate" cls.output_dir.mkdir(exist_ok=True, parents=True) + def test__from_task__task_completion_criteria_is_acceptance_completed(self): + task = Task.from_csv( + data_dir / "task.csv", + ) + obj = WholeProductivityPerFirstAnnotationStartedDate.from_task(task, TaskCompletionCriteria.ACCEPTANCE_COMPLETED) + df_actual = obj.df + assert df_actual["task_count"].sum() == 3 + + def test__from_task__task_completion_criteria_is_acceptance_reached(cls): + task = Task.from_csv( + data_dir / "task.csv", + ) + obj = WholeProductivityPerFirstAnnotationStartedDate.from_task(task, TaskCompletionCriteria.ACCEPTANCE_REACHED) + df_actual = obj.df + assert df_actual["task_count"].sum() == 4 + def test__from_task__and__to_csv(self): task = Task.from_csv( data_dir / "task.csv", @@ -81,7 +115,7 @@ def test__from_task__and__to_csv(self): ProductionVolumeColumn("custom_production_volume2", "custom_生産量2"), ], ) - obj = WholeProductivityPerFirstAnnotationStartedDate.from_task(task) + obj = WholeProductivityPerFirstAnnotationStartedDate.from_task(task, TaskCompletionCriteria.ACCEPTANCE_COMPLETED) obj.to_csv(self.output_dir / "test__from_task__and__to_csv.csv") def test__from_task__and__plot(self): @@ -92,5 +126,5 @@ def test__from_task__and__plot(self): ProductionVolumeColumn("custom_production_volume2", "custom_生産量2"), ], ) - obj = WholeProductivityPerFirstAnnotationStartedDate.from_task(task) + obj = WholeProductivityPerFirstAnnotationStartedDate.from_task(task, TaskCompletionCriteria.ACCEPTANCE_COMPLETED) obj.plot(self.output_dir / "test__from_task__and__plot.html") diff --git a/tests/statistics/visualization/test_write_performance_rating_csv.py b/tests/statistics/visualization/test_write_performance_rating_csv.py index d55d360d..7db11152 100644 --- a/tests/statistics/visualization/test_write_performance_rating_csv.py +++ b/tests/statistics/visualization/test_write_performance_rating_csv.py @@ -14,7 +14,7 @@ create_quality_indicator_by_directory, create_threshold_infos_per_project, ) -from annofabcli.statistics.visualization.project_dir import ProjectDir +from annofabcli.statistics.visualization.project_dir import ProjectDir, TaskCompletionCriteria data_dir = Path("tests/data/stat_visualization") @@ -41,7 +41,7 @@ def test__create_quality_indicator_by_directory(): ("biography", ""): ["category-KK", "category-KT", "category-KT", "category-KT"], } ) -project_dir = ProjectDir(data_dir / "visualization-dir") +project_dir = ProjectDir(data_dir / "visualization-dir", TaskCompletionCriteria.ACCEPTANCE_COMPLETED) user_performance = project_dir.read_user_performance()