Skip to content

Commit

Permalink
Merge pull request #145 from kurusugawa-computer/fix/modify-histogram
Browse files Browse the repository at this point in the history
[statitics visualize] ヒストグラムを改善
  • Loading branch information
yuji38kwmt authored Dec 27, 2019
2 parents 486b96e + a95983a commit 107be43
Show file tree
Hide file tree
Showing 79 changed files with 3,275 additions and 1,765 deletions.
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ init:

format:
pipenv run autoflake --in-place --remove-all-unused-imports --ignore-init-module-imports --recursive ${FORMAT_FILES}
pipenv run black ${FORMAT_FILES}
pipenv run isort --verbose --recursive ${FORMAT_FILES}
pipenv run yapf --verbose --in-place --recursive ${FORMAT_FILES}


lint:
pipenv run mypy ${LINT_FILES} --config-file setup.cfg
Expand Down
1 change: 1 addition & 0 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ twine = "*"
autoflake = "*"
flake8 = "*"
docutils = "*"
black = "*"

[packages]

Expand Down
265 changes: 163 additions & 102 deletions Pipfile.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions annofabcli/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# flake8: noqa: F401
from annofabcli.common import enums
from annofabcli.common import typing
from annofabcli.common import exceptions
Expand Down
8 changes: 4 additions & 4 deletions annofabcli/__main__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import argparse
import logging
from typing import Optional, Sequence # pylint: disable=unused-import
from typing import Optional, Sequence

