Export Form Responses and/or Annotations to CSV file(s).
Project description
Form and Annotation Exporter
Overview
Summary
Export Form Responses and/or Annotations to CSV file(s).
License
License: MIT
Classification
Category: Analysis
Gear Level:
- Project
- Subject
- Session
- Acquisition
- Analysis
Usage
The Form and Annotation Exporter gear is executed by ensuring the following configuration parameters are provided and are in a valid combination. This gear has no file inputs. This gear requires that the Reader Task Workflow be enabled on the instance it is run on.
If an ohif_config.json
is being used to configure the OHIF Viewer, and you are
using it to capture form responses outside of the Reader Task workflow, you cannot use
this gear to retrieve the form responses from the sessions. See the Example of
Retrieving Form-Responses from Session Variables
section for anexample of how to do this.
If the gear is run within a project for a protocol where the protocol_name is not defined, the gear will fail.
For the annotations-scope configuration parameter, the following combinations are valid:
task
andboth
settings require a valid protocol_name for a protocol defined within the project.non-task
andnone
settings do not require a valid protocol_name. This allows for the export of annotations and form responses that are not associated with a task.- if both -scope settings are set to
none
, the gear will fail as there will be no output.
For the form-responses-scope configuration parameter, the following combinations are valid:
task
andnone
are the only valid combinations
Running this gear under a specific subject, session, or acquisition will constrain the output to only those tasks, form-responses, and annotations that are associated with the container and its children.
This gear will output select annotation properties for the following annotation types:
- Ellipse
- Circle
- Rectangle
- Freehand/Contour (closed)
- Length
- Annotate (Arrow)
- Bidirectional
- Angle
The gear will output the following annotation properties if available in the tool type:
- Area
- Length
- Angle
- Units (of measurement)
- min/max X/Y coordinates of a bounding box of the annotation
- perpendicular min/max X/Y of a Bidirectional annotation
- ShortestDiameter/LongestDiameter of a Bidirectional annotation
Inputs
This gear has no file input. The exported form responses and annotations will depend on the level at which the gear is launched (e.g. project, subject, session, acquisition) and the confiugration options selected.
Config
- debug
- Type: boolean
- Description: Log debug messages
- Default: False
- protocol_name
- Type: string
- Description: The name of the protocol to export data from.
- Optional: True
- annotations-scope
- Type: string
- Description: The scope of the exported annotations.
- Default: task
- form-responses-scope
- Type: string
- Description: The scope of the form responses.
- Default: task
- read_timeout
- Type: integer
- Description: The maximum time in seconds to wait for a response from the server.
- Default: 60
Outputs
The Form and Annotations Exporter gear has the following outputs:
- form-responses-<datestamp>.csv
- annotations-<datestamp>.csv
For form responses and annotations that are coordinated with a task, the above outputs
will correspond to the same Task ID and the Location
column of the annotations CSV
will correspond to the matching Question
with a Answer
of yes
. The question will
take the form of <question #>: <Location>
(e.g. 2: LV
).
Both output CSV files are in a "narrow" format where each row represents a single form
response Question/Answer or annotation Property/Value pair. Each of these CSV files can
be converted to a "wide" format using the pandas
Python library with the pivot
command. A
data dictionary is provided for the CSV files.
Example Conversion to Wide Format
import pandas as pd
from pathlib import Path
root_dir = Path('~')
# Read in the CSV file
form_responses_path = root_dir / 'form-responses-2023-05-13_08-47-26.csv'
df = pd.read_csv(form_responses_path)
index_cols = [col for col in list(df.columns) if col not in ['Question', 'Answer']]
df_wide = df.pivot(index=index_cols, columns='Question', values='Answer').reset_index()
df_wide.to_csv(root / (form_responses_path.stem + '_wide.csv'))
# Read in the CSV file
annotations_path = root_dir / 'annotations-2023-05-13_08-47-26.csv'
df = pd.read_csv(annotations_path)
index_cols = [col for col in list(df.columns) if col not in ['Property', 'Value']]
df_wide = df.pivot(index=index_cols, columns='Property', values='Value').reset_index()
df_wide.to_csv(annotations_path.stem + '_wide.csv')
Example of Merging Form Responses and Annotations
import pandas as pd
annotations_wide_df = pd.read_csv('annotations-2023-05-13_08-47-26_wide.csv')
form_responses_wide_df = pd.read_csv('form-responses-2023-05-13_08-47-26_wide.csv')
# Ensure that the common columns have the same datatypes
form_responses_wide_df=form_responses_wide_df.astype(object)
annotations_wide_df=annotations_wide_df.astype(object)
# Get the common columns between the two dataframes
common_columns = set(annotations_wide_df.columns)
common_columns = list(common_columns.intersection(set(form_responses_wide_df.columns)))
common_columns = [
col for col in common_columns if col not in ['Created', 'Modified','Revision']
]
# Acquisition and File Name may not be common columns
common_columns = [
col
for col in common_columns
if col not in ["Acquisition Label", "acquisition.id", "File Name", "file.id"]
]
# Merge the two dataframes on the common columns
merged_df = pd.merge(
annotations_wide_df,
form_responses_wide_df,
on=list(common_columns),
how="outer"
)
# More than one annotation per task.id will produce multiple rows for the same task.id
merged_df.to_csv('merged_annotations_and_form_responses.csv')
The columns of each CSV output are described below.
form-responses-<datestamp>.csv
On form-response-scope being task
, non-task
, or both
and a non-empty response,
the gear will output a CSV file containing the form responses for the specified
protocol.
The file name will be prefixed with form-responses-
and suffixed with the datestamp
of the export (e.g. form-responses-2023-05-13_08-47-26.csv
). The CSV will contain the
following columns:
- Task ID: The ID of the task the form response is associated with (e.g. R-2-1)
- Task Type: The type of the task the form response is associated with (e.g. Read)
- Protocol Label: The label of the protocol the form response is associated with.
- Group: The group the form response is associated with.
- Project Label: The project label the form response is associated with.
- Subject Label: The subject label the form response is associated with.
- Session Label: The session label the form response is associated with.
- Session Timestamp: The timestamp of the session.
- Acquisition Label: The acquisition label the form response is associated with. Can be blank.
- File Name: The name of the file the form response is associated with. Can be blank.
- Task Assignee: The user who was assigned the task. Blank if non-task.
- Task Creator: The user who created the task. Blank if non-task.
- Task Due Date: The due date of the task. Blank if non-task.
- Task Status: The status of the task (e.g. Complete, Todo, In_Progress). Blank if non-task.
- Question: The text of a question (e.g. "What is the patient's age?")
- Answer: The answer to the question (e.g. "42")
- Created: The date the form response was created.
- Modified: The date the form response was last modified.
- Revision: The revision number of the form response.
- Url: The URL of the session the form response is associated with.
- group: The group.id.
- project.id: The ID of the project the form response is associated with.
- subject.id: The ID of the subject the form response is associated with.
- session.id: The ID of the session the form response is associated with.
- acquisition.id: The ID of the acquisition the form response is associated with.
- file.file_id: The ID of the file the form response is associated with.
- formresponse.id: The ID of the form response.
- form.id: The ID of the form the form response is associated with.
- task.id: The ID of the task the form response is associated with.
annotations-<datestamp>.csv
On annotations-scope being task
, non-task
, or both
and a non-empty response, the
gear willoutput a CSV file containing the annotations for the specified protocol.
The file name will be prefixed with annotations-
and suffixed with the datestamp
of the export (e.g. annotations-2023-05-13_08-47-26.csv
). The CSV will contain the
following columns:
- Task ID: The ID of the task the annotation is associated with (e.g. R-2-1)
- Task Type: The type of the task the annotation is associated with (e.g. Read)
- Group: The group the annotation is associated with.
- Project Label: The project label the annotation is associated with.
- Subject Label: The subject label the annotation is associated with.
- Session Label: The session label the annotation is associated with.
- Session Timestamp: The timestamp of the session the annotation is associated with.
- Acquisition Label: The acquisition label the annotation is associated with.
- File Name: The name of the file the annotation is associated with.
- Task Assignee: The user who was assigned the task. Blank if non-task annotation.
- Task Creator: The user who created the task. Blank if non-task annotation.
- Task Due Date: The due date of the task. Blank if non-task annotation.
- Task Status: The status of the task (e.g. Complete, Todo, In_Progress). Blank if non-task annotation.
- SliceNumber: The slice number of the image the annotation is drawn upon.
- Location: The label of the annotation. Corresponds to the label in the form-responses.
- Annotation ID: The ID of the annotation.
- Property: The name of the property being reported on (e.g "toolType", "Area")
- Value: The value of the property being reported on (e.g. "Length", "859.075")
- Created: The date the annotation was created.
- Modified: The date the annotation was last modified.
- Revision: The revision number of the annotation.
- frameIndex: The frame index of the annotation. This will be
0
for non-DICOM images and the slice number for DICOM images. - imagePath: This will be a
$$$
-separated string representing different attributes for DICOM and non-DICOM images.- For DICOM images, the format is
StudyInstanceUID$$$instancSeriesInstanceUIDeUID$$$SOPInstanceUID$$$frameIndex
. - For NIfTI images, the format is
fileName$$$Orientation$$$api-address#<slice_features>
. - For other image types please see the Flywheel Annotation Data Format wiki.
- For DICOM images, the format is
- group: The group the annotation is associated with.
- project.id: The ID of the project the annotation is associated with.
- subject.id: The ID of the subject the annotation is associated with.
- session.id: The ID of the session the annotation is associated with.
- acquisition.id: The ID of the acquisition the annotation is associated with.
- file.file_id: The ID of the file the annotation is associated with.
- File ID: The ID of the file the annotation is associated with.
- File Version: The version of the file the annotation is associated with.
- task.id: The ID of the task the annotation is associated with. Blank if non-task annotation.
Example of Retrieving Form-Responses from Session Variables
When session forms have been filled outside of the Reader Task Workflow (i.e.
using a ohif_config.json
stored that the project leve), the form
responses are stored in the session custom info variable (session.info
).
You can export the responses in 2 ways:
-
Using a DataView to export as columns the responses you need.
-
Using the SDK. For instance, the script below can be used to retrieve the form responses from the session info and convert them to a CSV file.
import flywheel
import os
import json
import pandas as pd
api_key = os.environ['FW_LATEST_KEY']
client = flywheel.Client(api_key)
group="your_group"
project_label="form_and_annotation_export_project"
project = client.lookup(f"{group}/{project_label}")
read_df = pd.DataFrame()
df_indx = 0
for session in project.sessions.iter():
info = session.reload().info
reads = info.get("ohifViewer", {}).get("read", {})
reader_keys = info.get("ohifViewer", {}).get("read", {}).keys()
for reader in reader_keys:
read_df.at[df_indx, "session_id"] = session.id
read_df.at[df_indx, "session_label"] = session.label
read_df.at[df_indx, "reader"] = reader
read_df.at[df_indx, "date"] = reads.get(reader, {}).get("date", {})
read_df.at[df_indx, "readTime"] = reads.get(reader, {}).get("readTime", {})
read_df.at[df_indx, "readStatus"] = reads.get(reader, {}).get("readStatus", {})
for k,v in reads.get(reader, {}).get("notes", {}).items():
read_df.at[df_indx, k] = v
df_indx += 1
read_df.to_csv("read_df.csv", index=False)
Cite
License: MIT
Contributing
For more information about how to get started contributing to that gear, checkout CONTRIBUTING.md.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
File details
Details for the file fw_gear_form_and_annotations_exporter-0.1.5-py3-none-any.whl
.
File metadata
- Download URL: fw_gear_form_and_annotations_exporter-0.1.5-py3-none-any.whl
- Upload date:
- Size: 18.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.8.3 CPython/3.9.19 Linux/5.15.154+
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 2f2fb8d97f6262c64d169c08cbc02a983b656ad4f2d80d3401284580f15019eb |
|
MD5 | 0771eb39f7910d15c7e1aac4ee131425 |
|
BLAKE2b-256 | 826249f6453df0495d5fe01a0199c4d002697d4642152c7ee71d961e27e5a6eb |