From 14d06b1f2c228cc0be2d8c1b790ad39f10e2b9b6 Mon Sep 17 00:00:00 2001 From: Robbie1977 Date: Tue, 15 Sep 2026 10:21:17 +0000 Subject: [PATCH] Put a template's indexed image first in Examples An image with an index is a domain in that template's label volume, so it belongs to the template and should lead the Available Images carousel. Examples records now carry the index and each template's list is ordered indexed-first (index ascending), then by id descending as before. Refs VirtualFlyBrain/VFB2#500 --- src/test/test_examples_order.py | 41 +++++++++++++++++++++++++++++++++ src/vfbquery/vfb_queries.py | 17 ++++++++++++-- 2 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 src/test/test_examples_order.py diff --git a/src/test/test_examples_order.py b/src/test/test_examples_order.py new file mode 100644 index 0000000..0ed22b6 --- /dev/null +++ b/src/test/test_examples_order.py @@ -0,0 +1,41 @@ +"""Available Images order: a template's own domain image leads.""" +import unittest + +from vfbquery.vfb_queries import order_template_examples + + +class OrderTemplateExamplesTest(unittest.TestCase): + + def test_indexed_image_first_then_newest_id(self): + # FBbt_00003748 on JRC2018U: the painted domain VFB_00102107 has the + # oldest id but is the only image indexed to the template. + records = [ + {"id": "VFB_00107fo8"}, + {"id": "VFB_00102107", "index": 3}, + {"id": "VFB_001091st"}, + {"id": "VFB_00108iwp"}, + ] + self.assertEqual( + [r["id"] for r in order_template_examples(records)], + ["VFB_00102107", "VFB_001091st", "VFB_00108iwp", "VFB_00107fo8"]) + + def test_several_indexed_images_ascend_by_index(self): + records = [ + {"id": "VFB_0000000a", "index": 7}, + {"id": "VFB_0000000b"}, + {"id": "VFB_0000000c", "index": 0}, + {"id": "VFB_0000000d", "index": 2}, + ] + self.assertEqual( + [r["id"] for r in order_template_examples(records)], + ["VFB_0000000c", "VFB_0000000d", "VFB_0000000a", "VFB_0000000b"]) + + def test_no_index_keeps_id_descending(self): + records = [{"id": "VFB_00000001"}, {"id": "VFB_00000003"}, {"id": "VFB_00000002"}] + self.assertEqual( + [r["id"] for r in order_template_examples(records)], + ["VFB_00000003", "VFB_00000002", "VFB_00000001"]) + + +if __name__ == "__main__": + unittest.main() diff --git a/src/vfbquery/vfb_queries.py b/src/vfbquery/vfb_queries.py index 1482fc1..f9fcb4f 100644 --- a/src/vfbquery/vfb_queries.py +++ b/src/vfbquery/vfb_queries.py @@ -360,6 +360,17 @@ def __init__(self, id, label, thumbnail=None, thumbnail_transparent=None, nrrd=N self.type_label = type_label self.type_id = type_id +def order_template_examples(records): + """Order one template's Examples so its own domain images come first. + + An image with an index is a domain in that template's label volume, so it + belongs to the template and leads the Available Images carousel, by index + ascending. Everything else follows, newest id first as before. + """ + by_id = sorted(records, key=lambda r: r["id"], reverse=True) + return sorted(by_id, key=lambda r: (r.get("index") is None, r.get("index") or 0)) + + class ImageSchema(Schema): id = fields.String(required=True) label = fields.String(required=True) @@ -963,11 +974,13 @@ def term_info_parse_object(results, short_form): for key in vars(image.channel_image.image).keys(): if "image_" in key and not ("thumbnail" in key or "folder" in key) and len(vars(image.channel_image.image)[key]) > 1: record[key.replace("image_","")] = vars(image.channel_image.image)[key].replace("http://","https://") + image_index = getattr(image.channel_image.image, "index", None) + if image_index: + record["index"] = int(image_index[0]) images[image.channel_image.image.template_anatomy.short_form].append(record) - # Sort each template's images by id in descending order (newest first) for template_key in images: - images[template_key] = sorted(images[template_key], key=lambda x: x["id"], reverse=True) + images[template_key] = order_template_examples(images[template_key]) termInfo["Examples"] = images # Add techniques to termInfo for Individuals