import annofabcli.annotation.subcommand_annotation
import annofabcli.annotation_specs.subcommand_annotation_specs
Expand Down Expand Up @@ -32,10 +32,10 @@ def main(arguments: Optional[Sequence[str]] = None):
"""

parser = argparse.ArgumentParser(description="annofabapiを使ったCLIツール")
parser.add_argument('--version', action='version', version=f'annofabcli {annofabcli.__version__}')
parser.add_argument("--version", action="version", version=f"annofabcli {annofabcli.__version__}")
parser.set_defaults(command_help=parser.print_help)

subparsers = parser.add_subparsers(dest='command_name')
subparsers = parser.add_subparsers(dest="command_name")

annofabcli.annotation.subcommand_annotation.add_parser(subparsers)
annofabcli.annotation_specs.subcommand_annotation_specs.add_parser(subparsers)
Expand All @@ -59,7 +59,7 @@ def main(arguments: Optional[Sequence[str]] = None):
else:
args = parser.parse_args(arguments)

if hasattr(args, 'subcommand_func'):
if hasattr(args, "subcommand_func"):
try:
args.subcommand_func(args)
except Exception as e:
Expand Down
2 changes: 1 addition & 1 deletion annofabcli/__version__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '1.15.9'
__version__ = "1.16.10"
140 changes: 82 additions & 58 deletions annofabcli/annotation/list_annotation_count.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import argparse
import logging
from enum import Enum
from typing import Any, Callable, Dict, List, Optional, Tuple, Union # pylint: disable=unused-import
from typing import Any, Dict, List, Optional

import annofabapi
import more_itertools
Expand All @@ -20,54 +20,62 @@


class GroupBy(Enum):
TASK_ID = 'task_id'
INPUT_DATA_ID = 'input_data_id'
TASK_ID = "task_id"
INPUT_DATA_ID = "input_data_id"


class ListAnnotationCount(AbstractCommandLineInterface):
"""
タスクの一覧を表示する
"""

def __init__(self, service: annofabapi.Resource, facade: AnnofabApiFacade, args: argparse.Namespace):
super().__init__(service, facade, args)
self.visualize = AddProps(self.service, args.project_id)

@staticmethod
def _modify_attribute_of_query(attribute_query: Dict[str, Any],
additional_data_definition: AdditionalDataDefinition) -> Dict[str, Any]:
if 'choice_name_en' in attribute_query:
def _modify_attribute_of_query(
attribute_query: Dict[str, Any], additional_data_definition: AdditionalDataDefinition
) -> Dict[str, Any]:
if "choice_name_en" in attribute_query:
choice_info = more_itertools.first_true(
additional_data_definition['choices'],
pred=lambda e: AnnofabApiFacade.get_choice_name_en(e) == attribute_query['choice_name_en'])
additional_data_definition["choices"],
pred=lambda e: AnnofabApiFacade.get_choice_name_en(e) == attribute_query["choice_name_en"],
)

if choice_info is not None:
attribute_query['choice'] = choice_info['choice_id']
attribute_query["choice"] = choice_info["choice_id"]
else:
logger.warning(f"choice_name_en = {attribute_query['choice_name_en']} の選択肢は存在しませんでした。")

return attribute_query

@staticmethod
def _find_additional_data_with_name(additional_data_definitions: List[AdditionalDataDefinition],
name: str) -> Optional[AdditionalDataDefinition]:
def _find_additional_data_with_name(
additional_data_definitions: List[AdditionalDataDefinition], name: str
) -> Optional[AdditionalDataDefinition]:

additional_data_definition = more_itertools.first_true(
additional_data_definitions,
pred=lambda e: AnnofabApiFacade.get_additional_data_definition_name_en(e) == name)
pred=lambda e: AnnofabApiFacade.get_additional_data_definition_name_en(e) == name,
)
return additional_data_definition

@staticmethod
def _find_additional_data_with_id(additional_data_definitions: List[AdditionalDataDefinition],
definition_id: str) -> Optional[AdditionalDataDefinition]:
def _find_additional_data_with_id(
additional_data_definitions: List[AdditionalDataDefinition], definition_id: str
) -> Optional[AdditionalDataDefinition]:

additional_data_definition = more_itertools.first_true(
additional_data_definitions, pred=lambda e: e['additional_data_definition_id'] == definition_id)
additional_data_definitions, pred=lambda e: e["additional_data_definition_id"] == definition_id
)
return additional_data_definition

def _modify_attributes_of_query(self, attributes_of_query: List[Dict[str, Any]],
definitions: List[AdditionalDataDefinition]) -> List[Dict[str, Any]]:
def _modify_attributes_of_query(
self, attributes_of_query: List[Dict[str, Any]], definitions: List[AdditionalDataDefinition]
) -> List[Dict[str, Any]]:
for attribute_query in attributes_of_query:
definition_name = attribute_query.get('additional_data_definition_name_en')
definition_name = attribute_query.get("additional_data_definition_name_en")
if definition_name is not None:
additional_data_definition = self._find_additional_data_with_name(definitions, definition_name)
if additional_data_definition is None:
Expand All @@ -77,10 +85,11 @@ def _modify_attributes_of_query(self, attributes_of_query: List[Dict[str, Any]],
continue

if additional_data_definition is not None:
attribute_query['additional_data_definition_id'] = additional_data_definition[
'additional_data_definition_id']
attribute_query["additional_data_definition_id"] = additional_data_definition[
"additional_data_definition_id"
]

definition_id = attribute_query['additional_data_definition_id']
definition_id = attribute_query["additional_data_definition_id"]
additional_data_definition = self._find_additional_data_with_id(definitions, definition_id)
if additional_data_definition is None:
logger.warning(
Expand All @@ -92,8 +101,9 @@ def _modify_attributes_of_query(self, attributes_of_query: List[Dict[str, Any]],

return attributes_of_query

def _modify_annotation_query(self, project_id: str, annotation_query: Dict[str, Any],
task_id: Optional[str] = None) -> Dict[str, Any]:
def _modify_annotation_query(
self, project_id: str, annotation_query: Dict[str, Any], task_id: Optional[str] = None
) -> Dict[str, Any]:
"""
タスク検索クエリを修正する。
* ``label_name_en`` から ``label_id`` に変換する。
Expand All @@ -111,56 +121,60 @@ def _modify_annotation_query(self, project_id: str, annotation_query: Dict[str,
"""

annotation_specs, _ = self.service.api.get_annotation_specs(project_id)
specs_labels = annotation_specs['labels']
specs_labels = annotation_specs["labels"]

# label_name_en から label_idを設定
if 'label_name_en' in annotation_query:
label_name_en = annotation_query['label_name_en']
label = more_itertools.first_true(specs_labels,
pred=lambda e: AnnofabApiFacade.get_label_name_en(e) == label_name_en)
if "label_name_en" in annotation_query:
label_name_en = annotation_query["label_name_en"]
label = more_itertools.first_true(
specs_labels, pred=lambda e: AnnofabApiFacade.get_label_name_en(e) == label_name_en
)
if label is not None:
annotation_query['label_id'] = label['label_id']
annotation_query["label_id"] = label["label_id"]
else:
logger.warning(f"label_name_en: {label_name_en} の label_id が見つかりませんでした。")

if annotation_query.keys() >= {'label_id', 'attributes'}:
label = more_itertools.first_true(specs_labels,
pred=lambda e: e['label_id'] == annotation_query['label_id'])
if annotation_query.keys() >= {"label_id", "attributes"}:
label = more_itertools.first_true(
specs_labels, pred=lambda e: e["label_id"] == annotation_query["label_id"]
)
if label is not None:
self._modify_attributes_of_query(annotation_query['attributes'], label['additional_data_definitions'])
self._modify_attributes_of_query(annotation_query["attributes"], label["additional_data_definitions"])
else:
logger.warning(f"label_id: {annotation_query['label_id']} の label_id が見つかりませんでした。")

if task_id is not None:
annotation_query['task_id'] = task_id
annotation_query['exact_match_task_id'] = True
annotation_query["task_id"] = task_id
annotation_query["exact_match_task_id"] = True

return annotation_query

@staticmethod
def aggregate_annotations(annotations: List[SingleAnnotation], group_by: GroupBy) -> pandas.DataFrame:
df = pandas.DataFrame(annotations)
df = df[['task_id', 'input_data_id']]
df['annotation_count'] = 1
df = df[["task_id", "input_data_id"]]
df["annotation_count"] = 1

if group_by == GroupBy.INPUT_DATA_ID:
return df.groupby(['task_id', 'input_data_id'], as_index=False).count()
return df.groupby(["task_id", "input_data_id"], as_index=False).count()

elif group_by == GroupBy.TASK_ID:
return df.groupby(['task_id'], as_index=False).count().drop(['input_data_id'], axis=1)
return df.groupby(["task_id"], as_index=False).count().drop(["input_data_id"], axis=1)

else:
return pandas.DataFrame()

def get_annotations(self, project_id: str, annotation_query: Dict[str, Any],
task_id: Optional[str] = None) -> List[SingleAnnotation]:
def get_annotations(
self, project_id: str, annotation_query: Dict[str, Any], task_id: Optional[str] = None
) -> List[SingleAnnotation]:
annotation_query = self._modify_annotation_query(project_id, annotation_query, task_id)
logger.debug(f"annotation_query: {annotation_query}")
annotations = self.service.wrapper.get_all_annotation_list(project_id, query_params={'query': annotation_query})
annotations = self.service.wrapper.get_all_annotation_list(project_id, query_params={"query": annotation_query})
return annotations

def list_annotations(self, project_id: str, annotation_query: Dict[str, Any], group_by: GroupBy,
task_id_list: List[str]):
def list_annotations(
self, project_id: str, annotation_query: Dict[str, Any], group_by: GroupBy, task_id_list: List[str]
):
"""
アノテーション一覧を出力する
"""
Expand Down Expand Up @@ -191,8 +205,9 @@ def main(self):

group_by = GroupBy(args.group_by)
task_id_list = annofabcli.common.cli.get_list_from_args(args.task_id)
self.list_annotations(args.project_id, annotation_query=annotation_query, group_by=group_by,
task_id_list=task_id_list)
self.list_annotations(
args.project_id, annotation_query=annotation_query, group_by=group_by, task_id_list=task_id_list
)


def main(args):
Expand All @@ -207,23 +222,32 @@ def parse_args(parser: argparse.ArgumentParser):
argument_parser.add_project_id()

parser.add_argument(
'-aq',
'--annotation_query',
"-aq",
"--annotation_query",
type=str,
required=True,
help='アノテーションの検索クエリをJSON形式で指定します。'
'`file://`を先頭に付けると、JSON形式のファイルを指定できます。'
'クエリのフォーマットは、[getAnnotationList API](https://annofab.com/docs/api/#operation/getAnnotationList)のクエリパラメータの`query`キー配下と同じです。' # noqa: E501
'さらに追加で、`label_name_en`(label_idに対応), `additional_data_definition_name_en`(additional_data_definition_idに対応) キーも指定できます。' # noqa: E501
help="アノテーションの検索クエリをJSON形式で指定します。"
"`file://`を先頭に付けると、JSON形式のファイルを指定できます。"
"クエリのフォーマットは、[getAnnotationList API](https://annofab.com/docs/api/#operation/getAnnotationList)のクエリパラメータの`query`キー配下と同じです。" # noqa: E501
"さらに追加で、`label_name_en`(label_idに対応), `additional_data_definition_name_en`(additional_data_definition_idに対応) キーも指定できます。", # noqa: E501
)

argument_parser.add_task_id(
required=False, help_message=('対象のタスクのtask_idを指定します。'
'`file://`を先頭に付けると、task_idの一覧が記載されたファイルを指定できます。'
'指定した場合、`--annotation_query`のtask_id, exact_match_task_idが上書きされます'))
required=False,
help_message=(
"対象のタスクのtask_idを指定します。"
"`file://`を先頭に付けると、task_idの一覧が記載されたファイルを指定できます。"
"指定した場合、`--annotation_query`のtask_id, exact_match_task_idが上書きされます"
),
)

parser.add_argument('--group_by', type=str, choices=[GroupBy.TASK_ID.value, GroupBy.INPUT_DATA_ID.value],
default=GroupBy.TASK_ID.value, help='アノテーションの個数をどの単位で集約するかを指定してます。')
parser.add_argument(
"--group_by",
type=str,
choices=[GroupBy.TASK_ID.value, GroupBy.INPUT_DATA_ID.value],
default=GroupBy.TASK_ID.value,
help="アノテーションの個数をどの単位で集約するかを指定してます。",
)

argument_parser.add_output()
argument_parser.add_csv_format()
Expand All @@ -234,7 +258,7 @@ def parse_args(parser: argparse.ArgumentParser):
def add_parser(subparsers: argparse._SubParsersAction):
subcommand_name = "list_count"
subcommand_help = "task_idまたはinput_data_idで集約したアノテーションの個数を出力します。"
description = ("task_idまたはinput_data_idで集約したアノテーションの個数を出力します。")
description = "task_idまたはinput_data_idで集約したアノテーションの個数を出力します。"

parser = annofabcli.common.cli.add_parser(subparsers, subcommand_name, subcommand_help, description)
parse_args(parser)
2 changes: 1 addition & 1 deletion annofabcli/annotation/subcommand_annotation.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

def parse_args(parser: argparse.ArgumentParser):

subparsers = parser.add_subparsers(dest='subcommand_name')
subparsers = parser.add_subparsers(dest="subcommand_name")

# サブコマンドの定義
annofabcli.annotation.list_annotation_count.add_parser(subparsers)
Expand Down
10 changes: 6 additions & 4 deletions annofabcli/annotation_specs/list_annotation_specs_history.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import argparse
import logging
from typing import Any, Callable, Dict, List, Optional, Tuple, Union # pylint: disable=unused-import
from typing import Any, Dict, List

import annofabapi

Expand All @@ -17,6 +17,7 @@ class AnnotationSpecsHistories(AbstractCommandLineInterface):
"""
アノテーション仕様の変更履歴を出力する。
"""

def __init__(self, service: annofabapi.Resource, facade: AnnofabApiFacade, args: argparse.Namespace):
super().__init__(service, facade, args)
self.visualize = AddProps(self.service, args.project_id)
Expand Down Expand Up @@ -47,8 +48,9 @@ def parse_args(parser: argparse.ArgumentParser):

argument_parser.add_project_id()

argument_parser.add_format(choices=[FormatArgument.CSV, FormatArgument.JSON, FormatArgument.PRETTY_JSON],
default=FormatArgument.CSV)
argument_parser.add_format(
choices=[FormatArgument.CSV, FormatArgument.JSON, FormatArgument.PRETTY_JSON], default=FormatArgument.CSV
)
argument_parser.add_output()
argument_parser.add_csv_format()
argument_parser.add_query()
Expand All @@ -59,7 +61,7 @@ def parse_args(parser: argparse.ArgumentParser):
def add_parser(subparsers: argparse._SubParsersAction):
subcommand_name = "history"
subcommand_help = "アノテーション仕様の変更履歴を表示する。"
description = ("アノテーション仕様の変更履歴を表示する。")
description = "アノテーション仕様の変更履歴を表示する。"

parser = annofabcli.common.cli.add_parser(subparsers, subcommand_name, subcommand_help, description)
parse_args(parser)
Loading

0 comments on commit 107be43

Please sign in to comment.