Xnatpy: Searching with subject.Demographics data and with custom fields sets

125 views
Skip to first unread message

andres rojas

unread,
Nov 24, 2023, 9:47:28 AM11/24/23
to xnat_discussion
Hello guys,

I have uploaded the subjects from my study to a dataset hosted in XNAT and I have added all the metadata for the subjects. To store the metadata I used the fields for subject demographics in XNAT and I also created a custom form for additional information. 

I need to be able to perform searches in my data set. For example I would like to be able to retrieve all female subjects above 60 years who have a given diagnostic stored in my custom form. Below an example of how I am accesing it in Xnatpy.

Query 1: female and older than 60 years 

subject_obj = session.classes.SubjectData
project_id='my_project_name

subject_obj.query().filter(subject_obj.project == project_id, subject_obj.demographics.age > 70, subject_obj.demographics.gender.like('female')).all()

# Query one Answer Error
Interestingly If I query this it works well: 
subject_obj.query().filter(subject_obj.project==project_id, subject_obj.AGE > 70).all()
# The access to age is direct, no in demographics. 

Query 2:
I would like to select all subjects from the data set that satisy the condition -> CustomForm.cognitiveDecline == ''NO". 

Question 1: How can I query using the demographics data ?

Question 2: How can I perform my Query 2 accesing the custom fields ? 
Do you have a snapshoot ? 

I attached a picture of how my custom field looks like for illustration. 

If anyone has a suggestion of doing in it with the raw APi and would like to show me how to construct the right query, it is also well apreciated. Although I would like to continue the development with Xnatpy 

Thanks a lot in advance, 

Andrés 








Screenshot 2023-11-24 153717.png

Chidi Ugonna

unread,
Dec 1, 2023, 12:40:28 PM12/1/23
to xnat_discussion
Hi everyone,
Sorry for posting this twice. It seems better to track progress with this in this thread.

........

I used XNATpy 0.5.2 (I think 0.5.1 will also work without issues but I didn't test this)  and used Hakim's suggestion to get past the "*** TypeError: 'NoneType' object is not iterable" exception that was thrown when trying to query on an XNAT class. This is  a hack and I'm sure that with the next iteration of XNATpy this will be fixed. To make that change:

1. Quick hack for searching on 0.5.2
Find  module `search.py` on your python path for example `lib/python3.9/site-packages/xnat/search.py` (there is another search,py at /xnat/client/search.py that you dont want). In the definition for Class Query change fields=None to fields = ()

so before looks like this:
class Query(object):
    def __init__(self, queried_class, xnat_session, fields=None, constraints=None):
        self.queried_class = queried_class

after looks like this:
class Query(object):
    def __init__(self, queried_class, xnat_session, fields=(), constraints=None):
        self.queried_class = queried_class

2. What can I search on?
XNATpy's documentation on searching is really comprehensive and explains much  https://xnat.readthedocs.io/en/latest/static/tutorial.html#searching. To inspect what fields are available in a connection class e.g SubjectData - we can use the vars() method as shown below - I have highlighted the Custom Fields that I created using the Custom Form

import xnat
from pprint import pprint

connection = xnat.connect(server="http://127.0.0.1",user='admin',password='admin')
SubjectData = connection.classes.SubjectData
pprint(vars(SubjectData))


This is a trunctated output showing custom fields and standard fields:

mappingproxy({'ADD_IDS': <SearchField xnat:subjectData/ADD_IDS>,
              'AGE': <SearchField xnat:subjectData/AGE>,
              'AGE_BRACKET': <SearchField xnat:subjectData/AGE_BRACKET>,
              'DOB': <SearchField xnat:subjectData/DOB>,
              'EDUC': <SearchField xnat:subjectData/EDUC>,
              'ETHNICITY': <SearchField xnat:subjectData/ETHNICITY>,
              'GENDER_TEXT': <SearchField xnat:subjectData/GENDER_TEXT>,
              'HANDEDNESS_TEXT': <SearchField xnat:subjectData/HANDEDNESS_TEXT>,
              'INSERT_DATE': <SearchField xnat:subjectData/INSERT_DATE>,
              'INSERT_USER': <SearchField xnat:subjectData/INSERT_USER>,
              'INVEST_CSV': <SearchField xnat:subjectData/INVEST_CSV>,
              'PROJECT': <SearchField xnat:subjectData/PROJECT>,
              'PROJECTS': <SearchField xnat:subjectData/PROJECTS>,
              'RACE': <SearchField xnat:subjectData/RACE>,
              'SES': <SearchField xnat:subjectData/SES>,
              'SUB_GROUP': <SearchField xnat:subjectData/SUB_GROUP>,
              'XNAT:SUBJECTDATA_CUSTOM-FORM_0E51F111-E2AA-4671-A0C8-B5C50981F332_DRUGDOSE': <SearchField xnat:subjectData/XNAT:SUBJECTDATA_CUSTOM-FORM_0E51F111-E2AA-4671-A0C8-B5C50981F332_DRUGDOSE>,
              'XNAT:SUBJECTDATA_CUSTOM-FORM_0E51F111-E2AA-4671-A0C8-B5C50981F332_DRUGTYPE': <SearchField xnat:subjectData/XNAT:SUBJECTDATA_CUSTOM-FORM_0E51F111-E2AA-4671-A0C8-B5C50981F332_DRUGTYPE>,


3. Constructing a search using custom fields (from custom form) and standard fields?
because of the format of the custom fields we will access them using the getattr() method instead. So for a combined search on gender and drug dose for example we can do this:

sublist = SubjectData.query().filter((SubjectData.GENDER_TEXT == "M") & (getattr(SubjectData,"XNAT:SUBJECTDATA_CUSTOM-FORM_0E51F111-E2AA-4671-A0C8-B5C50981F332_DRUGDOSE") > 20))
sublist.all()

[<SubjectData SUB001 (XNAT_S00001)>, <SubjectData SUB004 (XNAT_S00004)>]

Reply all
Reply to author
Forward
0 new messages