Skip to content

Commit 5c09171

Browse files
committed
feat: enhance safe_to_dict function to support sorting by ID and update term info parsing to sort images by ID
1 parent f003e25 commit 5c09171

3 files changed

Lines changed: 41 additions & 121 deletions

File tree

README.md

Lines changed: 19 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ vfb.get_term_info('FBbt_00003748')
3333
"Meta": {
3434
"Name": "[medulla](FBbt_00003748)",
3535
"Description": "The second optic neuropil, sandwiched between the lamina and the lobula complex. It is divided into 10 layers: 1-6 make up the outer (distal) medulla, the seventh (or serpentine) layer exhibits a distinct architecture and layers 8-10 make up the inner (proximal) medulla (Ito et al., 2014).",
36-
"Comment": "",
36+
"Comment": "Nern et al. (2025) - doi:10.1038/s41586-025-08746-0 say distal is M1-5 and M6-7 is central medulla.",
3737
"Types": "[anterior ectoderm derivative](FBbt_00025991); [synaptic neuropil domain](FBbt_00040007)",
3838
"Relationships": "[develops from](RO_0002202): [medulla anlage](FBbt_00001935); [is part of](BFO_0000050): [adult optic lobe](FBbt_00003701)"
3939
},
@@ -81,106 +81,6 @@ vfb.get_term_info('FBbt_00003748')
8181
"0": "Asc"
8282
}
8383
},
84-
"tags": {
85-
"title": "Gross Types",
86-
"type": "tags",
87-
"order": 3
88-
},
89-
"thumbnail": {
90-
"title": "Thumbnail",
91-
"type": "markdown",
92-
"order": 9
93-
}
94-
},
95-
"rows": [
96-
{
97-
"id": "VFB_00102107",
98-
"label": "[ME on JRC2018Unisex adult brain](VFB_00102107)",
99-
"tags": "Nervous_system|Adult|Visual_system|Synaptic_neuropil_domain",
100-
"thumbnail": "[![ME on JRC2018Unisex adult brain aligned to JRC2018U](http://www.virtualflybrain.org/data/VFB/i/0010/2107/VFB_00101567/thumbnail.png 'ME on JRC2018Unisex adult brain aligned to JRC2018U')](VFB_00101567,VFB_00102107)"
101-
},
102-
{
103-
"id": "VFB_00101385",
104-
"label": "[ME%28R%29 on JRC_FlyEM_Hemibrain](VFB_00101385)",
105-
"tags": "Nervous_system|Adult|Visual_system|Synaptic_neuropil_domain",
106-
"thumbnail": "[![ME%28R%29 on JRC_FlyEM_Hemibrain aligned to JRCFIB2018Fum](http://www.virtualflybrain.org/data/VFB/i/0010/1385/VFB_00101384/thumbnail.png 'ME(R) on JRC_FlyEM_Hemibrain aligned to JRCFIB2018Fum')](VFB_00101384,VFB_00101385)"
107-
},
108-
{
109-
"id": "VFB_00030810",
110-
"label": "[medulla on adult brain template Ito2014](VFB_00030810)",
111-
"tags": "Nervous_system|Visual_system|Adult|Synaptic_neuropil_domain",
112-
"thumbnail": "[![medulla on adult brain template Ito2014 aligned to adult brain template Ito2014](http://www.virtualflybrain.org/data/VFB/i/0003/0810/VFB_00030786/thumbnail.png 'medulla on adult brain template Ito2014 aligned to adult brain template Ito2014')](VFB_00030786,VFB_00030810)"
113-
},
114-
{
115-
"id": "VFB_00030624",
116-
"label": "[medulla on adult brain template JFRC2](VFB_00030624)",
117-
"tags": "Nervous_system|Visual_system|Adult|Synaptic_neuropil_domain",
118-
"thumbnail": "[![medulla on adult brain template JFRC2 aligned to JFRC2](http://www.virtualflybrain.org/data/VFB/i/0003/0624/VFB_00017894/thumbnail.png 'medulla on adult brain template JFRC2 aligned to JFRC2')](VFB_00017894,VFB_00030624)"
119-
}
120-
]
121-
},
122-
"output_format": "table",
123-
"count": 4
124-
}
125-
],
126-
"IsIndividual": False,
127-
"IsClass": True,
128-
"Examples": {
129-
"VFB_00017894": [
130-
{
131-
"id": "VFB_00030624",
132-
"label": "medulla on adult brain template JFRC2",
133-
"thumbnail": "https://www.virtualflybrain.org/data/VFB/i/0003/0624/VFB_00017894/thumbnail.png",
134-
"thumbnail_transparent": "https://www.virtualflybrain.org/data/VFB/i/0003/0624/VFB_00017894/thumbnailT.png",
135-
"nrrd": "https://www.virtualflybrain.org/data/VFB/i/0003/0624/VFB_00017894/volume.nrrd",
136-
"wlz": "https://www.virtualflybrain.org/data/VFB/i/0003/0624/VFB_00017894/volume.wlz",
137-
"obj": "https://www.virtualflybrain.org/data/VFB/i/0003/0624/VFB_00017894/volume_man.obj"
138-
}
139-
],
140-
"VFB_00101384": [
141-
{
142-
"id": "VFB_00101385",
143-
"label": "ME(R) on JRC_FlyEM_Hemibrain",
144-
"thumbnail": "https://www.virtualflybrain.org/data/VFB/i/0010/1385/VFB_00101384/thumbnail.png",
145-
"thumbnail_transparent": "https://www.virtualflybrain.org/data/VFB/i/0010/1385/VFB_00101384/thumbnailT.png",
146-
"nrrd": "https://www.virtualflybrain.org/data/VFB/i/0010/1385/VFB_00101384/volume.nrrd",
147-
"wlz": "https://www.virtualflybrain.org/data/VFB/i/0010/1385/VFB_00101384/volume.wlz",
148-
"obj": "https://www.virtualflybrain.org/data/VFB/i/0010/1385/VFB_00101384/volume_man.obj"
149-
}
150-
],
151-
"VFB_00101567": [
152-
{
153-
"id": "VFB_00102107",
154-
"label": "ME on JRC2018Unisex adult brain",
155-
"thumbnail": "https://www.virtualflybrain.org/data/VFB/i/0010/2107/VFB_00101567/thumbnail.png",
156-
"thumbnail_transparent": "https://www.virtualflybrain.org/data/VFB/i/0010/2107/VFB_00101567/thumbnailT.png",
157-
"nrrd": "https://www.virtualflybrain.org/data/VFB/i/0010/2107/VFB_00101567/volume.nrrd",
158-
"wlz": "https://www.virtualflybrain.org/data/VFB/i/0010/2107/VFB_00101567/volume.wlz",
159-
"obj": "https://www.virtualflybrain.org/data/VFB/i/0010/2107/VFB_00101567/volume_man.obj"
160-
}
161-
],
162-
"VFB_00030786": [
163-
{
164-
"id": "VFB_00030810",
165-
"label": "medulla on adult brain template Ito2014",
166-
"thumbnail": "https://www.virtualflybrain.org/data/VFB/i/0003/0810/VFB_00030786/thumbnail.png",
167-
"thumbnail_transparent": "https://www.virtualflybrain.org/data/VFB/i/0003/0810/VFB_00030786/thumbnailT.png",
168-
"nrrd": "https://www.virtualflybrain.org/data/VFB/i/0003/0810/VFB_00030786/volume.nrrd",
169-
"wlz": "https://www.virtualflybrain.org/data/VFB/i/0003/0810/VFB_00030786/volume.wlz",
170-
"obj": "https://www.virtualflybrain.org/data/VFB/i/0003/0810/VFB_00030786/volume_man.obj"
171-
}
172-
]
173-
},
174-
"IsTemplate": False,
175-
"Synonyms": [
176-
{
177-
"label": "ME",
178-
"scope": "has_exact_synonym",
179-
"type": "",
180-
"publication": "[Ito et al., 2014](FBrf0224194)"
181-
},
182-
{
183-
"label": "Med",
18484
"scope": "has_exact_synonym",
18585
"type": "",
18686
"publication": "[Chiang et al., 2011](FBrf0212704)"
@@ -303,14 +203,14 @@ vfb.get_term_info('VFB_00000001')
303203
"score": "0.61",
304204
"name": "[fru-M-000204](VFB_00000333)",
305205
"tags": "Expression_pattern_fragment|Neuron|Adult|lineage_CM3",
306-
"thumbnail": "[![fru-M-000204 aligned to JRC2018U](http://www.virtualflybrain.org/data/VFB/i/0000/0333/VFB_00101567/thumbnail.png 'fru-M-000204 aligned to JRC2018U')](VFB_00101567,VFB_00000333)"
206+
"thumbnail": "[![fru-M-000204 aligned to JFRC2](http://www.virtualflybrain.org/data/VFB/i/0000/0333/VFB_00017894/thumbnail.png 'fru-M-000204 aligned to JFRC2')](VFB_00017894,VFB_00000333)"
307207
},
308208
{
309209
"id": "VFB_00000333",
310210
"score": "0.61",
311211
"name": "[fru-M-000204](VFB_00000333)",
312212
"tags": "Expression_pattern_fragment|Neuron|Adult|lineage_CM3",
313-
"thumbnail": "[![fru-M-000204 aligned to JFRC2](http://www.virtualflybrain.org/data/VFB/i/0000/0333/VFB_00017894/thumbnail.png 'fru-M-000204 aligned to JFRC2')](VFB_00017894,VFB_00000333)"
213+
"thumbnail": "[![fru-M-000204 aligned to JRC2018U](http://www.virtualflybrain.org/data/VFB/i/0000/0333/VFB_00101567/thumbnail.png 'fru-M-000204 aligned to JRC2018U')](VFB_00101567,VFB_00000333)"
314214
},
315215
{
316216
"id": "VFB_00002439",
@@ -327,32 +227,20 @@ vfb.get_term_info('VFB_00000001')
327227
"thumbnail": "[![fru-M-900020 aligned to JFRC2](http://www.virtualflybrain.org/data/VFB/i/0000/2439/VFB_00017894/thumbnail.png 'fru-M-900020 aligned to JFRC2')](VFB_00017894,VFB_00002439)"
328228
},
329229
{
330-
"id": "VFB_00001880",
230+
"id": "VFB_00000845",
331231
"score": "0.59",
332-
"name": "[fru-M-100041](VFB_00001880)",
232+
"name": "[fru-M-100191](VFB_00000845)",
333233
"tags": "Expression_pattern_fragment|Neuron|Adult|lineage_CM3",
334-
"thumbnail": "[![fru-M-100041 aligned to JRC2018U](http://www.virtualflybrain.org/data/VFB/i/0000/1880/VFB_00101567/thumbnail.png 'fru-M-100041 aligned to JRC2018U')](VFB_00101567,VFB_00001880)"
234+
"thumbnail": "[![fru-M-100191 aligned to JRC2018U](http://www.virtualflybrain.org/data/VFB/i/0000/0845/VFB_00101567/thumbnail.png 'fru-M-100191 aligned to JRC2018U')](VFB_00101567,VFB_00000845)"
335235
}
336236
]
337237
},
338238
"output_format": "table",
339-
"count": 44
239+
"count": 60
340240
}
341241
],
342242
"IsIndividual": True,
343243
"Images": {
344-
"VFB_00101567": [
345-
{
346-
"id": "VFB_00000001",
347-
"label": "fru-M-200266",
348-
"thumbnail": "https://www.virtualflybrain.org/data/VFB/i/0000/0001/VFB_00101567/thumbnail.png",
349-
"thumbnail_transparent": "https://www.virtualflybrain.org/data/VFB/i/0000/0001/VFB_00101567/thumbnailT.png",
350-
"nrrd": "https://www.virtualflybrain.org/data/VFB/i/0000/0001/VFB_00101567/volume.nrrd",
351-
"wlz": "https://www.virtualflybrain.org/data/VFB/i/0000/0001/VFB_00101567/volume.wlz",
352-
"obj": "https://www.virtualflybrain.org/data/VFB/i/0000/0001/VFB_00101567/volume.obj",
353-
"swc": "https://www.virtualflybrain.org/data/VFB/i/0000/0001/VFB_00101567/volume.swc"
354-
}
355-
],
356244
"VFB_00017894": [
357245
{
358246
"id": "VFB_00000001",
@@ -364,6 +252,18 @@ vfb.get_term_info('VFB_00000001')
364252
"obj": "https://www.virtualflybrain.org/data/VFB/i/0000/0001/VFB_00017894/volume.obj",
365253
"swc": "https://www.virtualflybrain.org/data/VFB/i/0000/0001/VFB_00017894/volume.swc"
366254
}
255+
],
256+
"VFB_00101567": [
257+
{
258+
"id": "VFB_00000001",
259+
"label": "fru-M-200266",
260+
"thumbnail": "https://www.virtualflybrain.org/data/VFB/i/0000/0001/VFB_00101567/thumbnail.png",
261+
"thumbnail_transparent": "https://www.virtualflybrain.org/data/VFB/i/0000/0001/VFB_00101567/thumbnailT.png",
262+
"nrrd": "https://www.virtualflybrain.org/data/VFB/i/0000/0001/VFB_00101567/volume.nrrd",
263+
"wlz": "https://www.virtualflybrain.org/data/VFB/i/0000/0001/VFB_00101567/volume.wlz",
264+
"obj": "https://www.virtualflybrain.org/data/VFB/i/0000/0001/VFB_00101567/volume.obj",
265+
"swc": "https://www.virtualflybrain.org/data/VFB/i/0000/0001/VFB_00101567/volume.swc"
266+
}
367267
]
368268
},
369269
"IsClass": False,

