diff --git a/config/branch_metric.json b/config/branch_metric.json index 315b8d7..a05990d 100644 --- a/config/branch_metric.json +++ b/config/branch_metric.json @@ -2,7 +2,7 @@ "threshold_dis": 2, "threshold_mode": 1, "z_scale": 1, - "true_positive_type": 3, - "false_negative_type": 4, - "false_positive_type": 5 + "true_positive": 3, + "missed": 4, + "excess": 5 } \ No newline at end of file diff --git a/config/schemas/branch_metric_schema.json b/config/schemas/branch_metric_schema.json index e87a458..4c9d264 100644 --- a/config/schemas/branch_metric_schema.json +++ b/config/schemas/branch_metric_schema.json @@ -5,16 +5,16 @@ "threshold_dis", "threshold_mode", "z_scale", - "true_positive_type", - "false_negative_type", - "false_positive_type" + "true_positive", + "missed", + "excess" ], "properties": { "threshold_dis": {"type": "number", "exclusiveMinimum": 0}, "threshold_mode": {"type": "number", "enum": [1, 2]}, "z_scale": {"type": "number","minimum": 0}, - "true_positive_type": {"type": "integer", "exclusiveMinimum": 0}, - "false_negative_type": {"type": "integer", "exclusiveMinimum": 0}, - "false_positive_type": {"type": "integer", "exclusiveMinimum": 0} + "true_positive": {"type": "integer", "exclusiveMinimum": 0}, + "missed": {"type": "integer", "exclusiveMinimum": 0}, + "excess": {"type": "integer", "exclusiveMinimum": 0} } } \ No newline at end of file diff --git a/pyneval/cli/pyneval.py b/pyneval/cli/pyneval.py index e44720c..9c6756d 100644 --- a/pyneval/cli/pyneval.py +++ b/pyneval/cli/pyneval.py @@ -13,6 +13,8 @@ from pyneval.metric import branch_leaf_metric from pyneval.metric import link_metric from pyneval.metric import ssd_metric +from pyneval.metric.utils import anno_utils + METRICS = { 'diadem_metric': { @@ -193,10 +195,9 @@ def set_configs(abs_dir, args): config = read_json.read_json(config_path) config_schema = read_json.read_json(config_schema_path) - try: - jsonschema.validate(config, config_schema) - except Exception: - raise Exception("[Error: ]Error in analyzing config json file") + + jsonschema.validate(config, config_schema) + # argument: output output_dir = None @@ -230,10 +231,15 @@ def excute_metric(metric, gold_swc_tree, test_swc_tree, config, detail_dir, outp file_name = test_swc_name[:-4] + "_" + metric + "_" if detail_dir: - swc_save(swc_tree=res_gold_swc_tree, - out_path=os.path.join(detail_dir, file_name + "recall.swc")) - swc_save(swc_tree=res_test_swc_tree, - out_path=os.path.join(detail_dir, file_name + "precision.swc")) + if res_gold_swc_tree is not None: + swc_save(swc_tree=res_gold_swc_tree, + out_path=os.path.join(detail_dir, file_name + "recall.swc"), + extra=anno_utils.get_detail_type(metric)) + if res_test_swc_tree is not None: + swc_save(swc_tree=res_test_swc_tree, + out_path=os.path.join(detail_dir, file_name + "precision.swc"), + extra=anno_utils.get_detail_type(metric)) + if output_dir: read_json.save_json(data=result, diff --git a/pyneval/io/swc_writer.py b/pyneval/io/swc_writer.py index 8a0e6fe..d300af3 100644 --- a/pyneval/io/swc_writer.py +++ b/pyneval/io/swc_writer.py @@ -46,13 +46,15 @@ def print_swc(object): print_line_tuple_swc(object) -def swc_save(swc_tree, out_path): +def swc_save(swc_tree, out_path, extra=None): if not is_path_valid(out_path): return False swc_node_list = swc_tree.get_node_list() swc_tree.sort_node_list(key="id") with open(out_path, 'w') as f: f.truncate() + if extra is not None: + f.write(extra) for node in swc_node_list: if node.is_virtual(): continue diff --git a/pyneval/metric/branch_leaf_metric.py b/pyneval/metric/branch_leaf_metric.py index d6d8fb4..50010dc 100644 --- a/pyneval/metric/branch_leaf_metric.py +++ b/pyneval/metric/branch_leaf_metric.py @@ -161,9 +161,9 @@ def branch_leaf_metric(gold_swc_tree, test_swc_tree, config): threshold_dis = threshold_dis * tot_dis / edge_num # denote the color id of different type of nodes. color = [ - config["true_positive_type"], - config["false_negative_type"], - config["false_positive_type"] + config["true_positive"], + config["missed"], + config["excess"] ] gold_swc_tree.type_clear(0, 0) test_swc_tree.type_clear(0, 0) diff --git a/pyneval/metric/utils/anno_utils.py b/pyneval/metric/utils/anno_utils.py new file mode 100644 index 0000000..9e64308 --- /dev/null +++ b/pyneval/metric/utils/anno_utils.py @@ -0,0 +1,48 @@ +from pyneval.io.read_json import read_json + + +def get_detail_type(metric_name): + detail_type_annotation = dict() + detail_type_annotation["ssd_metric"] = "# 1: gold standard root\n" \ + "# 2: gold standard branch(degree >= 3)\n" \ + "# 3: gold standard continuation(degree == 2)\n" \ + "# 4: gold standard leaf(degree == 1)\n" \ + "# 5: reconstruction root\n" \ + "# 6: reconstruction branch(degree >= 3)\n" \ + "# 7: reconstruction continuation(degree == 2)\n" \ + "# 8: reconstruction leaf(degree == 1)\n" \ + "# 9: mismatched node(regardless rules above)\n\n" + detail_type_annotation["length_metric"] = "# 1: gold standard root\n" \ + "# 2: gold standard branch(degree >= 3)\n" \ + "# 3: gold standard continuation(degree == 2)\n" \ + "# 4: gold standard leaf(degree == 1)\n" \ + "# 5: reconstruction root\n" \ + "# 6: reconstruction branch(degree >= 3)\n" \ + "# 7: reconstruction continuation(degree == 2)\n" \ + "# 8: reconstruction leaf(degree == 1)\n" \ + "# 9: edge between this node and its parent is mismatched" \ + "(regardless rules above)\n\n" + detail_type_annotation["branch_metric"] = "# type of nodes in this metric detail could be change in configs\n" \ + "# true_positive_type: successfully reconstructed nodes, " \ + "exists in both GS and R\n" \ + "# missed: wrongly reconstructed as negative. " \ + "exist in GS but not in R\n" \ + "# excess: wrongly reconstructed as positive. " \ + "exist in R but not in GS.\n\n" + detail_type_annotation["diadem_metric"] = "# 1: gold standard root\n" \ + "# 2: gold standard branch(degree >= 3)\n" \ + "# 3: gold standard continuation(degree == 2)\n" \ + "# 4: gold standard leaf(degree == 1)\n" \ + "# 5: reconstruction root\n" \ + "# 6: reconstruction branch(degree >= 3)\n" \ + "# 7: reconstruction continuation(degree == 2)\n" \ + "# 8: reconstruction leaf(degree == 1)\n" \ + "# 9: missed: exist in GS but not in R\n" \ + "# 10 excess: exist in R but not in GS\n\n" + if metric_name not in detail_type_annotation: + return None + return detail_type_annotation[metric_name] + + +if __name__ == "__main__": + print(get_detail_type("branch_metric")) \ No newline at end of file