src/vfbquery/test_utils.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def default(self, obj):
1818
return obj.item()
1919
return super(NumpyEncoder, self).default(obj)
2020

21-
def safe_to_dict(df):
21+
def safe_to_dict(df, sort_by_id=True):
2222
"""Convert DataFrame to dict with numpy types converted to native Python types"""
2323
if isinstance(df, pd.DataFrame):
2424
# Convert numpy dtypes to native Python types
@@ -28,6 +28,11 @@ def safe_to_dict(df):
2828
df_copy[col] = df_copy[col].astype('object')
2929
elif df_copy[col].dtype.name.startswith('float'):
3030
df_copy[col] = df_copy[col].astype('object')
31+
32+
# Sort by id column in descending order if it exists and sort_by_id is True
33+
if sort_by_id and 'id' in df_copy.columns:
34+
df_copy = df_copy.sort_values('id', ascending=False)
35+
3136
return df_copy.to_dict("records")
3237
return df
3338

src/vfbquery/vfb_queries.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def default(self, obj):
2525
return obj.item()
2626
return super(NumpyEncoder, self).default(obj)
2727

28-
def safe_to_dict(df):
28+
def safe_to_dict(df, sort_by_id=True):
2929
"""Convert DataFrame to dict with numpy types converted to native Python types"""
3030
if isinstance(df, pd.DataFrame):
3131
# Convert numpy dtypes to native Python types
@@ -35,6 +35,11 @@ def safe_to_dict(df):
3535
df_copy[col] = df_copy[col].astype('object')
3636
elif df_copy[col].dtype.name.startswith('float'):
3737
df_copy[col] = df_copy[col].astype('object')
38+
39+
# Sort by id column in descending order if it exists and sort_by_id is True
40+
if sort_by_id and 'id' in df_copy.columns:
41+
df_copy = df_copy.sort_values('id', ascending=False)
42+
3843
return df_copy.to_dict("records")
3944
return df
4045

@@ -518,6 +523,11 @@ def term_info_parse_object(results, short_form):
518523
if "image_" in key and not ("thumbnail" in key or "folder" in key) and len(vars(image.channel_image.image)[key]) > 1:
519524
record[key.replace("image_","")] = vars(image.channel_image.image)[key].replace("http://","https://")
520525
images[image.channel_image.image.template_anatomy.short_form].append(record)
526+
527+
# Sort each template's images by id in descending order (newest first)
528+
for template_key in images:
529+
images[template_key] = sorted(images[template_key], key=lambda x: x["id"], reverse=True)
530+
521531
termInfo["Examples"] = images
522532
# add a query to `queries` list for listing all available images
523533
q = ListAllAvailableImages_to_schema(termInfo["Name"], {"short_form":vfbTerm.term.core.short_form})
@@ -541,6 +551,11 @@ def term_info_parse_object(results, short_form):
541551
if "image_" in key and not ("thumbnail" in key or "folder" in key) and len(vars(image.image)[key]) > 1:
542552
record[key.replace("image_","")] = vars(image.image)[key].replace("http://","https://")
543553
images[image.image.template_anatomy.short_form].append(record)
554+
555+
# Sort each template's images by id in descending order (newest first)
556+
for template_key in images:
557+
images[template_key] = sorted(images[template_key], key=lambda x: x["id"], reverse=True)
558+
544559
# Add the thumbnails to the term info
545560
termInfo["Images"] = images
546561

0 commit comments

Comments
 (0)