From c2f95a6be5e18cca587084763f384a4302c482dc Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Mon, 20 May 2024 19:56:18 -0400 Subject: [PATCH 01/31] refactor and deal with simple visbility --- .pre-commit-config.yaml | 10 +- ui/forms.py | 235 ++++++++++++++++++ ui/modules.py | 28 +++ ui/neurovault/README_eCOBIDAS-en.html | 139 +++++++++++ .../experimental_design_schema.jsonld | 129 ++++++++++ .../items/length_of_blocks.jsonld | 28 +++ .../items/length_of_runs.jsonld | 28 +++ .../items/length_of_trials.jsonld | 28 +++ .../items/number_of_experimental_units.jsonld | 20 ++ .../items/number_of_imaging_runs.jsonld | 20 ++ .../items/optimization.jsonld | 23 ++ .../items/optimization_method.jsonld | 17 ++ .../items/type_of_design.jsonld | 42 ++++ .../group_inference_schema.jsonld | 64 +++++ .../items/group_smoothness_fwhm.jsonld | 20 ++ .../items/group_statistic_parameters.jsonld | 20 ++ .../items/group_statistic_type.jsonld | 66 +++++ .../group_modeling_schema.jsonld | 116 +++++++++ .../items/group_estimation_type.jsonld | 36 +++ .../items/group_inference_type.jsonld | 42 ++++ .../items/group_model_multilevel.jsonld | 17 ++ .../items/group_model_type.jsonld | 30 +++ .../items/group_modeling_software.jsonld | 23 ++ .../items/group_repeated_measures.jsonld | 23 ++ .../group_repeated_measures_method.jsonld | 17 ++ .../individual_subject_modeling_schema.jsonld | 220 ++++++++++++++++ .../items/autocorrelation_model.jsonld | 17 ++ .../items/contrast_definition.jsonld | 17 ++ .../items/contrast_definition_cogatlas.jsonld | 17 ++ .../hemodynamic_response_function.jsonld | 42 ++++ .../items/high_pass_filter_method.jsonld | 17 ++ .../items/intrasubject_estimation_type.jsonld | 36 +++ .../items/intrasubject_model_type.jsonld | 30 +++ .../intrasubject_modeling_software.jsonld | 23 ++ .../orthogonalization_description.jsonld | 17 ++ .../items/used_dispersion_derivatives.jsonld | 23 ++ .../items/used_high_pass_filter.jsonld | 23 ++ .../items/used_motion_regressors.jsonld | 23 ++ .../items/used_orthogonalization.jsonld | 23 ++ .../items/used_reaction_time_regressor.jsonld | 23 ++ .../items/used_temporal_derivatives.jsonld | 23 ++ .../intersubject_registration_schema.jsonld | 233 +++++++++++++++++ .../items/coordinate_space.jsonld | 42 ++++ ...nctional_coregistered_to_structural.jsonld | 23 ++ .../functional_coregistration_method.jsonld | 17 ++ .../items/interpolation_method.jsonld | 23 ++ .../intersubject_registration_software.jsonld | 23 ++ .../intersubject_transformation_type.jsonld | 36 +++ .../items/nonlinear_transform_type.jsonld | 17 ++ .../items/object_image_type.jsonld | 17 ++ .../items/resampled_voxel_size.jsonld | 20 ++ .../items/smoothing_fwhm.jsonld | 28 +++ .../items/smoothing_type.jsonld | 21 ++ .../items/target_resolution.jsonld | 28 +++ .../items/target_template_image.jsonld | 17 ++ .../items/transform_similarity_metric.jsonld | 17 ++ .../used_intersubject_registration.jsonld | 23 ++ .../items/used_smoothing.jsonld | 23 ++ .../mri_acquisition/items/EchoTime.jsonld | 28 +++ .../mri_acquisition/items/FlipAngle.jsonld | 28 +++ .../items/MagneticFieldStrength.jsonld | 28 +++ .../mri_acquisition/items/Manufacturer.jsonld | 42 ++++ .../items/ManufacturersModelName.jsonld | 17 ++ .../items/PulseSequenceType.jsonld | 60 +++++ .../items/RepetitionTime.jsonld | 28 +++ .../mri_acquisition/items/SliceTiming.jsonld | 42 ++++ .../items/acquisition_orientation.jsonld | 42 ++++ .../items/field_of_view.jsonld | 28 +++ .../mri_acquisition/items/matrix_size.jsonld | 20 ++ .../items/parallel_imaging.jsonld | 17 ++ .../mri_acquisition/items/skip_factor.jsonld | 28 +++ .../items/slice_thickness.jsonld | 28 +++ .../mri_acquisition_schema.jsonld | 207 +++++++++++++++ .../items/group_comparison.jsonld | 23 ++ .../items/group_description.jsonld | 17 ++ .../participants/items/handedness.jsonld | 42 ++++ .../items/inclusion_exclusion_criteria.jsonld | 17 ++ .../items/number_of_rejected_subjects.jsonld | 20 ++ .../items/number_of_subjects.jsonld | 20 ++ .../items/proportion_male_subjects.jsonld | 145 +++++++++++ .../participants/items/subject_age_max.jsonld | 20 ++ .../items/subject_age_mean.jsonld | 20 ++ .../participants/items/subject_age_min.jsonld | 20 ++ .../participants/participants_schema.jsonld | 155 ++++++++++++ .../preprocessing/items/SoftwareName.jsonld | 23 ++ .../items/SoftwareVersion.jsonld | 17 ++ .../items/b0_unwarping_software.jsonld | 23 ++ .../motion_correction_interpolation.jsonld | 23 ++ .../items/motion_correction_metric.jsonld | 23 ++ .../items/motion_correction_reference.jsonld | 17 ++ .../items/motion_correction_software.jsonld | 23 ++ .../order_of_preprocessing_operations.jsonld | 17 ++ .../items/quality_control.jsonld | 17 ++ .../slice_timing_correction_software.jsonld | 17 ++ .../items/used_b0_unwarping.jsonld | 23 ++ .../items/used_motion_correction.jsonld | 23 ++ ...sed_motion_susceptibiity_correction.jsonld | 23 ++ .../items/used_slice_timing_correction.jsonld | 23 ++ .../preprocessing/preprocessing_schema.jsonld | 207 +++++++++++++++ .../protocols/neurovault_schema.jsonld | 133 ++++++++++ ui/requirements.txt | 3 + ui/templates/404.html | 14 ++ ui/templates/500.html | 14 ++ ui/templates/about.html | 1 + ui/templates/activity.html | 14 ++ ui/templates/base.html | 52 ++++ ui/templates/index.html | 18 ++ 107 files changed, 4292 insertions(+), 1 deletion(-) create mode 100644 ui/forms.py create mode 100644 ui/modules.py create mode 100644 ui/neurovault/README_eCOBIDAS-en.html create mode 100644 ui/neurovault/activities/experimental_design/experimental_design_schema.jsonld create mode 100644 ui/neurovault/activities/experimental_design/items/length_of_blocks.jsonld create mode 100644 ui/neurovault/activities/experimental_design/items/length_of_runs.jsonld create mode 100644 ui/neurovault/activities/experimental_design/items/length_of_trials.jsonld create mode 100644 ui/neurovault/activities/experimental_design/items/number_of_experimental_units.jsonld create mode 100644 ui/neurovault/activities/experimental_design/items/number_of_imaging_runs.jsonld create mode 100644 ui/neurovault/activities/experimental_design/items/optimization.jsonld create mode 100644 ui/neurovault/activities/experimental_design/items/optimization_method.jsonld create mode 100644 ui/neurovault/activities/experimental_design/items/type_of_design.jsonld create mode 100644 ui/neurovault/activities/group_inference/group_inference_schema.jsonld create mode 100644 ui/neurovault/activities/group_inference/items/group_smoothness_fwhm.jsonld create mode 100644 ui/neurovault/activities/group_inference/items/group_statistic_parameters.jsonld create mode 100644 ui/neurovault/activities/group_inference/items/group_statistic_type.jsonld create mode 100644 ui/neurovault/activities/group_modeling/group_modeling_schema.jsonld create mode 100644 ui/neurovault/activities/group_modeling/items/group_estimation_type.jsonld create mode 100644 ui/neurovault/activities/group_modeling/items/group_inference_type.jsonld create mode 100644 ui/neurovault/activities/group_modeling/items/group_model_multilevel.jsonld create mode 100644 ui/neurovault/activities/group_modeling/items/group_model_type.jsonld create mode 100644 ui/neurovault/activities/group_modeling/items/group_modeling_software.jsonld create mode 100644 ui/neurovault/activities/group_modeling/items/group_repeated_measures.jsonld create mode 100644 ui/neurovault/activities/group_modeling/items/group_repeated_measures_method.jsonld create mode 100644 ui/neurovault/activities/individual_subject_modeling/individual_subject_modeling_schema.jsonld create mode 100644 ui/neurovault/activities/individual_subject_modeling/items/autocorrelation_model.jsonld create mode 100644 ui/neurovault/activities/individual_subject_modeling/items/contrast_definition.jsonld create mode 100644 ui/neurovault/activities/individual_subject_modeling/items/contrast_definition_cogatlas.jsonld create mode 100644 ui/neurovault/activities/individual_subject_modeling/items/hemodynamic_response_function.jsonld create mode 100644 ui/neurovault/activities/individual_subject_modeling/items/high_pass_filter_method.jsonld create mode 100644 ui/neurovault/activities/individual_subject_modeling/items/intrasubject_estimation_type.jsonld create mode 100644 ui/neurovault/activities/individual_subject_modeling/items/intrasubject_model_type.jsonld create mode 100644 ui/neurovault/activities/individual_subject_modeling/items/intrasubject_modeling_software.jsonld create mode 100644 ui/neurovault/activities/individual_subject_modeling/items/orthogonalization_description.jsonld create mode 100644 ui/neurovault/activities/individual_subject_modeling/items/used_dispersion_derivatives.jsonld create mode 100644 ui/neurovault/activities/individual_subject_modeling/items/used_high_pass_filter.jsonld create mode 100644 ui/neurovault/activities/individual_subject_modeling/items/used_motion_regressors.jsonld create mode 100644 ui/neurovault/activities/individual_subject_modeling/items/used_orthogonalization.jsonld create mode 100644 ui/neurovault/activities/individual_subject_modeling/items/used_reaction_time_regressor.jsonld create mode 100644 ui/neurovault/activities/individual_subject_modeling/items/used_temporal_derivatives.jsonld create mode 100644 ui/neurovault/activities/intersubject_registration/intersubject_registration_schema.jsonld create mode 100644 ui/neurovault/activities/intersubject_registration/items/coordinate_space.jsonld create mode 100644 ui/neurovault/activities/intersubject_registration/items/functional_coregistered_to_structural.jsonld create mode 100644 ui/neurovault/activities/intersubject_registration/items/functional_coregistration_method.jsonld create mode 100644 ui/neurovault/activities/intersubject_registration/items/interpolation_method.jsonld create mode 100644 ui/neurovault/activities/intersubject_registration/items/intersubject_registration_software.jsonld create mode 100644 ui/neurovault/activities/intersubject_registration/items/intersubject_transformation_type.jsonld create mode 100644 ui/neurovault/activities/intersubject_registration/items/nonlinear_transform_type.jsonld create mode 100644 ui/neurovault/activities/intersubject_registration/items/object_image_type.jsonld create mode 100644 ui/neurovault/activities/intersubject_registration/items/resampled_voxel_size.jsonld create mode 100644 ui/neurovault/activities/intersubject_registration/items/smoothing_fwhm.jsonld create mode 100644 ui/neurovault/activities/intersubject_registration/items/smoothing_type.jsonld create mode 100644 ui/neurovault/activities/intersubject_registration/items/target_resolution.jsonld create mode 100644 ui/neurovault/activities/intersubject_registration/items/target_template_image.jsonld create mode 100644 ui/neurovault/activities/intersubject_registration/items/transform_similarity_metric.jsonld create mode 100644 ui/neurovault/activities/intersubject_registration/items/used_intersubject_registration.jsonld create mode 100644 ui/neurovault/activities/intersubject_registration/items/used_smoothing.jsonld create mode 100644 ui/neurovault/activities/mri_acquisition/items/EchoTime.jsonld create mode 100644 ui/neurovault/activities/mri_acquisition/items/FlipAngle.jsonld create mode 100644 ui/neurovault/activities/mri_acquisition/items/MagneticFieldStrength.jsonld create mode 100644 ui/neurovault/activities/mri_acquisition/items/Manufacturer.jsonld create mode 100644 ui/neurovault/activities/mri_acquisition/items/ManufacturersModelName.jsonld create mode 100644 ui/neurovault/activities/mri_acquisition/items/PulseSequenceType.jsonld create mode 100644 ui/neurovault/activities/mri_acquisition/items/RepetitionTime.jsonld create mode 100644 ui/neurovault/activities/mri_acquisition/items/SliceTiming.jsonld create mode 100644 ui/neurovault/activities/mri_acquisition/items/acquisition_orientation.jsonld create mode 100644 ui/neurovault/activities/mri_acquisition/items/field_of_view.jsonld create mode 100644 ui/neurovault/activities/mri_acquisition/items/matrix_size.jsonld create mode 100644 ui/neurovault/activities/mri_acquisition/items/parallel_imaging.jsonld create mode 100644 ui/neurovault/activities/mri_acquisition/items/skip_factor.jsonld create mode 100644 ui/neurovault/activities/mri_acquisition/items/slice_thickness.jsonld create mode 100644 ui/neurovault/activities/mri_acquisition/mri_acquisition_schema.jsonld create mode 100644 ui/neurovault/activities/participants/items/group_comparison.jsonld create mode 100644 ui/neurovault/activities/participants/items/group_description.jsonld create mode 100644 ui/neurovault/activities/participants/items/handedness.jsonld create mode 100644 ui/neurovault/activities/participants/items/inclusion_exclusion_criteria.jsonld create mode 100644 ui/neurovault/activities/participants/items/number_of_rejected_subjects.jsonld create mode 100644 ui/neurovault/activities/participants/items/number_of_subjects.jsonld create mode 100644 ui/neurovault/activities/participants/items/proportion_male_subjects.jsonld create mode 100644 ui/neurovault/activities/participants/items/subject_age_max.jsonld create mode 100644 ui/neurovault/activities/participants/items/subject_age_mean.jsonld create mode 100644 ui/neurovault/activities/participants/items/subject_age_min.jsonld create mode 100644 ui/neurovault/activities/participants/participants_schema.jsonld create mode 100644 ui/neurovault/activities/preprocessing/items/SoftwareName.jsonld create mode 100644 ui/neurovault/activities/preprocessing/items/SoftwareVersion.jsonld create mode 100644 ui/neurovault/activities/preprocessing/items/b0_unwarping_software.jsonld create mode 100644 ui/neurovault/activities/preprocessing/items/motion_correction_interpolation.jsonld create mode 100644 ui/neurovault/activities/preprocessing/items/motion_correction_metric.jsonld create mode 100644 ui/neurovault/activities/preprocessing/items/motion_correction_reference.jsonld create mode 100644 ui/neurovault/activities/preprocessing/items/motion_correction_software.jsonld create mode 100644 ui/neurovault/activities/preprocessing/items/order_of_preprocessing_operations.jsonld create mode 100644 ui/neurovault/activities/preprocessing/items/quality_control.jsonld create mode 100644 ui/neurovault/activities/preprocessing/items/slice_timing_correction_software.jsonld create mode 100644 ui/neurovault/activities/preprocessing/items/used_b0_unwarping.jsonld create mode 100644 ui/neurovault/activities/preprocessing/items/used_motion_correction.jsonld create mode 100644 ui/neurovault/activities/preprocessing/items/used_motion_susceptibiity_correction.jsonld create mode 100644 ui/neurovault/activities/preprocessing/items/used_slice_timing_correction.jsonld create mode 100644 ui/neurovault/activities/preprocessing/preprocessing_schema.jsonld create mode 100644 ui/neurovault/protocols/neurovault_schema.jsonld create mode 100644 ui/requirements.txt create mode 100644 ui/templates/404.html create mode 100644 ui/templates/500.html create mode 100644 ui/templates/about.html create mode 100644 ui/templates/activity.html create mode 100644 ui/templates/base.html create mode 100644 ui/templates/index.html diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 47807bb2..5cc96985 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -76,6 +76,14 @@ repos: # additional_dependencies: [types-all, pandas-stubs] # args: [--config-file=pyproject.toml] +# Check formatting of CSS and HTML +# prettier: https://prettier.io/ +- repo: https://github.com/pre-commit/mirrors-prettier + rev: v4.0.0-alpha.8 + hooks: + - id: prettier + types_or: [css, html] + # Check that Python code complies with PEP8 guidelines # flake8 uses pydocstyle to check docstrings: https://flake8.pycqa.org/en/latest/ # flake8-docstrings: https://pypi.org/project/flake8-docstrings/ @@ -86,5 +94,5 @@ repos: rev: 7.0.0 hooks: - id: flake8 - args: [--config, .flake8, --verbose, ecobidas, tests, macros] + args: [--config, .flake8, --verbose, ecobidas, tests, macros, ui] additional_dependencies: [flake8-docstrings, flake8-use-fstring, flake8-functions, flake8-bugbear] diff --git a/ui/forms.py b/ui/forms.py new file mode 100644 index 00000000..15a228c7 --- /dev/null +++ b/ui/forms.py @@ -0,0 +1,235 @@ +from functools import lru_cache + +import requests +from flask import Flask, render_template +from flask_bootstrap import Bootstrap5 +from flask_wtf import CSRFProtect, FlaskForm +from markupsafe import Markup, escape +from modules import activity_url, get_activity, get_item +from rich import print +from wtforms import ( + DecimalField, + HiddenField, + IntegerField, + MultipleFileField, + RadioField, + SelectField, + StringField, + SubmitField, + TextAreaField, +) +from wtforms.validators import DataRequired + +LANG = "en" + +app = Flask(__name__) +app.secret_key = "tO$&!|0wkamvVia0?n$NqIRVWOG" + +# Bootstrap-Flask requires this line +bootstrap = Bootstrap5(app) + +# Flask-WTF requires this line +csrf = CSRFProtect(app) + + +class DyanmicForm(FlaskForm): + pass + + +@lru_cache +def query_choices(url): + try: + data = requests.get(url).json() + except Exception as exc: + print(exc) + data = None + return data + + +@app.route("/", methods=["GET", "POST"]) +def index(): + return render_template("index.html") + + +@app.route("/about") +def about(): + return render_template("about.html") + + +@app.route("//", methods=["GET", "POST"]) +def activity(protocol_name, activity_name): + protocol_name = escape(protocol_name) + activity_name = escape(activity_name) + + activity = get_activity(protocol_name, activity_name) + + items = get_items_for_activity(protocol_name, activity_name) + + form = generate_form(items) + + if form.validate_on_submit(): + for item, values in items.items(): + isVis = values["isVis"] + if isinstance(isVis, str): + isVis = isVis.replace(" ", "").split("==") + if len(isVis) == 2: + response = form[isVis[0]].data + value = items[isVis[0]]["choices"].get(response) + expected = int(isVis[1]) + items[item]["visibility"] = value == expected + + form = generate_form(items) + + return render_template( + "activity.html", + prefLabel=activity["prefLabel"][LANG], + preamble=Markup(activity["preamble"][LANG]), + form=form, + ) + + return render_template( + "activity.html", + prefLabel=activity["prefLabel"][LANG], + preamble=Markup(activity["preamble"][LANG]), + form=form, + ) + + +def generate_form(items): + for item_name, item in items.items(): + + validators = [] + if item["required"]: + validators.append(DataRequired()) + + question = f"{item['question']} {item['unit']}" + + if not item["visibility"]: + setattr( + DyanmicForm, + item_name, + HiddenField( + Markup(question), + validators=validators, + description=item["description"], + ), + ) + continue + + input_type = item["input_type"] + + if input_type not in ["select", "radio", "slider"]: + + FieldType = StringField + if input_type == "number": + FieldType = IntegerField + elif input_type in ["float", "slider"]: + FieldType = DecimalField + elif input_type == "textarea": + FieldType = TextAreaField + + setattr( + DyanmicForm, + item_name, + FieldType( + Markup(question), + validators=validators, + description=item["description"], + ), + ) + + else: + + is_multiple = item["is_multiple"] + + if is_multiple: + FieldType = MultipleFileField + if input_type == "select": + FieldType = SelectField + elif input_type == "radio": + FieldType = RadioField + + setattr( + DyanmicForm, + item_name, + FieldType( + Markup(question), + validators=validators, + description=item["description"], + choices=[key for key in item["choices"]], + ), + ) + + setattr(DyanmicForm, "submit", SubmitField("Submit")) # noqa B010 + + return DyanmicForm() + + +def get_items_for_activity(protocol_name, activity_name): + # TODO make sure items are presented in the right order + activity = get_activity(protocol_name, activity_name) + items = {} + for item in activity["ui"]["addProperties"]: + + item_name = item["variableName"] + + item_data = get_item(activity_url(protocol_name, activity_name).parent / item["isAbout"]) + + tmp = { + "visibility": False, + "required": False, + "isVis": item["isVis"], + "choices": get_choices(item_data), + } + + tmp["description"] = item_data.get("description") + tmp["question"] = item_data["question"][LANG] + tmp["input_type"] = item_data["ui"]["inputType"] + + if item["isVis"] == 1: + tmp["visibility"] = True + + if item["requiredValue"]: + tmp["required"] = True + + try: + unit = f"({item_data['responseOptions']['unitOptions'][0]['prefLabel'][LANG]})" + except KeyError: + unit = "" + tmp["unit"] = unit + + try: + is_multiple = item_data["responseOptions"].get("multipleChoice", False) + except KeyError: + is_multiple = False + tmp["is_multiple"] = is_multiple + + items[item_name] = tmp + + return items + + +def get_choices(item_data): + try: + choices = item_data["responseOptions"]["choices"] + if isinstance(choices, str): + choices = query_choices(choices)["choices"] + choices = {x["name"][LANG]: x["value"] for x in choices} + except KeyError: + choices = {} + return choices + + +@app.errorhandler(404) +def page_not_found(e): + return render_template("404.html"), 404 + + +@app.errorhandler(500) +def internal_server_error(e): + return render_template("500.html"), 500 + + +# keep this as is +if __name__ == "__main__": + app.run(debug=True) diff --git a/ui/modules.py b/ui/modules.py new file mode 100644 index 00000000..72b4053b --- /dev/null +++ b/ui/modules.py @@ -0,0 +1,28 @@ +# functions to be used by the routes +import json +from pathlib import Path + + +def activity_url(protocol_name, activity_name): + return ( + Path(__file__).parents[1] + / "cobidas_schema" + / "schemas" + / protocol_name + / "activities" + / activity_name + / f"{activity_name}_schema.jsonld" + ) + + +def get_activity(protocol_name, activity_name): + file = activity_url(protocol_name, activity_name) + with open(file) as f: + content = json.load(f) + return content + + +def get_item(file): + with open(file) as f: + content = json.load(f) + return content diff --git a/ui/neurovault/README_eCOBIDAS-en.html b/ui/neurovault/README_eCOBIDAS-en.html new file mode 100644 index 00000000..5d398bc2 --- /dev/null +++ b/ui/neurovault/README_eCOBIDAS-en.html @@ -0,0 +1,139 @@ +
+
+

COBIDAS Information Collection Protocol

+

+ The aim of this protocol is to help users collect information related to + the different components of the COBIDAS protocol. +

+

How to use it

+

+ You can navigate each section on the left and then answer the questions + corresponding to your fMRI analysis. This is meant to make sure that you + have not forgotten any of the essential information in the methods and + results parts of your article. +

+

+ At the end, you can click on Export (bottom left) to get a zip file + containing machine readable json files that captures information about + your method/results section: our next step is to use this to automate the + part of the methods writing and to submit the information alongside data + submission to Neurovault and other data archives. +

+

Have any questions? Something is missing? Let us know.

+ +

Why this project?

+

+ Poor methods and results description hinders the reproducibility and the + replicability of research. It also makes it hard to compare new and old + results and generally increases inefficiency in the research process. This + project is built on the hope that improving methods and results reporting + could improve our research. +

+

+ Follow the link if you want to know more about the + motivations behind this project. +

+

Background

+

+ This checklist is a project to make a user friendly checklist out the best + practices + report of + the Committee on Best Practices in Data Analysis and Sharing (COBIDAS) of the + Organization for Human Brain Mapping. +

+

+ This is very much of a work in progress but the next step is to expand the + list to cover all the items of the COBIDAS report for fMRI as well as for + the recent + extension to EEG and MEG. +

+

Want to help?

+

+ We are currently working on trying to expand the number of items used in + the checklist. All of this work is done in google spreadsheets: the + spreadsheet for each section is accessible by clicking on the + Source + at the top of each page. +

+

Want to know more?

+

+ Most of the information concerning this project can be found on this + github repository. +

+

+ If you want to be kept posted about the progress of the project, you can + join our + google group +

+

+ From more frequent updates and behind the scenes, come and join us on the + cobidas_checklist channel on the brainhack + + + channel. + +

+

+ There is also an [OSF project](https://osf.io/anvqy/) to centralize all + the information and repos. +

+

+ We have a + list + of short, middle, long term goals: if you are interested by any of those + get in touch. Many of them do not necessarily require super-advanced + technical skills (except maybe a certain love for working with spreadsheet + and wanting them to be super organized). +

+

Contributors

+

+ The list of the people involved in this project can be found + here. +

+

License

+

The protocol is licensed CC-BY-4.0

+

(c) 2020 COBIDAS Contributors

+
+
diff --git a/ui/neurovault/activities/experimental_design/experimental_design_schema.jsonld b/ui/neurovault/activities/experimental_design/experimental_design_schema.jsonld new file mode 100644 index 00000000..0b3bac44 --- /dev/null +++ b/ui/neurovault/activities/experimental_design/experimental_design_schema.jsonld @@ -0,0 +1,129 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Activity", + "@id": "experimental_design_schema.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "Experimental design" + }, + "description": "experimental design", + "preamble": { + "en": "

Source | Github repository | Reference

Describe your experimental design

" + }, + "ui": { + "shuffle": false, + "order": [ + "items/type_of_design.jsonld", + "items/number_of_imaging_runs.jsonld", + "items/number_of_experimental_units.jsonld", + "items/length_of_runs.jsonld", + "items/length_of_blocks.jsonld", + "items/length_of_trials.jsonld", + "items/optimization.jsonld", + "items/optimization_method.jsonld" + ], + "addProperties": [ + { + "variableName": "type_of_design", + "isAbout": "items/type_of_design.jsonld", + "prefLabel": { + "en": "type of design" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "number_of_imaging_runs", + "isAbout": "items/number_of_imaging_runs.jsonld", + "prefLabel": { + "en": "number of imaging runs" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "number_of_experimental_units", + "isAbout": "items/number_of_experimental_units.jsonld", + "prefLabel": { + "en": "number of experimental units" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "length_of_runs", + "isAbout": "items/length_of_runs.jsonld", + "prefLabel": { + "en": "length of runs" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "length_of_blocks", + "isAbout": "items/length_of_blocks.jsonld", + "prefLabel": { + "en": "length of blocks" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "length_of_trials", + "isAbout": "items/length_of_trials.jsonld", + "prefLabel": { + "en": "length of trials" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "optimization", + "isAbout": "items/optimization.jsonld", + "prefLabel": { + "en": "optimization" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "optimization_method", + "isAbout": "items/optimization_method.jsonld", + "prefLabel": { + "en": "optimization method" + }, + "isVis": "optimization == 1", + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + } + ], + "allow": [ + "reproschema:AutoAdvance", + "reproschema:AllowExport" + ] + } +} diff --git a/ui/neurovault/activities/experimental_design/items/length_of_blocks.jsonld b/ui/neurovault/activities/experimental_design/items/length_of_blocks.jsonld new file mode 100644 index 00000000..8e5f97a2 --- /dev/null +++ b/ui/neurovault/activities/experimental_design/items/length_of_blocks.jsonld @@ -0,0 +1,28 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "length_of_blocks.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "length of blocks" + }, + "description": "length of blocks", + "ui": { + "inputType": "float" + }, + "question": { + "en": "1.5 - For blocked designs, length of blocks" + }, + "responseOptions": { + "valueType": "xsd:float", + "unitOptions": [ + { + "prefLabel": { + "en": "seconds" + }, + "value": "seconds" + } + ] + } +} diff --git a/ui/neurovault/activities/experimental_design/items/length_of_runs.jsonld b/ui/neurovault/activities/experimental_design/items/length_of_runs.jsonld new file mode 100644 index 00000000..95a04ab0 --- /dev/null +++ b/ui/neurovault/activities/experimental_design/items/length_of_runs.jsonld @@ -0,0 +1,28 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "length_of_runs.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "length of runs" + }, + "description": "length of runs", + "ui": { + "inputType": "float" + }, + "question": { + "en": "1.4 - Length of each imaging run" + }, + "responseOptions": { + "valueType": "xsd:float", + "unitOptions": [ + { + "prefLabel": { + "en": "seconds" + }, + "value": "seconds" + } + ] + } +} diff --git a/ui/neurovault/activities/experimental_design/items/length_of_trials.jsonld b/ui/neurovault/activities/experimental_design/items/length_of_trials.jsonld new file mode 100644 index 00000000..27e04f68 --- /dev/null +++ b/ui/neurovault/activities/experimental_design/items/length_of_trials.jsonld @@ -0,0 +1,28 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "length_of_trials.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "length of trials" + }, + "description": "length of trials", + "ui": { + "inputType": "float" + }, + "question": { + "en": "1.6 - Length of individual trials" + }, + "responseOptions": { + "valueType": "xsd:float", + "unitOptions": [ + { + "prefLabel": { + "en": "seconds" + }, + "value": "seconds" + } + ] + } +} diff --git a/ui/neurovault/activities/experimental_design/items/number_of_experimental_units.jsonld b/ui/neurovault/activities/experimental_design/items/number_of_experimental_units.jsonld new file mode 100644 index 00000000..e1e4230f --- /dev/null +++ b/ui/neurovault/activities/experimental_design/items/number_of_experimental_units.jsonld @@ -0,0 +1,20 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "number_of_experimental_units.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "number of experimental units" + }, + "description": "number of experimental units", + "ui": { + "inputType": "number" + }, + "question": { + "en": "1.3 - Number of blocks, trials or experimental units per imaging run" + }, + "responseOptions": { + "valueType": "xsd:integer" + } +} diff --git a/ui/neurovault/activities/experimental_design/items/number_of_imaging_runs.jsonld b/ui/neurovault/activities/experimental_design/items/number_of_imaging_runs.jsonld new file mode 100644 index 00000000..c7068816 --- /dev/null +++ b/ui/neurovault/activities/experimental_design/items/number_of_imaging_runs.jsonld @@ -0,0 +1,20 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "number_of_imaging_runs.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "number of imaging runs" + }, + "description": "number of imaging runs", + "ui": { + "inputType": "number" + }, + "question": { + "en": "1.2 - Number of imaging runs acquired" + }, + "responseOptions": { + "valueType": "xsd:integer" + } +} diff --git a/ui/neurovault/activities/experimental_design/items/optimization.jsonld b/ui/neurovault/activities/experimental_design/items/optimization.jsonld new file mode 100644 index 00000000..0185848b --- /dev/null +++ b/ui/neurovault/activities/experimental_design/items/optimization.jsonld @@ -0,0 +1,23 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "optimization.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "optimization" + }, + "description": "optimization", + "ui": { + "inputType": "radio" + }, + "question": { + "en": "1.7 - Was the design optimized for efficiency?" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": "https://raw.githubusercontent.com/ohbm/cobidas_schema/master/response_options/boolean.jsonld", + "minValue": 0, + "maxValue": 0 + } +} diff --git a/ui/neurovault/activities/experimental_design/items/optimization_method.jsonld b/ui/neurovault/activities/experimental_design/items/optimization_method.jsonld new file mode 100644 index 00000000..9cf95519 --- /dev/null +++ b/ui/neurovault/activities/experimental_design/items/optimization_method.jsonld @@ -0,0 +1,17 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "optimization_method.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "optimization method" + }, + "description": "optimization method", + "ui": { + "inputType": "textarea" + }, + "question": { + "en": "1.8 - What method was used for optimization?" + } +} diff --git a/ui/neurovault/activities/experimental_design/items/type_of_design.jsonld b/ui/neurovault/activities/experimental_design/items/type_of_design.jsonld new file mode 100644 index 00000000..3412df98 --- /dev/null +++ b/ui/neurovault/activities/experimental_design/items/type_of_design.jsonld @@ -0,0 +1,42 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "type_of_design.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "type of design" + }, + "description": "type of design", + "ui": { + "inputType": "select" + }, + "question": { + "en": "1.1 - Type of design" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": { + "en": "blocked" + }, + "value": 0 + }, + { + "name": { + "en": "event_related" + }, + "value": 1 + }, + { + "name": { + "en": "hybrid block/event" + }, + "value": 2 + } + ], + "minValue": 0, + "maxValue": 2 + } +} diff --git a/ui/neurovault/activities/group_inference/group_inference_schema.jsonld b/ui/neurovault/activities/group_inference/group_inference_schema.jsonld new file mode 100644 index 00000000..127118bc --- /dev/null +++ b/ui/neurovault/activities/group_inference/group_inference_schema.jsonld @@ -0,0 +1,64 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Activity", + "@id": "group_inference_schema.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "Group inference" + }, + "description": "group inference", + "preamble": { + "en": "

Source | Github repository | Reference

Describe your statistical inference

" + }, + "ui": { + "shuffle": false, + "order": [ + "items/group_statistic_type.jsonld", + "items/group_statistic_parameters.jsonld", + "items/group_smoothness_fwhm.jsonld" + ], + "addProperties": [ + { + "variableName": "group_statistic_type", + "isAbout": "items/group_statistic_type.jsonld", + "prefLabel": { + "en": "group statistic type" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "group_statistic_parameters", + "isAbout": "items/group_statistic_parameters.jsonld", + "prefLabel": { + "en": "group statistic parameters" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "group_smoothness_fwhm", + "isAbout": "items/group_smoothness_fwhm.jsonld", + "prefLabel": { + "en": "group smoothness fwhm" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + } + ], + "allow": [ + "reproschema:AutoAdvance", + "reproschema:AllowExport" + ] + } +} diff --git a/ui/neurovault/activities/group_inference/items/group_smoothness_fwhm.jsonld b/ui/neurovault/activities/group_inference/items/group_smoothness_fwhm.jsonld new file mode 100644 index 00000000..ef28a28a --- /dev/null +++ b/ui/neurovault/activities/group_inference/items/group_smoothness_fwhm.jsonld @@ -0,0 +1,20 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "group_smoothness_fwhm.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "group smoothness fwhm" + }, + "description": "group smoothness fwhm", + "ui": { + "inputType": "float" + }, + "question": { + "en": "8.3 - Noise smoothness for statistical inference
details
This is the estimated smoothness used with Random Field Theory or a simulation-based inference method.
" + }, + "responseOptions": { + "valueType": "xsd:float" + } +} diff --git a/ui/neurovault/activities/group_inference/items/group_statistic_parameters.jsonld b/ui/neurovault/activities/group_inference/items/group_statistic_parameters.jsonld new file mode 100644 index 00000000..a1ed7109 --- /dev/null +++ b/ui/neurovault/activities/group_inference/items/group_statistic_parameters.jsonld @@ -0,0 +1,20 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "group_statistic_parameters.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "group statistic parameters" + }, + "description": "group statistic parameters", + "ui": { + "inputType": "float" + }, + "question": { + "en": "8.2 - Parameters of the null distribution of the test statisic.
details
Typically degrees of freedom (should be clear from the test statistic what these are).
" + }, + "responseOptions": { + "valueType": "xsd:float" + } +} diff --git a/ui/neurovault/activities/group_inference/items/group_statistic_type.jsonld b/ui/neurovault/activities/group_inference/items/group_statistic_type.jsonld new file mode 100644 index 00000000..3975092f --- /dev/null +++ b/ui/neurovault/activities/group_inference/items/group_statistic_type.jsonld @@ -0,0 +1,66 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "group_statistic_type.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "group statistic type" + }, + "description": "group statistic type", + "ui": { + "inputType": "select" + }, + "question": { + "en": "8.1 - Type of statistic that is the basis of the inference" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": { + "en": "Z" + }, + "value": 0 + }, + { + "name": { + "en": "T" + }, + "value": 1 + }, + { + "name": { + "en": "F" + }, + "value": 2 + }, + { + "name": { + "en": "X2" + }, + "value": 3 + }, + { + "name": { + "en": "PostProb" + }, + "value": 4 + }, + { + "name": { + "en": "NonparametricP" + }, + "value": 5 + }, + { + "name": { + "en": "MonteCarloP" + }, + "value": 6 + } + ], + "minValue": 0, + "maxValue": 6 + } +} diff --git a/ui/neurovault/activities/group_modeling/group_modeling_schema.jsonld b/ui/neurovault/activities/group_modeling/group_modeling_schema.jsonld new file mode 100644 index 00000000..5b99bca4 --- /dev/null +++ b/ui/neurovault/activities/group_modeling/group_modeling_schema.jsonld @@ -0,0 +1,116 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Activity", + "@id": "group_modeling_schema.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "Group modeling" + }, + "description": "group modeling", + "preamble": { + "en": "

Source | Github repository | Reference

Describe the group level analysis

" + }, + "ui": { + "shuffle": false, + "order": [ + "items/group_model_type.jsonld", + "items/group_estimation_type.jsonld", + "items/group_modeling_software.jsonld", + "items/group_inference_type.jsonld", + "items/group_model_multilevel.jsonld", + "items/group_repeated_measures.jsonld", + "items/group_repeated_measures_method.jsonld" + ], + "addProperties": [ + { + "variableName": "group_model_type", + "isAbout": "items/group_model_type.jsonld", + "prefLabel": { + "en": "group model type" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "group_estimation_type", + "isAbout": "items/group_estimation_type.jsonld", + "prefLabel": { + "en": "group estimation type" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "group_modeling_software", + "isAbout": "items/group_modeling_software.jsonld", + "prefLabel": { + "en": "group modeling software" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "group_inference_type", + "isAbout": "items/group_inference_type.jsonld", + "prefLabel": { + "en": "group inference type" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "group_model_multilevel", + "isAbout": "items/group_model_multilevel.jsonld", + "prefLabel": { + "en": "group model multilevel" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "group_repeated_measures", + "isAbout": "items/group_repeated_measures.jsonld", + "prefLabel": { + "en": "group repeated measures" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "group_repeated_measures_method", + "isAbout": "items/group_repeated_measures_method.jsonld", + "prefLabel": { + "en": "group repeated measures method" + }, + "isVis": "group_repeated_measures == 1", + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + } + ], + "allow": [ + "reproschema:AutoAdvance", + "reproschema:AllowExport" + ] + } +} diff --git a/ui/neurovault/activities/group_modeling/items/group_estimation_type.jsonld b/ui/neurovault/activities/group_modeling/items/group_estimation_type.jsonld new file mode 100644 index 00000000..6a494c09 --- /dev/null +++ b/ui/neurovault/activities/group_modeling/items/group_estimation_type.jsonld @@ -0,0 +1,36 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "group_estimation_type.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "group estimation type" + }, + "description": "group estimation type", + "ui": { + "inputType": "select" + }, + "question": { + "en": "7.2 - Estimation method used for model" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": { + "en": "ordinary least squares" + }, + "value": 0 + }, + { + "name": { + "en": "generalized least squares" + }, + "value": 1 + } + ], + "minValue": 0, + "maxValue": 1 + } +} diff --git a/ui/neurovault/activities/group_modeling/items/group_inference_type.jsonld b/ui/neurovault/activities/group_modeling/items/group_inference_type.jsonld new file mode 100644 index 00000000..c76bec29 --- /dev/null +++ b/ui/neurovault/activities/group_modeling/items/group_inference_type.jsonld @@ -0,0 +1,42 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "group_inference_type.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "group inference type" + }, + "description": "group inference type", + "ui": { + "inputType": "select" + }, + "question": { + "en": "7.4 - Type of inference for group model" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": { + "en": "random effect" + }, + "value": 0 + }, + { + "name": { + "en": "mixed effect" + }, + "value": 1 + }, + { + "name": { + "en": "fixed effect" + }, + "value": 2 + } + ], + "minValue": 0, + "maxValue": 2 + } +} diff --git a/ui/neurovault/activities/group_modeling/items/group_model_multilevel.jsonld b/ui/neurovault/activities/group_modeling/items/group_model_multilevel.jsonld new file mode 100644 index 00000000..233806ff --- /dev/null +++ b/ui/neurovault/activities/group_modeling/items/group_model_multilevel.jsonld @@ -0,0 +1,17 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "group_model_multilevel.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "group model multilevel" + }, + "description": "group model multilevel", + "ui": { + "inputType": "textarea" + }, + "question": { + "en": "7.5 - If more than 2-levels, describe the levels and assumptions of the model.
details
For example, are variances assumed equal between groups.
" + } +} diff --git a/ui/neurovault/activities/group_modeling/items/group_model_type.jsonld b/ui/neurovault/activities/group_modeling/items/group_model_type.jsonld new file mode 100644 index 00000000..f1f3b7f6 --- /dev/null +++ b/ui/neurovault/activities/group_modeling/items/group_model_type.jsonld @@ -0,0 +1,30 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "group_model_type.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "group model type" + }, + "description": "group model type", + "ui": { + "inputType": "select" + }, + "question": { + "en": "7.1 - Type of group model used" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": { + "en": "Regression" + }, + "value": 0 + } + ], + "minValue": 0, + "maxValue": 0 + } +} diff --git a/ui/neurovault/activities/group_modeling/items/group_modeling_software.jsonld b/ui/neurovault/activities/group_modeling/items/group_modeling_software.jsonld new file mode 100644 index 00000000..894ef68c --- /dev/null +++ b/ui/neurovault/activities/group_modeling/items/group_modeling_software.jsonld @@ -0,0 +1,23 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "group_modeling_software.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "group modeling software" + }, + "description": "group modeling software", + "ui": { + "inputType": "select" + }, + "question": { + "en": "7.3 - Software used for group modeling if different from overall package" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": "https://raw.githubusercontent.com/ohbm/cobidas_schema/master/response_options/mri_softwares.jsonld", + "minValue": 0, + "maxValue": 0 + } +} diff --git a/ui/neurovault/activities/group_modeling/items/group_repeated_measures.jsonld b/ui/neurovault/activities/group_modeling/items/group_repeated_measures.jsonld new file mode 100644 index 00000000..73223aa8 --- /dev/null +++ b/ui/neurovault/activities/group_modeling/items/group_repeated_measures.jsonld @@ -0,0 +1,23 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "group_repeated_measures.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "group repeated measures" + }, + "description": "group repeated measures", + "ui": { + "inputType": "radio" + }, + "question": { + "en": "7.6 - Was this a repeated measures design at the group level?" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": "https://raw.githubusercontent.com/ohbm/cobidas_schema/master/response_options/boolean.jsonld", + "minValue": 0, + "maxValue": 0 + } +} diff --git a/ui/neurovault/activities/group_modeling/items/group_repeated_measures_method.jsonld b/ui/neurovault/activities/group_modeling/items/group_repeated_measures_method.jsonld new file mode 100644 index 00000000..4bb0bd87 --- /dev/null +++ b/ui/neurovault/activities/group_modeling/items/group_repeated_measures_method.jsonld @@ -0,0 +1,17 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "group_repeated_measures_method.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "group repeated measures method" + }, + "description": "group repeated measures method", + "ui": { + "inputType": "textarea" + }, + "question": { + "en": "7.7 - If multiple measurements per subject, list method to account for within subject correlation, exact assumptions made about correlation/variance" + } +} diff --git a/ui/neurovault/activities/individual_subject_modeling/individual_subject_modeling_schema.jsonld b/ui/neurovault/activities/individual_subject_modeling/individual_subject_modeling_schema.jsonld new file mode 100644 index 00000000..bdcde850 --- /dev/null +++ b/ui/neurovault/activities/individual_subject_modeling/individual_subject_modeling_schema.jsonld @@ -0,0 +1,220 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Activity", + "@id": "individual_subject_modeling_schema.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "Individual subject modeling" + }, + "description": "individual subject modeling", + "preamble": { + "en": "

Source | Github repository | Reference

Describe your model specification at the subejct level

" + }, + "ui": { + "shuffle": false, + "order": [ + "items/intrasubject_model_type.jsonld", + "items/intrasubject_estimation_type.jsonld", + "items/intrasubject_modeling_software.jsonld", + "items/hemodynamic_response_function.jsonld", + "items/used_temporal_derivatives.jsonld", + "items/used_dispersion_derivatives.jsonld", + "items/used_motion_regressors.jsonld", + "items/used_reaction_time_regressor.jsonld", + "items/used_orthogonalization.jsonld", + "items/orthogonalization_description.jsonld", + "items/used_high_pass_filter.jsonld", + "items/high_pass_filter_method.jsonld", + "items/autocorrelation_model.jsonld", + "items/contrast_definition.jsonld", + "items/contrast_definition_cogatlas.jsonld" + ], + "addProperties": [ + { + "variableName": "intrasubject_model_type", + "isAbout": "items/intrasubject_model_type.jsonld", + "prefLabel": { + "en": "intrasubject model type" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "intrasubject_estimation_type", + "isAbout": "items/intrasubject_estimation_type.jsonld", + "prefLabel": { + "en": "intrasubject estimation type" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "intrasubject_modeling_software", + "isAbout": "items/intrasubject_modeling_software.jsonld", + "prefLabel": { + "en": "intrasubject modeling software" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "hemodynamic_response_function", + "isAbout": "items/hemodynamic_response_function.jsonld", + "prefLabel": { + "en": "hemodynamic response function" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "used_temporal_derivatives", + "isAbout": "items/used_temporal_derivatives.jsonld", + "prefLabel": { + "en": "used temporal derivatives" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "used_dispersion_derivatives", + "isAbout": "items/used_dispersion_derivatives.jsonld", + "prefLabel": { + "en": "used dispersion derivatives" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "used_motion_regressors", + "isAbout": "items/used_motion_regressors.jsonld", + "prefLabel": { + "en": "used motion regressors" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "used_reaction_time_regressor", + "isAbout": "items/used_reaction_time_regressor.jsonld", + "prefLabel": { + "en": "used reaction time regressor" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "used_orthogonalization", + "isAbout": "items/used_orthogonalization.jsonld", + "prefLabel": { + "en": "used orthogonalization" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "orthogonalization_description", + "isAbout": "items/orthogonalization_description.jsonld", + "prefLabel": { + "en": "orthogonalization description" + }, + "isVis": "used_orthogonalization == 1", + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "used_high_pass_filter", + "isAbout": "items/used_high_pass_filter.jsonld", + "prefLabel": { + "en": "used high pass filter" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "high_pass_filter_method", + "isAbout": "items/high_pass_filter_method.jsonld", + "prefLabel": { + "en": "high pass filter method" + }, + "isVis": "used_high_pass_filter == 1", + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "autocorrelation_model", + "isAbout": "items/autocorrelation_model.jsonld", + "prefLabel": { + "en": "autocorrelation model" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "contrast_definition", + "isAbout": "items/contrast_definition.jsonld", + "prefLabel": { + "en": "contrast definition" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "contrast_definition_cogatlas", + "isAbout": "items/contrast_definition_cogatlas.jsonld", + "prefLabel": { + "en": "contrast definition cogatlas" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + } + ], + "allow": [ + "reproschema:AutoAdvance", + "reproschema:AllowExport" + ] + } +} diff --git a/ui/neurovault/activities/individual_subject_modeling/items/autocorrelation_model.jsonld b/ui/neurovault/activities/individual_subject_modeling/items/autocorrelation_model.jsonld new file mode 100644 index 00000000..04f01849 --- /dev/null +++ b/ui/neurovault/activities/individual_subject_modeling/items/autocorrelation_model.jsonld @@ -0,0 +1,17 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "autocorrelation_model.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "autocorrelation model" + }, + "description": "autocorrelation model", + "ui": { + "inputType": "textarea" + }, + "question": { + "en": "6.13 - What autocorrelation model was used (or 'none' if none was used)" + } +} diff --git a/ui/neurovault/activities/individual_subject_modeling/items/contrast_definition.jsonld b/ui/neurovault/activities/individual_subject_modeling/items/contrast_definition.jsonld new file mode 100644 index 00000000..9fc7a54e --- /dev/null +++ b/ui/neurovault/activities/individual_subject_modeling/items/contrast_definition.jsonld @@ -0,0 +1,17 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "contrast_definition.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "contrast definition" + }, + "description": "contrast definition", + "ui": { + "inputType": "textarea" + }, + "question": { + "en": "6.14 - Exactly what terms are subtracted from what?" + } +} diff --git a/ui/neurovault/activities/individual_subject_modeling/items/contrast_definition_cogatlas.jsonld b/ui/neurovault/activities/individual_subject_modeling/items/contrast_definition_cogatlas.jsonld new file mode 100644 index 00000000..39df28c6 --- /dev/null +++ b/ui/neurovault/activities/individual_subject_modeling/items/contrast_definition_cogatlas.jsonld @@ -0,0 +1,17 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "contrast_definition_cogatlas.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "contrast definition cogatlas" + }, + "description": "contrast definition cogatlas", + "ui": { + "inputType": "textarea" + }, + "question": { + "en": "6.15 - Link to Cognitive Atlas definition of this contrast
details
Define these in terms of task or stimulus conditions (e.g., 'one-back task with objects versus zero-back task with objects') instead of underlying psychological concepts (e.g., 'working memory').
" + } +} diff --git a/ui/neurovault/activities/individual_subject_modeling/items/hemodynamic_response_function.jsonld b/ui/neurovault/activities/individual_subject_modeling/items/hemodynamic_response_function.jsonld new file mode 100644 index 00000000..e9f259fb --- /dev/null +++ b/ui/neurovault/activities/individual_subject_modeling/items/hemodynamic_response_function.jsonld @@ -0,0 +1,42 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "hemodynamic_response_function.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "hemodynamic response function" + }, + "description": "hemodynamic response function", + "ui": { + "inputType": "select" + }, + "question": { + "en": "6.4 - Nature of HRF model" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": { + "en": "double gamma" + }, + "value": 0 + }, + { + "name": { + "en": "Fourrier set" + }, + "value": 1 + }, + { + "name": { + "en": "FIR" + }, + "value": 2 + } + ], + "minValue": 0, + "maxValue": 2 + } +} diff --git a/ui/neurovault/activities/individual_subject_modeling/items/high_pass_filter_method.jsonld b/ui/neurovault/activities/individual_subject_modeling/items/high_pass_filter_method.jsonld new file mode 100644 index 00000000..54cd4e2a --- /dev/null +++ b/ui/neurovault/activities/individual_subject_modeling/items/high_pass_filter_method.jsonld @@ -0,0 +1,17 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "high_pass_filter_method.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "high pass filter method" + }, + "description": "high pass filter method", + "ui": { + "inputType": "textarea" + }, + "question": { + "en": "6.12 - Describe method used for high pass filtering" + } +} diff --git a/ui/neurovault/activities/individual_subject_modeling/items/intrasubject_estimation_type.jsonld b/ui/neurovault/activities/individual_subject_modeling/items/intrasubject_estimation_type.jsonld new file mode 100644 index 00000000..92437f24 --- /dev/null +++ b/ui/neurovault/activities/individual_subject_modeling/items/intrasubject_estimation_type.jsonld @@ -0,0 +1,36 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "intrasubject_estimation_type.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "intrasubject estimation type" + }, + "description": "intrasubject estimation type", + "ui": { + "inputType": "select" + }, + "question": { + "en": "6.2 - Estimation method used for model" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": { + "en": "ordinary least squares" + }, + "value": 0 + }, + { + "name": { + "en": "generalized least squares" + }, + "value": 1 + } + ], + "minValue": 0, + "maxValue": 1 + } +} diff --git a/ui/neurovault/activities/individual_subject_modeling/items/intrasubject_model_type.jsonld b/ui/neurovault/activities/individual_subject_modeling/items/intrasubject_model_type.jsonld new file mode 100644 index 00000000..2adbccf7 --- /dev/null +++ b/ui/neurovault/activities/individual_subject_modeling/items/intrasubject_model_type.jsonld @@ -0,0 +1,30 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "intrasubject_model_type.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "intrasubject model type" + }, + "description": "intrasubject model type", + "ui": { + "inputType": "radio" + }, + "question": { + "en": "6.1 - Type of group model used" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": { + "en": "Regression" + }, + "value": 0 + } + ], + "minValue": 0, + "maxValue": 0 + } +} diff --git a/ui/neurovault/activities/individual_subject_modeling/items/intrasubject_modeling_software.jsonld b/ui/neurovault/activities/individual_subject_modeling/items/intrasubject_modeling_software.jsonld new file mode 100644 index 00000000..5bfcb659 --- /dev/null +++ b/ui/neurovault/activities/individual_subject_modeling/items/intrasubject_modeling_software.jsonld @@ -0,0 +1,23 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "intrasubject_modeling_software.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "intrasubject modeling software" + }, + "description": "intrasubject modeling software", + "ui": { + "inputType": "select" + }, + "question": { + "en": "6.3 - Software used for intrasubject modeling if different from overall package" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": "https://raw.githubusercontent.com/ohbm/cobidas_schema/master/response_options/mri_softwares.jsonld", + "minValue": 0, + "maxValue": 0 + } +} diff --git a/ui/neurovault/activities/individual_subject_modeling/items/orthogonalization_description.jsonld b/ui/neurovault/activities/individual_subject_modeling/items/orthogonalization_description.jsonld new file mode 100644 index 00000000..b6cce576 --- /dev/null +++ b/ui/neurovault/activities/individual_subject_modeling/items/orthogonalization_description.jsonld @@ -0,0 +1,17 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "orthogonalization_description.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "orthogonalization description" + }, + "description": "orthogonalization description", + "ui": { + "inputType": "textarea" + }, + "question": { + "en": "6.10 - If orthogonalization was used, describe here" + } +} diff --git a/ui/neurovault/activities/individual_subject_modeling/items/used_dispersion_derivatives.jsonld b/ui/neurovault/activities/individual_subject_modeling/items/used_dispersion_derivatives.jsonld new file mode 100644 index 00000000..18f30f07 --- /dev/null +++ b/ui/neurovault/activities/individual_subject_modeling/items/used_dispersion_derivatives.jsonld @@ -0,0 +1,23 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "used_dispersion_derivatives.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "used dispersion derivatives" + }, + "description": "used dispersion derivatives", + "ui": { + "inputType": "radio" + }, + "question": { + "en": "6.6 - Were dispersion derivatives included?" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": "https://raw.githubusercontent.com/ohbm/cobidas_schema/master/response_options/boolean.jsonld", + "minValue": 0, + "maxValue": 0 + } +} diff --git a/ui/neurovault/activities/individual_subject_modeling/items/used_high_pass_filter.jsonld b/ui/neurovault/activities/individual_subject_modeling/items/used_high_pass_filter.jsonld new file mode 100644 index 00000000..c2c8f014 --- /dev/null +++ b/ui/neurovault/activities/individual_subject_modeling/items/used_high_pass_filter.jsonld @@ -0,0 +1,23 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "used_high_pass_filter.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "used high pass filter" + }, + "description": "used high pass filter", + "ui": { + "inputType": "radio" + }, + "question": { + "en": "6.11 - Was high pass filtering applied?" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": "https://raw.githubusercontent.com/ohbm/cobidas_schema/master/response_options/boolean.jsonld", + "minValue": 0, + "maxValue": 0 + } +} diff --git a/ui/neurovault/activities/individual_subject_modeling/items/used_motion_regressors.jsonld b/ui/neurovault/activities/individual_subject_modeling/items/used_motion_regressors.jsonld new file mode 100644 index 00000000..310989dd --- /dev/null +++ b/ui/neurovault/activities/individual_subject_modeling/items/used_motion_regressors.jsonld @@ -0,0 +1,23 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "used_motion_regressors.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "used motion regressors" + }, + "description": "used motion regressors", + "ui": { + "inputType": "radio" + }, + "question": { + "en": "6.7 - Were motion regressors included?" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": "https://raw.githubusercontent.com/ohbm/cobidas_schema/master/response_options/boolean.jsonld", + "minValue": 0, + "maxValue": 0 + } +} diff --git a/ui/neurovault/activities/individual_subject_modeling/items/used_orthogonalization.jsonld b/ui/neurovault/activities/individual_subject_modeling/items/used_orthogonalization.jsonld new file mode 100644 index 00000000..08148781 --- /dev/null +++ b/ui/neurovault/activities/individual_subject_modeling/items/used_orthogonalization.jsonld @@ -0,0 +1,23 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "used_orthogonalization.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "used orthogonalization" + }, + "description": "used orthogonalization", + "ui": { + "inputType": "radio" + }, + "question": { + "en": "6.9 - Were any regressors specifically orthogonalized with respect to others?" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": "https://raw.githubusercontent.com/ohbm/cobidas_schema/master/response_options/boolean.jsonld", + "minValue": 0, + "maxValue": 0 + } +} diff --git a/ui/neurovault/activities/individual_subject_modeling/items/used_reaction_time_regressor.jsonld b/ui/neurovault/activities/individual_subject_modeling/items/used_reaction_time_regressor.jsonld new file mode 100644 index 00000000..da6e8f18 --- /dev/null +++ b/ui/neurovault/activities/individual_subject_modeling/items/used_reaction_time_regressor.jsonld @@ -0,0 +1,23 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "used_reaction_time_regressor.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "used reaction time regressor" + }, + "description": "used reaction time regressor", + "ui": { + "inputType": "radio" + }, + "question": { + "en": "6.8 - Was a reaction time regressor included?" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": "https://raw.githubusercontent.com/ohbm/cobidas_schema/master/response_options/boolean.jsonld", + "minValue": 0, + "maxValue": 0 + } +} diff --git a/ui/neurovault/activities/individual_subject_modeling/items/used_temporal_derivatives.jsonld b/ui/neurovault/activities/individual_subject_modeling/items/used_temporal_derivatives.jsonld new file mode 100644 index 00000000..4bacae27 --- /dev/null +++ b/ui/neurovault/activities/individual_subject_modeling/items/used_temporal_derivatives.jsonld @@ -0,0 +1,23 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "used_temporal_derivatives.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "used temporal derivatives" + }, + "description": "used temporal derivatives", + "ui": { + "inputType": "radio" + }, + "question": { + "en": "6.5 - Were temporal derivatives included?" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": "https://raw.githubusercontent.com/ohbm/cobidas_schema/master/response_options/boolean.jsonld", + "minValue": 0, + "maxValue": 0 + } +} diff --git a/ui/neurovault/activities/intersubject_registration/intersubject_registration_schema.jsonld b/ui/neurovault/activities/intersubject_registration/intersubject_registration_schema.jsonld new file mode 100644 index 00000000..263c225c --- /dev/null +++ b/ui/neurovault/activities/intersubject_registration/intersubject_registration_schema.jsonld @@ -0,0 +1,233 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Activity", + "@id": "intersubject_registration_schema.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "Intersubject registration" + }, + "description": "intersubject registration", + "preamble": { + "en": "

Source | Github repository | Reference

Describe your spatial normalization

" + }, + "ui": { + "shuffle": false, + "order": [ + "items/used_intersubject_registration.jsonld", + "items/intersubject_registration_software.jsonld", + "items/intersubject_transformation_type.jsonld", + "items/nonlinear_transform_type.jsonld", + "items/transform_similarity_metric.jsonld", + "items/interpolation_method.jsonld", + "items/object_image_type.jsonld", + "items/functional_coregistered_to_structural.jsonld", + "items/functional_coregistration_method.jsonld", + "items/coordinate_space.jsonld", + "items/target_template_image.jsonld", + "items/target_resolution.jsonld", + "items/used_smoothing.jsonld", + "items/smoothing_type.jsonld", + "items/smoothing_fwhm.jsonld", + "items/resampled_voxel_size.jsonld" + ], + "addProperties": [ + { + "variableName": "used_intersubject_registration", + "isAbout": "items/used_intersubject_registration.jsonld", + "prefLabel": { + "en": "used intersubject registration" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "intersubject_registration_software", + "isAbout": "items/intersubject_registration_software.jsonld", + "prefLabel": { + "en": "intersubject registration software" + }, + "isVis": "used_intersubject_registration == 1", + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "intersubject_transformation_type", + "isAbout": "items/intersubject_transformation_type.jsonld", + "prefLabel": { + "en": "intersubject transformation type" + }, + "isVis": "used_intersubject_registration == 1", + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "nonlinear_transform_type", + "isAbout": "items/nonlinear_transform_type.jsonld", + "prefLabel": { + "en": "nonlinear transform type" + }, + "isVis": "used_intersubject_registration == 1", + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "transform_similarity_metric", + "isAbout": "items/transform_similarity_metric.jsonld", + "prefLabel": { + "en": "transform similarity metric" + }, + "isVis": "used_intersubject_registration == 1", + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "interpolation_method", + "isAbout": "items/interpolation_method.jsonld", + "prefLabel": { + "en": "interpolation method" + }, + "isVis": "used_intersubject_registration == 1", + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "object_image_type", + "isAbout": "items/object_image_type.jsonld", + "prefLabel": { + "en": "object image type" + }, + "isVis": "used_intersubject_registration == 1", + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "functional_coregistered_to_structural", + "isAbout": "items/functional_coregistered_to_structural.jsonld", + "prefLabel": { + "en": "functional coregistered to structural" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "functional_coregistration_method", + "isAbout": "items/functional_coregistration_method.jsonld", + "prefLabel": { + "en": "functional coregistration method" + }, + "isVis": "functional_coregistered_to_structural == 1", + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "coordinate_space", + "isAbout": "items/coordinate_space.jsonld", + "prefLabel": { + "en": "coordinate space" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "target_template_image", + "isAbout": "items/target_template_image.jsonld", + "prefLabel": { + "en": "target template image" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "target_resolution", + "isAbout": "items/target_resolution.jsonld", + "prefLabel": { + "en": "target resolution" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "used_smoothing", + "isAbout": "items/used_smoothing.jsonld", + "prefLabel": { + "en": "used smoothing" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "smoothing_type", + "isAbout": "items/smoothing_type.jsonld", + "prefLabel": { + "en": "smoothing type" + }, + "isVis": "used_smoothing == 1", + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "smoothing_fwhm", + "isAbout": "items/smoothing_fwhm.jsonld", + "prefLabel": { + "en": "smoothing fwhm" + }, + "isVis": "used_smoothing == 1", + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "resampled_voxel_size", + "isAbout": "items/resampled_voxel_size.jsonld", + "prefLabel": { + "en": "resampled voxel size" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + } + ], + "allow": [ + "reproschema:AutoAdvance", + "reproschema:AllowExport" + ] + } +} diff --git a/ui/neurovault/activities/intersubject_registration/items/coordinate_space.jsonld b/ui/neurovault/activities/intersubject_registration/items/coordinate_space.jsonld new file mode 100644 index 00000000..9412f5c7 --- /dev/null +++ b/ui/neurovault/activities/intersubject_registration/items/coordinate_space.jsonld @@ -0,0 +1,42 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "coordinate_space.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "coordinate space" + }, + "description": "coordinate space", + "ui": { + "inputType": "select" + }, + "question": { + "en": "5.10 - Name of coordinate space for registration target" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": { + "en": "MNI" + }, + "value": 0 + }, + { + "name": { + "en": "Talairach" + }, + "value": 1 + }, + { + "name": { + "en": "MNI2Tal" + }, + "value": 2 + } + ], + "minValue": 0, + "maxValue": 2 + } +} diff --git a/ui/neurovault/activities/intersubject_registration/items/functional_coregistered_to_structural.jsonld b/ui/neurovault/activities/intersubject_registration/items/functional_coregistered_to_structural.jsonld new file mode 100644 index 00000000..d6cb14fe --- /dev/null +++ b/ui/neurovault/activities/intersubject_registration/items/functional_coregistered_to_structural.jsonld @@ -0,0 +1,23 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "functional_coregistered_to_structural.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "functional coregistered to structural" + }, + "description": "functional coregistered to structural", + "ui": { + "inputType": "radio" + }, + "question": { + "en": "5.8 - Were the functional images coregistered to the subject's structural image?" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": "https://raw.githubusercontent.com/ohbm/cobidas_schema/master/response_options/boolean.jsonld", + "minValue": 0, + "maxValue": 0 + } +} diff --git a/ui/neurovault/activities/intersubject_registration/items/functional_coregistration_method.jsonld b/ui/neurovault/activities/intersubject_registration/items/functional_coregistration_method.jsonld new file mode 100644 index 00000000..71376b1e --- /dev/null +++ b/ui/neurovault/activities/intersubject_registration/items/functional_coregistration_method.jsonld @@ -0,0 +1,17 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "functional_coregistration_method.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "functional coregistration method" + }, + "description": "functional coregistration method", + "ui": { + "inputType": "textarea" + }, + "question": { + "en": "5.9 - Method used to coregister functional to structural images" + } +} diff --git a/ui/neurovault/activities/intersubject_registration/items/interpolation_method.jsonld b/ui/neurovault/activities/intersubject_registration/items/interpolation_method.jsonld new file mode 100644 index 00000000..f7a1796e --- /dev/null +++ b/ui/neurovault/activities/intersubject_registration/items/interpolation_method.jsonld @@ -0,0 +1,23 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "interpolation_method.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "interpolation method" + }, + "description": "interpolation method", + "ui": { + "inputType": "select" + }, + "question": { + "en": "5.6 - Interpolation method used for intersubject registration" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": "https://raw.githubusercontent.com/ohbm/cobidas_schema/master/response_options/interpolations.jsonld", + "minValue": 0, + "maxValue": 0 + } +} diff --git a/ui/neurovault/activities/intersubject_registration/items/intersubject_registration_software.jsonld b/ui/neurovault/activities/intersubject_registration/items/intersubject_registration_software.jsonld new file mode 100644 index 00000000..00769bb8 --- /dev/null +++ b/ui/neurovault/activities/intersubject_registration/items/intersubject_registration_software.jsonld @@ -0,0 +1,23 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "intersubject_registration_software.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "intersubject registration software" + }, + "description": "intersubject registration software", + "ui": { + "inputType": "select" + }, + "question": { + "en": "5.2 - Specify software used for intersubject registration if different from main package" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": "https://raw.githubusercontent.com/ohbm/cobidas_schema/master/response_options/mri_softwares.jsonld", + "minValue": 0, + "maxValue": 0 + } +} diff --git a/ui/neurovault/activities/intersubject_registration/items/intersubject_transformation_type.jsonld b/ui/neurovault/activities/intersubject_registration/items/intersubject_transformation_type.jsonld new file mode 100644 index 00000000..c0b5f3f6 --- /dev/null +++ b/ui/neurovault/activities/intersubject_registration/items/intersubject_transformation_type.jsonld @@ -0,0 +1,36 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "intersubject_transformation_type.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "intersubject transformation type" + }, + "description": "intersubject transformation type", + "ui": { + "inputType": "select" + }, + "question": { + "en": "5.3 - Was linear or nonlinear registration used?" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": { + "en": "linear" + }, + "value": 0 + }, + { + "name": { + "en": "non-linear" + }, + "value": 1 + } + ], + "minValue": 0, + "maxValue": 1 + } +} diff --git a/ui/neurovault/activities/intersubject_registration/items/nonlinear_transform_type.jsonld b/ui/neurovault/activities/intersubject_registration/items/nonlinear_transform_type.jsonld new file mode 100644 index 00000000..b7c46e26 --- /dev/null +++ b/ui/neurovault/activities/intersubject_registration/items/nonlinear_transform_type.jsonld @@ -0,0 +1,17 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "nonlinear_transform_type.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "nonlinear transform type" + }, + "description": "nonlinear transform type", + "ui": { + "inputType": "textarea" + }, + "question": { + "en": "5.4 - If nonlinear registration was used, describe transform method" + } +} diff --git a/ui/neurovault/activities/intersubject_registration/items/object_image_type.jsonld b/ui/neurovault/activities/intersubject_registration/items/object_image_type.jsonld new file mode 100644 index 00000000..1f8d7065 --- /dev/null +++ b/ui/neurovault/activities/intersubject_registration/items/object_image_type.jsonld @@ -0,0 +1,17 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "object_image_type.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "object image type" + }, + "description": "object image type", + "ui": { + "inputType": "textarea" + }, + "question": { + "en": "5.7 - What type of image was used to determine the transformation to the atlas?" + } +} diff --git a/ui/neurovault/activities/intersubject_registration/items/resampled_voxel_size.jsonld b/ui/neurovault/activities/intersubject_registration/items/resampled_voxel_size.jsonld new file mode 100644 index 00000000..8610594e --- /dev/null +++ b/ui/neurovault/activities/intersubject_registration/items/resampled_voxel_size.jsonld @@ -0,0 +1,20 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "resampled_voxel_size.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "resampled voxel size" + }, + "description": "resampled voxel size", + "ui": { + "inputType": "float" + }, + "question": { + "en": "5.16 - Voxel size in mm of the resampled, atlas-space images" + }, + "responseOptions": { + "valueType": "xsd:float" + } +} diff --git a/ui/neurovault/activities/intersubject_registration/items/smoothing_fwhm.jsonld b/ui/neurovault/activities/intersubject_registration/items/smoothing_fwhm.jsonld new file mode 100644 index 00000000..03bb738a --- /dev/null +++ b/ui/neurovault/activities/intersubject_registration/items/smoothing_fwhm.jsonld @@ -0,0 +1,28 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "smoothing_fwhm.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "smoothing fwhm" + }, + "description": "smoothing fwhm", + "ui": { + "inputType": "float" + }, + "question": { + "en": "5.15 - The full-width at half-maximum of the smoothing kernel" + }, + "responseOptions": { + "valueType": "xsd:float", + "unitOptions": [ + { + "prefLabel": { + "en": "Millimeters" + }, + "value": "Millimeters" + } + ] + } +} diff --git a/ui/neurovault/activities/intersubject_registration/items/smoothing_type.jsonld b/ui/neurovault/activities/intersubject_registration/items/smoothing_type.jsonld new file mode 100644 index 00000000..baef85d9 --- /dev/null +++ b/ui/neurovault/activities/intersubject_registration/items/smoothing_type.jsonld @@ -0,0 +1,21 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "smoothing_type.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "smoothing type" + }, + "description": "smoothing type", + "ui": { + "inputType": "text" + }, + "question": { + "en": "5.14 - Describe the type of smoothing applied" + }, + "responseOptions": { + "valueType": "xsd:string", + "maxLength": 300 + } +} diff --git a/ui/neurovault/activities/intersubject_registration/items/target_resolution.jsonld b/ui/neurovault/activities/intersubject_registration/items/target_resolution.jsonld new file mode 100644 index 00000000..22d2ec9e --- /dev/null +++ b/ui/neurovault/activities/intersubject_registration/items/target_resolution.jsonld @@ -0,0 +1,28 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "target_resolution.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "target resolution" + }, + "description": "target resolution", + "ui": { + "inputType": "float" + }, + "question": { + "en": "5.12 - Voxel size of target template" + }, + "responseOptions": { + "valueType": "xsd:float", + "unitOptions": [ + { + "prefLabel": { + "en": "Millimeters" + }, + "value": "Millimeters" + } + ] + } +} diff --git a/ui/neurovault/activities/intersubject_registration/items/target_template_image.jsonld b/ui/neurovault/activities/intersubject_registration/items/target_template_image.jsonld new file mode 100644 index 00000000..d0e86d2e --- /dev/null +++ b/ui/neurovault/activities/intersubject_registration/items/target_template_image.jsonld @@ -0,0 +1,17 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "target_template_image.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "target template image" + }, + "description": "target template image", + "ui": { + "inputType": "textarea" + }, + "question": { + "en": "5.11 - Name of target template image" + } +} diff --git a/ui/neurovault/activities/intersubject_registration/items/transform_similarity_metric.jsonld b/ui/neurovault/activities/intersubject_registration/items/transform_similarity_metric.jsonld new file mode 100644 index 00000000..afa0bfba --- /dev/null +++ b/ui/neurovault/activities/intersubject_registration/items/transform_similarity_metric.jsonld @@ -0,0 +1,17 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "transform_similarity_metric.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "transform similarity metric" + }, + "description": "transform similarity metric", + "ui": { + "inputType": "textarea" + }, + "question": { + "en": "5.5 - Similarity metric used for intersubject registration" + } +} diff --git a/ui/neurovault/activities/intersubject_registration/items/used_intersubject_registration.jsonld b/ui/neurovault/activities/intersubject_registration/items/used_intersubject_registration.jsonld new file mode 100644 index 00000000..53b9a8d1 --- /dev/null +++ b/ui/neurovault/activities/intersubject_registration/items/used_intersubject_registration.jsonld @@ -0,0 +1,23 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "used_intersubject_registration.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "used intersubject registration" + }, + "description": "used intersubject registration", + "ui": { + "inputType": "radio" + }, + "question": { + "en": "5.1 - Were subjects registered to a common stereotactic space?" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": "https://raw.githubusercontent.com/ohbm/cobidas_schema/master/response_options/boolean.jsonld", + "minValue": 0, + "maxValue": 0 + } +} diff --git a/ui/neurovault/activities/intersubject_registration/items/used_smoothing.jsonld b/ui/neurovault/activities/intersubject_registration/items/used_smoothing.jsonld new file mode 100644 index 00000000..b78fcf59 --- /dev/null +++ b/ui/neurovault/activities/intersubject_registration/items/used_smoothing.jsonld @@ -0,0 +1,23 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "used_smoothing.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "used smoothing" + }, + "description": "used smoothing", + "ui": { + "inputType": "radio" + }, + "question": { + "en": "5.13 - Was spatial smoothing applied?" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": "https://raw.githubusercontent.com/ohbm/cobidas_schema/master/response_options/boolean.jsonld", + "minValue": 0, + "maxValue": 0 + } +} diff --git a/ui/neurovault/activities/mri_acquisition/items/EchoTime.jsonld b/ui/neurovault/activities/mri_acquisition/items/EchoTime.jsonld new file mode 100644 index 00000000..f6634208 --- /dev/null +++ b/ui/neurovault/activities/mri_acquisition/items/EchoTime.jsonld @@ -0,0 +1,28 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "EchoTime.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "echo time" + }, + "description": "echo time", + "ui": { + "inputType": "float" + }, + "question": { + "en": "3.13 - Echo time (TE)" + }, + "responseOptions": { + "valueType": "xsd:float", + "unitOptions": [ + { + "prefLabel": { + "en": "Milliseconds" + }, + "value": "Milliseconds" + } + ] + } +} diff --git a/ui/neurovault/activities/mri_acquisition/items/FlipAngle.jsonld b/ui/neurovault/activities/mri_acquisition/items/FlipAngle.jsonld new file mode 100644 index 00000000..4f14ab18 --- /dev/null +++ b/ui/neurovault/activities/mri_acquisition/items/FlipAngle.jsonld @@ -0,0 +1,28 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "FlipAngle.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "flip angle" + }, + "description": "flip angle", + "ui": { + "inputType": "float" + }, + "question": { + "en": "3.14 - Flip angle" + }, + "responseOptions": { + "valueType": "xsd:float", + "unitOptions": [ + { + "prefLabel": { + "en": "Degrees" + }, + "value": "Degrees" + } + ] + } +} diff --git a/ui/neurovault/activities/mri_acquisition/items/MagneticFieldStrength.jsonld b/ui/neurovault/activities/mri_acquisition/items/MagneticFieldStrength.jsonld new file mode 100644 index 00000000..bd4fc571 --- /dev/null +++ b/ui/neurovault/activities/mri_acquisition/items/MagneticFieldStrength.jsonld @@ -0,0 +1,28 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "MagneticFieldStrength.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "field strength" + }, + "description": "field strength", + "ui": { + "inputType": "float" + }, + "question": { + "en": "3.3 - Field strength of MRI scanner" + }, + "responseOptions": { + "valueType": "xsd:float", + "unitOptions": [ + { + "prefLabel": { + "en": "Tesla" + }, + "value": "Tesla" + } + ] + } +} diff --git a/ui/neurovault/activities/mri_acquisition/items/Manufacturer.jsonld b/ui/neurovault/activities/mri_acquisition/items/Manufacturer.jsonld new file mode 100644 index 00000000..ee66c38d --- /dev/null +++ b/ui/neurovault/activities/mri_acquisition/items/Manufacturer.jsonld @@ -0,0 +1,42 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "Manufacturer.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "scanner make" + }, + "description": "scanner make", + "ui": { + "inputType": "select" + }, + "question": { + "en": "3.1 - Manufacturer of MRI scanner" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": { + "en": "Siemens" + }, + "value": 0 + }, + { + "name": { + "en": "Philips" + }, + "value": 1 + }, + { + "name": { + "en": "General Electric" + }, + "value": 2 + } + ], + "minValue": 0, + "maxValue": 2 + } +} diff --git a/ui/neurovault/activities/mri_acquisition/items/ManufacturersModelName.jsonld b/ui/neurovault/activities/mri_acquisition/items/ManufacturersModelName.jsonld new file mode 100644 index 00000000..ffc0aa52 --- /dev/null +++ b/ui/neurovault/activities/mri_acquisition/items/ManufacturersModelName.jsonld @@ -0,0 +1,17 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "ManufacturersModelName.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "scanner model" + }, + "description": "scanner model", + "ui": { + "inputType": "textarea" + }, + "question": { + "en": "3.2 - Model of MRI scanner" + } +} diff --git a/ui/neurovault/activities/mri_acquisition/items/PulseSequenceType.jsonld b/ui/neurovault/activities/mri_acquisition/items/PulseSequenceType.jsonld new file mode 100644 index 00000000..e2796f47 --- /dev/null +++ b/ui/neurovault/activities/mri_acquisition/items/PulseSequenceType.jsonld @@ -0,0 +1,60 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "PulseSequenceType.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "pulse sequence" + }, + "description": "pulse sequence", + "ui": { + "inputType": "select" + }, + "question": { + "en": "3.4 - Description of pulse sequence used for fMRI" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": { + "en": "Gradient echo" + }, + "value": 0 + }, + { + "name": { + "en": "Spin echo" + }, + "value": 1 + }, + { + "name": { + "en": "Mutliband gradient echo" + }, + "value": 2 + }, + { + "name": { + "en": "MPRAGE" + }, + "value": 3 + }, + { + "name": { + "en": "MP2RAGE" + }, + "value": 4 + }, + { + "name": { + "en": "FLASH" + }, + "value": 5 + } + ], + "minValue": 0, + "maxValue": 5 + } +} diff --git a/ui/neurovault/activities/mri_acquisition/items/RepetitionTime.jsonld b/ui/neurovault/activities/mri_acquisition/items/RepetitionTime.jsonld new file mode 100644 index 00000000..d6b8eb4a --- /dev/null +++ b/ui/neurovault/activities/mri_acquisition/items/RepetitionTime.jsonld @@ -0,0 +1,28 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "RepetitionTime.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "repetition time" + }, + "description": "repetition time", + "ui": { + "inputType": "float" + }, + "question": { + "en": "3.12 - Repetition time (TR)" + }, + "responseOptions": { + "valueType": "xsd:float", + "unitOptions": [ + { + "prefLabel": { + "en": "Milliseconds" + }, + "value": "Milliseconds" + } + ] + } +} diff --git a/ui/neurovault/activities/mri_acquisition/items/SliceTiming.jsonld b/ui/neurovault/activities/mri_acquisition/items/SliceTiming.jsonld new file mode 100644 index 00000000..55430af9 --- /dev/null +++ b/ui/neurovault/activities/mri_acquisition/items/SliceTiming.jsonld @@ -0,0 +1,42 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "SliceTiming.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "order of acquisition" + }, + "description": "order of acquisition", + "ui": { + "inputType": "select" + }, + "question": { + "en": "3.11 - Order of acquisition of slices" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": { + "en": "ascending" + }, + "value": 0 + }, + { + "name": { + "en": "descending" + }, + "value": 1 + }, + { + "name": { + "en": "interleaved" + }, + "value": 2 + } + ], + "minValue": 0, + "maxValue": 2 + } +} diff --git a/ui/neurovault/activities/mri_acquisition/items/acquisition_orientation.jsonld b/ui/neurovault/activities/mri_acquisition/items/acquisition_orientation.jsonld new file mode 100644 index 00000000..f07816a0 --- /dev/null +++ b/ui/neurovault/activities/mri_acquisition/items/acquisition_orientation.jsonld @@ -0,0 +1,42 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "acquisition_orientation.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "acquisition orientation" + }, + "description": "acquisition orientation", + "ui": { + "inputType": "radio" + }, + "question": { + "en": "3.10 - The orientation of slices" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": { + "en": "axial" + }, + "value": 0 + }, + { + "name": { + "en": "sagittal" + }, + "value": 1 + }, + { + "name": { + "en": "frontal" + }, + "value": 2 + } + ], + "minValue": 0, + "maxValue": 2 + } +} diff --git a/ui/neurovault/activities/mri_acquisition/items/field_of_view.jsonld b/ui/neurovault/activities/mri_acquisition/items/field_of_view.jsonld new file mode 100644 index 00000000..63bcee3b --- /dev/null +++ b/ui/neurovault/activities/mri_acquisition/items/field_of_view.jsonld @@ -0,0 +1,28 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "field_of_view.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "field of view" + }, + "description": "field of view", + "ui": { + "inputType": "float" + }, + "question": { + "en": "3.6 - Imaging field of view" + }, + "responseOptions": { + "valueType": "xsd:float", + "unitOptions": [ + { + "prefLabel": { + "en": "Millimeters" + }, + "value": "Millimeters" + } + ] + } +} diff --git a/ui/neurovault/activities/mri_acquisition/items/matrix_size.jsonld b/ui/neurovault/activities/mri_acquisition/items/matrix_size.jsonld new file mode 100644 index 00000000..3e808f70 --- /dev/null +++ b/ui/neurovault/activities/mri_acquisition/items/matrix_size.jsonld @@ -0,0 +1,20 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "matrix_size.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "matrix size" + }, + "description": "matrix size", + "ui": { + "inputType": "number" + }, + "question": { + "en": "3.7 - Matrix size for MRI acquisition" + }, + "responseOptions": { + "valueType": "xsd:integer" + } +} diff --git a/ui/neurovault/activities/mri_acquisition/items/parallel_imaging.jsonld b/ui/neurovault/activities/mri_acquisition/items/parallel_imaging.jsonld new file mode 100644 index 00000000..0e918203 --- /dev/null +++ b/ui/neurovault/activities/mri_acquisition/items/parallel_imaging.jsonld @@ -0,0 +1,17 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "parallel_imaging.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "parallel imaging" + }, + "description": "parallel imaging", + "ui": { + "inputType": "textarea" + }, + "question": { + "en": "3.5 - Description of parallel imaging method and parameters" + } +} diff --git a/ui/neurovault/activities/mri_acquisition/items/skip_factor.jsonld b/ui/neurovault/activities/mri_acquisition/items/skip_factor.jsonld new file mode 100644 index 00000000..a7de681e --- /dev/null +++ b/ui/neurovault/activities/mri_acquisition/items/skip_factor.jsonld @@ -0,0 +1,28 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "skip_factor.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "skip factor" + }, + "description": "skip factor", + "ui": { + "inputType": "float" + }, + "question": { + "en": "3.9 - The size of the skipped area between slices." + }, + "responseOptions": { + "valueType": "xsd:float", + "unitOptions": [ + { + "prefLabel": { + "en": "Millimeters" + }, + "value": "Millimeters" + } + ] + } +} diff --git a/ui/neurovault/activities/mri_acquisition/items/slice_thickness.jsonld b/ui/neurovault/activities/mri_acquisition/items/slice_thickness.jsonld new file mode 100644 index 00000000..415d0675 --- /dev/null +++ b/ui/neurovault/activities/mri_acquisition/items/slice_thickness.jsonld @@ -0,0 +1,28 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "slice_thickness.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "slice thickness" + }, + "description": "slice thickness", + "ui": { + "inputType": "float" + }, + "question": { + "en": "3.8 - Distance between slices (includes skip or distance factor)." + }, + "responseOptions": { + "valueType": "xsd:float", + "unitOptions": [ + { + "prefLabel": { + "en": "Millimeters" + }, + "value": "Millimeters" + } + ] + } +} diff --git a/ui/neurovault/activities/mri_acquisition/mri_acquisition_schema.jsonld b/ui/neurovault/activities/mri_acquisition/mri_acquisition_schema.jsonld new file mode 100644 index 00000000..3542d38c --- /dev/null +++ b/ui/neurovault/activities/mri_acquisition/mri_acquisition_schema.jsonld @@ -0,0 +1,207 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Activity", + "@id": "mri_acquisition_schema.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "MRI acquisition" + }, + "description": "mri acquisition", + "preamble": { + "en": "

Source | Github repository | Reference

Describe your acquisition parameters

" + }, + "ui": { + "shuffle": false, + "order": [ + "items/Manufacturer.jsonld", + "items/ManufacturersModelName.jsonld", + "items/MagneticFieldStrength.jsonld", + "items/PulseSequenceType.jsonld", + "items/parallel_imaging.jsonld", + "items/field_of_view.jsonld", + "items/matrix_size.jsonld", + "items/slice_thickness.jsonld", + "items/skip_factor.jsonld", + "items/acquisition_orientation.jsonld", + "items/SliceTiming.jsonld", + "items/RepetitionTime.jsonld", + "items/EchoTime.jsonld", + "items/FlipAngle.jsonld" + ], + "addProperties": [ + { + "variableName": "Manufacturer", + "isAbout": "items/Manufacturer.jsonld", + "prefLabel": { + "en": "scanner make" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "ManufacturersModelName", + "isAbout": "items/ManufacturersModelName.jsonld", + "prefLabel": { + "en": "scanner model" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "MagneticFieldStrength", + "isAbout": "items/MagneticFieldStrength.jsonld", + "prefLabel": { + "en": "field strength" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "PulseSequenceType", + "isAbout": "items/PulseSequenceType.jsonld", + "prefLabel": { + "en": "pulse sequence" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "parallel_imaging", + "isAbout": "items/parallel_imaging.jsonld", + "prefLabel": { + "en": "parallel imaging" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "field_of_view", + "isAbout": "items/field_of_view.jsonld", + "prefLabel": { + "en": "field of view" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "matrix_size", + "isAbout": "items/matrix_size.jsonld", + "prefLabel": { + "en": "matrix size" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "slice_thickness", + "isAbout": "items/slice_thickness.jsonld", + "prefLabel": { + "en": "slice thickness" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "skip_factor", + "isAbout": "items/skip_factor.jsonld", + "prefLabel": { + "en": "skip factor" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "acquisition_orientation", + "isAbout": "items/acquisition_orientation.jsonld", + "prefLabel": { + "en": "acquisition orientation" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "SliceTiming", + "isAbout": "items/SliceTiming.jsonld", + "prefLabel": { + "en": "order of acquisition" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "RepetitionTime", + "isAbout": "items/RepetitionTime.jsonld", + "prefLabel": { + "en": "repetition time" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "EchoTime", + "isAbout": "items/EchoTime.jsonld", + "prefLabel": { + "en": "echo time" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "FlipAngle", + "isAbout": "items/FlipAngle.jsonld", + "prefLabel": { + "en": "flip angle" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + } + ], + "allow": [ + "reproschema:AutoAdvance", + "reproschema:AllowExport" + ] + } +} diff --git a/ui/neurovault/activities/participants/items/group_comparison.jsonld b/ui/neurovault/activities/participants/items/group_comparison.jsonld new file mode 100644 index 00000000..be14cf17 --- /dev/null +++ b/ui/neurovault/activities/participants/items/group_comparison.jsonld @@ -0,0 +1,23 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "group_comparison.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "group comparison" + }, + "description": "group comparison", + "ui": { + "inputType": "radio" + }, + "question": { + "en": "2.9 - Was this study a comparison between subject groups?" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": "https://raw.githubusercontent.com/ohbm/cobidas_schema/master/response_options/boolean.jsonld", + "minValue": 0, + "maxValue": 0 + } +} diff --git a/ui/neurovault/activities/participants/items/group_description.jsonld b/ui/neurovault/activities/participants/items/group_description.jsonld new file mode 100644 index 00000000..c77f7219 --- /dev/null +++ b/ui/neurovault/activities/participants/items/group_description.jsonld @@ -0,0 +1,17 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "group_description.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "group description" + }, + "description": "group description", + "ui": { + "inputType": "textarea" + }, + "question": { + "en": "2.10 - A description of the groups being compared" + } +} diff --git a/ui/neurovault/activities/participants/items/handedness.jsonld b/ui/neurovault/activities/participants/items/handedness.jsonld new file mode 100644 index 00000000..7fd713cb --- /dev/null +++ b/ui/neurovault/activities/participants/items/handedness.jsonld @@ -0,0 +1,42 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "handedness.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "handedness" + }, + "description": "handedness", + "ui": { + "inputType": "radio" + }, + "question": { + "en": "2.5 - Handedness of subjects" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": { + "en": "right" + }, + "value": 0 + }, + { + "name": { + "en": "left" + }, + "value": 1 + }, + { + "name": { + "en": "both" + }, + "value": 2 + } + ], + "minValue": 0, + "maxValue": 2 + } +} diff --git a/ui/neurovault/activities/participants/items/inclusion_exclusion_criteria.jsonld b/ui/neurovault/activities/participants/items/inclusion_exclusion_criteria.jsonld new file mode 100644 index 00000000..a9af6c13 --- /dev/null +++ b/ui/neurovault/activities/participants/items/inclusion_exclusion_criteria.jsonld @@ -0,0 +1,17 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "inclusion_exclusion_criteria.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "inclusion exclusion criteria" + }, + "description": "inclusion exclusion criteria", + "ui": { + "inputType": "textarea" + }, + "question": { + "en": "2.7 - Additional inclusion/exclusion criteria, if any.
details
Including specific sampling strategies that limit inclusion to a specific group, such as laboratory members.
" + } +} diff --git a/ui/neurovault/activities/participants/items/number_of_rejected_subjects.jsonld b/ui/neurovault/activities/participants/items/number_of_rejected_subjects.jsonld new file mode 100644 index 00000000..f2dca486 --- /dev/null +++ b/ui/neurovault/activities/participants/items/number_of_rejected_subjects.jsonld @@ -0,0 +1,20 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "number_of_rejected_subjects.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "number of rejected subjects" + }, + "description": "number of rejected subjects", + "ui": { + "inputType": "number" + }, + "question": { + "en": "2.8 - Number of subjects scanned but rejected from analysis" + }, + "responseOptions": { + "valueType": "xsd:integer" + } +} diff --git a/ui/neurovault/activities/participants/items/number_of_subjects.jsonld b/ui/neurovault/activities/participants/items/number_of_subjects.jsonld new file mode 100644 index 00000000..461a3768 --- /dev/null +++ b/ui/neurovault/activities/participants/items/number_of_subjects.jsonld @@ -0,0 +1,20 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "number_of_subjects.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "number of subjects" + }, + "description": "number of subjects", + "ui": { + "inputType": "number" + }, + "question": { + "en": "2.1 - Number of subjects entering into the analysis" + }, + "responseOptions": { + "valueType": "xsd:integer" + } +} diff --git a/ui/neurovault/activities/participants/items/proportion_male_subjects.jsonld b/ui/neurovault/activities/participants/items/proportion_male_subjects.jsonld new file mode 100644 index 00000000..89604b87 --- /dev/null +++ b/ui/neurovault/activities/participants/items/proportion_male_subjects.jsonld @@ -0,0 +1,145 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "proportion_male_subjects.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "proportion male subjects" + }, + "description": "proportion male subjects", + "ui": { + "inputType": "slider" + }, + "question": { + "en": "2.6 - The proportion of subjects who were male" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": [ + { + "name": { + "en": "0.000" + }, + "value": 0 + }, + { + "name": { + "en": "5.263" + }, + "value": 1 + }, + { + "name": { + "en": "10.526" + }, + "value": 2 + }, + { + "name": { + "en": "15.789" + }, + "value": 3 + }, + { + "name": { + "en": "21.053" + }, + "value": 4 + }, + { + "name": { + "en": "26.316" + }, + "value": 5 + }, + { + "name": { + "en": "31.579" + }, + "value": 6 + }, + { + "name": { + "en": "36.842" + }, + "value": 7 + }, + { + "name": { + "en": "42.105" + }, + "value": 8 + }, + { + "name": { + "en": "47.368" + }, + "value": 9 + }, + { + "name": { + "en": "52.632" + }, + "value": 10 + }, + { + "name": { + "en": "57.895" + }, + "value": 11 + }, + { + "name": { + "en": "63.158" + }, + "value": 12 + }, + { + "name": { + "en": "68.421" + }, + "value": 13 + }, + { + "name": { + "en": "73.684" + }, + "value": 14 + }, + { + "name": { + "en": "78.947" + }, + "value": 15 + }, + { + "name": { + "en": "84.211" + }, + "value": 16 + }, + { + "name": { + "en": "89.474" + }, + "value": 17 + }, + { + "name": { + "en": "94.737" + }, + "value": 18 + }, + { + "name": { + "en": "100.000" + }, + "value": 19 + } + ], + "multipleChoice": false, + "minValue": 0, + "maxValue": 19 + } +} diff --git a/ui/neurovault/activities/participants/items/subject_age_max.jsonld b/ui/neurovault/activities/participants/items/subject_age_max.jsonld new file mode 100644 index 00000000..096b704f --- /dev/null +++ b/ui/neurovault/activities/participants/items/subject_age_max.jsonld @@ -0,0 +1,20 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "subject_age_max.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "subject age max" + }, + "description": "subject age max", + "ui": { + "inputType": "float" + }, + "question": { + "en": "2.4 - Maximum age of subjects" + }, + "responseOptions": { + "valueType": "xsd:float" + } +} diff --git a/ui/neurovault/activities/participants/items/subject_age_mean.jsonld b/ui/neurovault/activities/participants/items/subject_age_mean.jsonld new file mode 100644 index 00000000..72b91f13 --- /dev/null +++ b/ui/neurovault/activities/participants/items/subject_age_mean.jsonld @@ -0,0 +1,20 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "subject_age_mean.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "subject age mean" + }, + "description": "subject age mean", + "ui": { + "inputType": "float" + }, + "question": { + "en": "2.2 - Mean age of subjects" + }, + "responseOptions": { + "valueType": "xsd:float" + } +} diff --git a/ui/neurovault/activities/participants/items/subject_age_min.jsonld b/ui/neurovault/activities/participants/items/subject_age_min.jsonld new file mode 100644 index 00000000..11a58508 --- /dev/null +++ b/ui/neurovault/activities/participants/items/subject_age_min.jsonld @@ -0,0 +1,20 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "subject_age_min.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "subject age min" + }, + "description": "subject age min", + "ui": { + "inputType": "float" + }, + "question": { + "en": "2.3 - Minimum age of subjects" + }, + "responseOptions": { + "valueType": "xsd:float" + } +} diff --git a/ui/neurovault/activities/participants/participants_schema.jsonld b/ui/neurovault/activities/participants/participants_schema.jsonld new file mode 100644 index 00000000..8a7c4fe4 --- /dev/null +++ b/ui/neurovault/activities/participants/participants_schema.jsonld @@ -0,0 +1,155 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Activity", + "@id": "participants_schema.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "Participants" + }, + "description": "participants", + "preamble": { + "en": "

Source | Github repository | Reference

Describe your participant sample

" + }, + "ui": { + "shuffle": false, + "order": [ + "items/number_of_subjects.jsonld", + "items/subject_age_mean.jsonld", + "items/subject_age_min.jsonld", + "items/subject_age_max.jsonld", + "items/handedness.jsonld", + "items/proportion_male_subjects.jsonld", + "items/inclusion_exclusion_criteria.jsonld", + "items/number_of_rejected_subjects.jsonld", + "items/group_comparison.jsonld", + "items/group_description.jsonld" + ], + "addProperties": [ + { + "variableName": "number_of_subjects", + "isAbout": "items/number_of_subjects.jsonld", + "prefLabel": { + "en": "number of subjects" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "subject_age_mean", + "isAbout": "items/subject_age_mean.jsonld", + "prefLabel": { + "en": "subject age mean" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "subject_age_min", + "isAbout": "items/subject_age_min.jsonld", + "prefLabel": { + "en": "subject age min" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "subject_age_max", + "isAbout": "items/subject_age_max.jsonld", + "prefLabel": { + "en": "subject age max" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "handedness", + "isAbout": "items/handedness.jsonld", + "prefLabel": { + "en": "handedness" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "proportion_male_subjects", + "isAbout": "items/proportion_male_subjects.jsonld", + "prefLabel": { + "en": "proportion male subjects" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "inclusion_exclusion_criteria", + "isAbout": "items/inclusion_exclusion_criteria.jsonld", + "prefLabel": { + "en": "inclusion exclusion criteria" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "number_of_rejected_subjects", + "isAbout": "items/number_of_rejected_subjects.jsonld", + "prefLabel": { + "en": "number of rejected subjects" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "group_comparison", + "isAbout": "items/group_comparison.jsonld", + "prefLabel": { + "en": "group comparison" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "group_description", + "isAbout": "items/group_description.jsonld", + "prefLabel": { + "en": "group description" + }, + "isVis": "group_comparison == 1", + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + } + ], + "allow": [ + "reproschema:AutoAdvance", + "reproschema:AllowExport" + ] + } +} diff --git a/ui/neurovault/activities/preprocessing/items/SoftwareName.jsonld b/ui/neurovault/activities/preprocessing/items/SoftwareName.jsonld new file mode 100644 index 00000000..e1a109b1 --- /dev/null +++ b/ui/neurovault/activities/preprocessing/items/SoftwareName.jsonld @@ -0,0 +1,23 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "SoftwareName.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "software package" + }, + "description": "software package", + "ui": { + "inputType": "select" + }, + "question": { + "en": "4.1 - If a single software package was used for all analyses, specify that here" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": "https://raw.githubusercontent.com/ohbm/cobidas_schema/master/response_options/mri_softwares.jsonld", + "minValue": 0, + "maxValue": 0 + } +} diff --git a/ui/neurovault/activities/preprocessing/items/SoftwareVersion.jsonld b/ui/neurovault/activities/preprocessing/items/SoftwareVersion.jsonld new file mode 100644 index 00000000..fd70d3ea --- /dev/null +++ b/ui/neurovault/activities/preprocessing/items/SoftwareVersion.jsonld @@ -0,0 +1,17 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "SoftwareVersion.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "software version" + }, + "description": "software version", + "ui": { + "inputType": "textarea" + }, + "question": { + "en": "4.2 - Version of software package used" + } +} diff --git a/ui/neurovault/activities/preprocessing/items/b0_unwarping_software.jsonld b/ui/neurovault/activities/preprocessing/items/b0_unwarping_software.jsonld new file mode 100644 index 00000000..b69bf97f --- /dev/null +++ b/ui/neurovault/activities/preprocessing/items/b0_unwarping_software.jsonld @@ -0,0 +1,23 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "b0_unwarping_software.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "b0 unwarping software" + }, + "description": "b0 unwarping software", + "ui": { + "inputType": "select" + }, + "question": { + "en": "4.6 - Specify software used for distortion correction if different from the main package" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": "https://raw.githubusercontent.com/ohbm/cobidas_schema/master/response_options/mri_softwares.jsonld", + "minValue": 0, + "maxValue": 0 + } +} diff --git a/ui/neurovault/activities/preprocessing/items/motion_correction_interpolation.jsonld b/ui/neurovault/activities/preprocessing/items/motion_correction_interpolation.jsonld new file mode 100644 index 00000000..5ae21815 --- /dev/null +++ b/ui/neurovault/activities/preprocessing/items/motion_correction_interpolation.jsonld @@ -0,0 +1,23 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "motion_correction_interpolation.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "motion correction interpolation" + }, + "description": "motion correction interpolation", + "ui": { + "inputType": "select" + }, + "question": { + "en": "4.13 - Interpolation method used for motion correction" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": "https://raw.githubusercontent.com/ohbm/cobidas_schema/master/response_options/interpolations.jsonld", + "minValue": 0, + "maxValue": 0 + } +} diff --git a/ui/neurovault/activities/preprocessing/items/motion_correction_metric.jsonld b/ui/neurovault/activities/preprocessing/items/motion_correction_metric.jsonld new file mode 100644 index 00000000..98ab1c42 --- /dev/null +++ b/ui/neurovault/activities/preprocessing/items/motion_correction_metric.jsonld @@ -0,0 +1,23 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "motion_correction_metric.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "motion correction metric" + }, + "description": "motion correction metric", + "ui": { + "inputType": "select" + }, + "question": { + "en": "4.12 - Similarity metric used for motion correction" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": "https://raw.githubusercontent.com/ohbm/cobidas_schema/master/response_options/cost_functions.jsonld", + "minValue": 0, + "maxValue": 0 + } +} diff --git a/ui/neurovault/activities/preprocessing/items/motion_correction_reference.jsonld b/ui/neurovault/activities/preprocessing/items/motion_correction_reference.jsonld new file mode 100644 index 00000000..9514078b --- /dev/null +++ b/ui/neurovault/activities/preprocessing/items/motion_correction_reference.jsonld @@ -0,0 +1,17 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "motion_correction_reference.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "motion correction reference" + }, + "description": "motion correction reference", + "ui": { + "inputType": "textarea" + }, + "question": { + "en": "4.11 - Reference scan used for motion correction" + } +} diff --git a/ui/neurovault/activities/preprocessing/items/motion_correction_software.jsonld b/ui/neurovault/activities/preprocessing/items/motion_correction_software.jsonld new file mode 100644 index 00000000..2b07c45c --- /dev/null +++ b/ui/neurovault/activities/preprocessing/items/motion_correction_software.jsonld @@ -0,0 +1,23 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "motion_correction_software.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "motion correction software" + }, + "description": "motion correction software", + "ui": { + "inputType": "select" + }, + "question": { + "en": "4.10 - Specify software used for motion correction if different from the main package" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": "https://raw.githubusercontent.com/ohbm/cobidas_schema/master/response_options/mri_softwares.jsonld", + "minValue": 0, + "maxValue": 0 + } +} diff --git a/ui/neurovault/activities/preprocessing/items/order_of_preprocessing_operations.jsonld b/ui/neurovault/activities/preprocessing/items/order_of_preprocessing_operations.jsonld new file mode 100644 index 00000000..b7f6a098 --- /dev/null +++ b/ui/neurovault/activities/preprocessing/items/order_of_preprocessing_operations.jsonld @@ -0,0 +1,17 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "order_of_preprocessing_operations.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "order of preprocessing operations" + }, + "description": "order of preprocessing operations", + "ui": { + "inputType": "textarea" + }, + "question": { + "en": "4.3 - Specify order of preprocessing operations" + } +} diff --git a/ui/neurovault/activities/preprocessing/items/quality_control.jsonld b/ui/neurovault/activities/preprocessing/items/quality_control.jsonld new file mode 100644 index 00000000..db0ab0e2 --- /dev/null +++ b/ui/neurovault/activities/preprocessing/items/quality_control.jsonld @@ -0,0 +1,17 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "quality_control.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "quality control" + }, + "description": "quality control", + "ui": { + "inputType": "textarea" + }, + "question": { + "en": "4.4 - Describe quality control measures" + } +} diff --git a/ui/neurovault/activities/preprocessing/items/slice_timing_correction_software.jsonld b/ui/neurovault/activities/preprocessing/items/slice_timing_correction_software.jsonld new file mode 100644 index 00000000..525a1439 --- /dev/null +++ b/ui/neurovault/activities/preprocessing/items/slice_timing_correction_software.jsonld @@ -0,0 +1,17 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "slice_timing_correction_software.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "slice timing correction software" + }, + "description": "slice timing correction software", + "ui": { + "inputType": "textarea" + }, + "question": { + "en": "4.8 - Specify software used for slice timing correction if different from the main package" + } +} diff --git a/ui/neurovault/activities/preprocessing/items/used_b0_unwarping.jsonld b/ui/neurovault/activities/preprocessing/items/used_b0_unwarping.jsonld new file mode 100644 index 00000000..edaf5c97 --- /dev/null +++ b/ui/neurovault/activities/preprocessing/items/used_b0_unwarping.jsonld @@ -0,0 +1,23 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "used_b0_unwarping.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "used b0 unwarping" + }, + "description": "used b0 unwarping", + "ui": { + "inputType": "radio" + }, + "question": { + "en": "4.5 - Was B0 distortion correction used?" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": "https://raw.githubusercontent.com/ohbm/cobidas_schema/master/response_options/boolean.jsonld", + "minValue": 0, + "maxValue": 0 + } +} diff --git a/ui/neurovault/activities/preprocessing/items/used_motion_correction.jsonld b/ui/neurovault/activities/preprocessing/items/used_motion_correction.jsonld new file mode 100644 index 00000000..42942532 --- /dev/null +++ b/ui/neurovault/activities/preprocessing/items/used_motion_correction.jsonld @@ -0,0 +1,23 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "used_motion_correction.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "used motion correction" + }, + "description": "used motion correction", + "ui": { + "inputType": "radio" + }, + "question": { + "en": "4.9 - Was motion correction used?" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": "https://raw.githubusercontent.com/ohbm/cobidas_schema/master/response_options/boolean.jsonld", + "minValue": 0, + "maxValue": 0 + } +} diff --git a/ui/neurovault/activities/preprocessing/items/used_motion_susceptibiity_correction.jsonld b/ui/neurovault/activities/preprocessing/items/used_motion_susceptibiity_correction.jsonld new file mode 100644 index 00000000..00c086b5 --- /dev/null +++ b/ui/neurovault/activities/preprocessing/items/used_motion_susceptibiity_correction.jsonld @@ -0,0 +1,23 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "used_motion_susceptibiity_correction.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "used motion susceptibiity correction" + }, + "description": "used motion susceptibiity correction", + "ui": { + "inputType": "radio" + }, + "question": { + "en": "4.14 - Was motion-susceptibility correction used?" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": "https://raw.githubusercontent.com/ohbm/cobidas_schema/master/response_options/boolean.jsonld", + "minValue": 0, + "maxValue": 0 + } +} diff --git a/ui/neurovault/activities/preprocessing/items/used_slice_timing_correction.jsonld b/ui/neurovault/activities/preprocessing/items/used_slice_timing_correction.jsonld new file mode 100644 index 00000000..a5d8c55e --- /dev/null +++ b/ui/neurovault/activities/preprocessing/items/used_slice_timing_correction.jsonld @@ -0,0 +1,23 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Field", + "@id": "used_slice_timing_correction.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "used slice timing correction" + }, + "description": "used slice timing correction", + "ui": { + "inputType": "radio" + }, + "question": { + "en": "4.7 - Was slice timing correction used?" + }, + "responseOptions": { + "valueType": "xsd:integer", + "choices": "https://raw.githubusercontent.com/ohbm/cobidas_schema/master/response_options/boolean.jsonld", + "minValue": 0, + "maxValue": 0 + } +} diff --git a/ui/neurovault/activities/preprocessing/preprocessing_schema.jsonld b/ui/neurovault/activities/preprocessing/preprocessing_schema.jsonld new file mode 100644 index 00000000..81b02fa5 --- /dev/null +++ b/ui/neurovault/activities/preprocessing/preprocessing_schema.jsonld @@ -0,0 +1,207 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Activity", + "@id": "preprocessing_schema.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "Preprocessing" + }, + "description": "preprocessing", + "preamble": { + "en": "

Source | Github repository | Reference

Describe your preprocessing

" + }, + "ui": { + "shuffle": false, + "order": [ + "items/SoftwareName.jsonld", + "items/SoftwareVersion.jsonld", + "items/order_of_preprocessing_operations.jsonld", + "items/quality_control.jsonld", + "items/used_b0_unwarping.jsonld", + "items/b0_unwarping_software.jsonld", + "items/used_slice_timing_correction.jsonld", + "items/slice_timing_correction_software.jsonld", + "items/used_motion_correction.jsonld", + "items/motion_correction_software.jsonld", + "items/motion_correction_reference.jsonld", + "items/motion_correction_metric.jsonld", + "items/motion_correction_interpolation.jsonld", + "items/used_motion_susceptibiity_correction.jsonld" + ], + "addProperties": [ + { + "variableName": "SoftwareName", + "isAbout": "items/SoftwareName.jsonld", + "prefLabel": { + "en": "software package" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "SoftwareVersion", + "isAbout": "items/SoftwareVersion.jsonld", + "prefLabel": { + "en": "software version" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "order_of_preprocessing_operations", + "isAbout": "items/order_of_preprocessing_operations.jsonld", + "prefLabel": { + "en": "order of preprocessing operations" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "quality_control", + "isAbout": "items/quality_control.jsonld", + "prefLabel": { + "en": "quality control" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "used_b0_unwarping", + "isAbout": "items/used_b0_unwarping.jsonld", + "prefLabel": { + "en": "used b0 unwarping" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "b0_unwarping_software", + "isAbout": "items/b0_unwarping_software.jsonld", + "prefLabel": { + "en": "b0 unwarping software" + }, + "isVis": "used_b0_unwarping == 1", + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "used_slice_timing_correction", + "isAbout": "items/used_slice_timing_correction.jsonld", + "prefLabel": { + "en": "used slice timing correction" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "slice_timing_correction_software", + "isAbout": "items/slice_timing_correction_software.jsonld", + "prefLabel": { + "en": "slice timing correction software" + }, + "isVis": "used_slice_timing_correction == 1", + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "used_motion_correction", + "isAbout": "items/used_motion_correction.jsonld", + "prefLabel": { + "en": "used motion correction" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "motion_correction_software", + "isAbout": "items/motion_correction_software.jsonld", + "prefLabel": { + "en": "motion correction software" + }, + "isVis": "used_motion_correction == 1", + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "motion_correction_reference", + "isAbout": "items/motion_correction_reference.jsonld", + "prefLabel": { + "en": "motion correction reference" + }, + "isVis": "used_motion_correction == 1", + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "motion_correction_metric", + "isAbout": "items/motion_correction_metric.jsonld", + "prefLabel": { + "en": "motion correction metric" + }, + "isVis": "used_motion_correction == 1", + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "motion_correction_interpolation", + "isAbout": "items/motion_correction_interpolation.jsonld", + "prefLabel": { + "en": "motion correction interpolation" + }, + "isVis": "used_motion_correction == 1", + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "used_motion_susceptibiity_correction", + "isAbout": "items/used_motion_susceptibiity_correction.jsonld", + "prefLabel": { + "en": "used motion susceptibiity correction" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + } + ], + "allow": [ + "reproschema:AutoAdvance", + "reproschema:AllowExport" + ] + } +} diff --git a/ui/neurovault/protocols/neurovault_schema.jsonld b/ui/neurovault/protocols/neurovault_schema.jsonld new file mode 100644 index 00000000..af243448 --- /dev/null +++ b/ui/neurovault/protocols/neurovault_schema.jsonld @@ -0,0 +1,133 @@ +{ + "@context": "https://raw.githubusercontent.com/ReproNim/reproschema/1.0.0-rc4/contexts/generic", + "@type": "reproschema:Protocol", + "@id": "neurovault_schema.jsonld", + "schemaVersion": "1.0.0-rc4", + "version": "0.0.1", + "prefLabel": { + "en": "neurovault" + }, + "description": "neurovault", + "preamble": { + "en": "" + }, + "ui": { + "shuffle": false, + "order": [ + "../activities/experimental_design/experimental_design_schema.jsonld", + "../activities/participants/participants_schema.jsonld", + "../activities/mri_acquisition/mri_acquisition_schema.jsonld", + "../activities/preprocessing/preprocessing_schema.jsonld", + "../activities/intersubject_registration/intersubject_registration_schema.jsonld", + "../activities/individual_subject_modeling/individual_subject_modeling_schema.jsonld", + "../activities/group_modeling/group_modeling_schema.jsonld", + "../activities/group_inference/group_inference_schema.jsonld" + ], + "addProperties": [ + { + "variableName": "experimental_design", + "isAbout": "../activities/experimental_design/experimental_design_schema.jsonld", + "prefLabel": { + "en": "Experimental design" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "participants", + "isAbout": "../activities/participants/participants_schema.jsonld", + "prefLabel": { + "en": "Participants" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "mri_acquisition", + "isAbout": "../activities/mri_acquisition/mri_acquisition_schema.jsonld", + "prefLabel": { + "en": "MRI acquisition" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "preprocessing", + "isAbout": "../activities/preprocessing/preprocessing_schema.jsonld", + "prefLabel": { + "en": "Preprocessing" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "intersubject_registration", + "isAbout": "../activities/intersubject_registration/intersubject_registration_schema.jsonld", + "prefLabel": { + "en": "Intersubject registration" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "individual_subject_modeling", + "isAbout": "../activities/individual_subject_modeling/individual_subject_modeling_schema.jsonld", + "prefLabel": { + "en": "Individual subject modeling" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "group_modeling", + "isAbout": "../activities/group_modeling/group_modeling_schema.jsonld", + "prefLabel": { + "en": "Group modeling" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + }, + { + "variableName": "group_inference", + "isAbout": "../activities/group_inference/group_inference_schema.jsonld", + "prefLabel": { + "en": "Group inference" + }, + "isVis": true, + "requiredValue": false, + "allow": [ + "reproschema:Skipped" + ] + } + ], + "allow": [ + "reproschema:AutoAdvance", + "reproschema:AllowExport" + ] + }, + "landingPage": { + "@id": "../README_eCOBIDAS-en.html", + "inLanguage": "en" + } +} diff --git a/ui/requirements.txt b/ui/requirements.txt new file mode 100644 index 00000000..1698b1f4 --- /dev/null +++ b/ui/requirements.txt @@ -0,0 +1,3 @@ +flask +Flask-WTF +bootstrap-flask diff --git a/ui/templates/404.html b/ui/templates/404.html new file mode 100644 index 00000000..a822154d --- /dev/null +++ b/ui/templates/404.html @@ -0,0 +1,14 @@ +{% extends 'base.html' %} {% block title %} 404 Error - Page Not Found {% +endblock %} {% block content %} + +
+
+
+

Page not found (Error 404)

+ +

Go to search page

+
+
+
+ +{% endblock %} diff --git a/ui/templates/500.html b/ui/templates/500.html new file mode 100644 index 00000000..c308186c --- /dev/null +++ b/ui/templates/500.html @@ -0,0 +1,14 @@ +{% extends 'base.html' %} {% block title %} 500 Error - Internal Server Error {% +endblock %} {% block content %} + +
+
+
+

Internal server error (500)

+ +

Go to search page

+
+
+
+ +{% endblock %} diff --git a/ui/templates/about.html b/ui/templates/about.html new file mode 100644 index 00000000..21f5da26 --- /dev/null +++ b/ui/templates/about.html @@ -0,0 +1 @@ +{% extends 'base.html' %} diff --git a/ui/templates/activity.html b/ui/templates/activity.html new file mode 100644 index 00000000..0e43cc54 --- /dev/null +++ b/ui/templates/activity.html @@ -0,0 +1,14 @@ +{% extends 'base.html' %} {% from 'bootstrap5/form.html' import render_form %} +{% block content %} + +
+
+
+

{{ prefLabel }}

+ + {{ preamble }} {{ render_form(form) }} +
+
+ + {% endblock %} +
diff --git a/ui/templates/base.html b/ui/templates/base.html new file mode 100644 index 00000000..883623a5 --- /dev/null +++ b/ui/templates/base.html @@ -0,0 +1,52 @@ +{% from 'bootstrap4/nav.html' import render_nav_item %} + + + + + + + + {% block title %} {% endblock %} + + {{ bootstrap.load_css() }} + + + + + + + +
+
+
+

eCOBIDAS

+
+
+ + + + {% block content %} {% endblock %} + + + {{ bootstrap.load_js() }} +
+ + +
+
+
+
eCOBIDAS
+
+
+
+ diff --git a/ui/templates/index.html b/ui/templates/index.html new file mode 100644 index 00000000..fd220352 --- /dev/null +++ b/ui/templates/index.html @@ -0,0 +1,18 @@ +{% extends 'base.html' %} {% block title %} TBD {% endblock %} {% block content +%} + + + +
+
+
+

TBD

+
+
+
+ +{% endblock %} From 69a273a001c17951d47498ba4099ef44ca0fa21b Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Tue, 21 May 2024 09:02:18 -0400 Subject: [PATCH 02/31] add protocol page --- ui/{forms.py => app.py} | 84 ++++++++++++++++++++++++++++----- ui/modules.py | 18 +++++++ ui/templates/activity.html | 2 +- ui/templates/base.html | 30 +++++++----- ui/templates/new_checklist.html | 1 + ui/templates/protocol.html | 26 ++++++++++ 6 files changed, 138 insertions(+), 23 deletions(-) rename ui/{forms.py => app.py} (71%) create mode 100644 ui/templates/new_checklist.html create mode 100644 ui/templates/protocol.html diff --git a/ui/forms.py b/ui/app.py similarity index 71% rename from ui/forms.py rename to ui/app.py index 15a228c7..debce858 100644 --- a/ui/forms.py +++ b/ui/app.py @@ -1,11 +1,12 @@ from functools import lru_cache +from pathlib import Path import requests from flask import Flask, render_template from flask_bootstrap import Bootstrap5 from flask_wtf import CSRFProtect, FlaskForm from markupsafe import Markup, escape -from modules import activity_url, get_activity, get_item +from modules import activity_url, get_activity, get_item, get_protocol, protocol_url from rich import print from wtforms import ( DecimalField, @@ -46,6 +47,20 @@ def query_choices(url): return data +@lru_cache +def get_landing_page(url: Path): + try: + if str(url).startswith("https:"): + data = requests.get(url) + else: + with open(url) as f: + data = f.read() + except Exception as exc: + print(exc) + data = None + return data + + @app.route("/", methods=["GET", "POST"]) def index(): return render_template("index.html") @@ -56,7 +71,39 @@ def about(): return render_template("about.html") -@app.route("//", methods=["GET", "POST"]) +@app.route("/new") +def new(): + return render_template("new_checklist.html") + + +@app.route("/protocol/", methods=["GET", "POST"]) +def protocol(protocol_name): + + protocol_content = get_protocol(protocol_name) + + landing_page_url = protocol_url(protocol_name).parent / protocol_content["landingPage"]["@id"] + landing_page = get_landing_page(landing_page_url) + + activities = [ + {"name": "Start", "link": f"/protocol/{protocol_name}"}, + ] + activities.extend( + { + "name": activity["prefLabel"][LANG], + "link": f"/protocol/{protocol_name}/{activity['variableName']}", + } + for activity in protocol_content["ui"]["addProperties"] + ) + return render_template( + "protocol.html", + prefLabel=protocol_name, + preamble=protocol_content["preamble"][LANG], + activities=activities, + landing_page=Markup(landing_page), + ) + + +@app.route("/protocol//", methods=["GET", "POST"]) def activity(protocol_name, activity_name): protocol_name = escape(protocol_name) activity_name = escape(activity_name) @@ -68,15 +115,8 @@ def activity(protocol_name, activity_name): form = generate_form(items) if form.validate_on_submit(): - for item, values in items.items(): - isVis = values["isVis"] - if isinstance(isVis, str): - isVis = isVis.replace(" ", "").split("==") - if len(isVis) == 2: - response = form[isVis[0]].data - value = items[isVis[0]]["choices"].get(response) - expected = int(isVis[1]) - items[item]["visibility"] = value == expected + + items = update_visbility(items, form) form = generate_form(items) @@ -95,6 +135,23 @@ def activity(protocol_name, activity_name): ) +def update_visbility(items, form): + for item, values in items.items(): + isVis = values["isVis"] + if isinstance(isVis, str): + isVis = isVis.replace(" ", "").split("==") + if len(isVis) > 2: + app.logger.warning("More than 1 '=='") + if len(isVis) < 2: + app.logger.warning(f"Unsupported JavaScript expression: {isVis}") + if len(isVis) == 2: + response = form[isVis[0]].data + value = items[isVis[0]]["choices"].get(response) + expected = int(isVis[1]) + items[item]["visibility"] = value == expected + return items + + def generate_form(items): for item_name, item in items.items(): @@ -118,13 +175,17 @@ def generate_form(items): input_type = item["input_type"] + default = None + if input_type not in ["select", "radio", "slider"]: FieldType = StringField if input_type == "number": FieldType = IntegerField + default = 0 elif input_type in ["float", "slider"]: FieldType = DecimalField + default = 0 elif input_type == "textarea": FieldType = TextAreaField @@ -135,6 +196,7 @@ def generate_form(items): Markup(question), validators=validators, description=item["description"], + default=default, ), ) diff --git a/ui/modules.py b/ui/modules.py index 72b4053b..8657eeb7 100644 --- a/ui/modules.py +++ b/ui/modules.py @@ -15,6 +15,24 @@ def activity_url(protocol_name, activity_name): ) +def protocol_url(protocol_name): + return ( + Path(__file__).parents[1] + / "cobidas_schema" + / "schemas" + / protocol_name + / "protocols" + / f"{protocol_name}_schema.jsonld" + ) + + +def get_protocol(protocol_name): + file = protocol_url(protocol_name) + with open(file) as f: + content = json.load(f) + return content + + def get_activity(protocol_name, activity_name): file = activity_url(protocol_name, activity_name) with open(file) as f: diff --git a/ui/templates/activity.html b/ui/templates/activity.html index 0e43cc54..8c40abd2 100644 --- a/ui/templates/activity.html +++ b/ui/templates/activity.html @@ -3,7 +3,7 @@
-
+

{{ prefLabel }}

{{ preamble }} {{ render_form(form) }} diff --git a/ui/templates/base.html b/ui/templates/base.html index 883623a5..97a25bf5 100644 --- a/ui/templates/base.html +++ b/ui/templates/base.html @@ -23,19 +23,25 @@
-
+

eCOBIDAS

- - - {% block content %} {% endblock %} +
{{ bootstrap.load_js() }} @@ -43,9 +49,11 @@

eCOBIDAS

-
-
-
eCOBIDAS
+
+
+
+
eCOBIDAS
+
diff --git a/ui/templates/new_checklist.html b/ui/templates/new_checklist.html new file mode 100644 index 00000000..21f5da26 --- /dev/null +++ b/ui/templates/new_checklist.html @@ -0,0 +1 @@ +{% extends 'base.html' %} diff --git a/ui/templates/protocol.html b/ui/templates/protocol.html new file mode 100644 index 00000000..993301ef --- /dev/null +++ b/ui/templates/protocol.html @@ -0,0 +1,26 @@ +{% extends 'base.html' %} {% from 'bootstrap5/form.html' import render_form %} +{% block content %} + +
+
+

{{ prefLabel }}

+ {{ preamble }} +
+ +
+
{{ landing_page }}
+
+
+ +{% endblock %} From c6920d289a6837118bef215d1f2722961d44badb Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Tue, 21 May 2024 09:43:41 -0400 Subject: [PATCH 03/31] display activity in protocol page --- ui/app.py | 53 ++++++++++++++++++++++++++------------ ui/templates/activity.html | 14 ---------- ui/templates/protocol.html | 12 +++++---- 3 files changed, 44 insertions(+), 35 deletions(-) delete mode 100644 ui/templates/activity.html diff --git a/ui/app.py b/ui/app.py index debce858..1a72ae09 100644 --- a/ui/app.py +++ b/ui/app.py @@ -84,8 +84,21 @@ def protocol(protocol_name): landing_page_url = protocol_url(protocol_name).parent / protocol_content["landingPage"]["@id"] landing_page = get_landing_page(landing_page_url) + activities = get_nav_bar_content(protocol_name) + + return render_template( + "protocol.html", + protocol_pref_label=protocol_name, + protocol_preamble=protocol_content["preamble"][LANG], + activities=activities, + landing_page=Markup(landing_page), + ) + + +def get_nav_bar_content(protocol_name, activity_name=None): + protocol_content = get_protocol(protocol_name) activities = [ - {"name": "Start", "link": f"/protocol/{protocol_name}"}, + {"name": "Start", "link": "#"}, ] activities.extend( { @@ -94,13 +107,12 @@ def protocol(protocol_name): } for activity in protocol_content["ui"]["addProperties"] ) - return render_template( - "protocol.html", - prefLabel=protocol_name, - preamble=protocol_content["preamble"][LANG], - activities=activities, - landing_page=Markup(landing_page), - ) + if activity_name: + activities[0]["link"] = f"/protocol/{protocol_name}" + for activity in activities: + if activity["name"] == activity_name: + activity["link"] = "#" + return activities @app.route("/protocol//", methods=["GET", "POST"]) @@ -110,9 +122,11 @@ def activity(protocol_name, activity_name): activity = get_activity(protocol_name, activity_name) + activities = get_nav_bar_content(protocol_name, activity["prefLabel"][LANG]) + items = get_items_for_activity(protocol_name, activity_name) - form = generate_form(items) + form = generate_form(items, prefix=activity_name) if form.validate_on_submit(): @@ -121,16 +135,20 @@ def activity(protocol_name, activity_name): form = generate_form(items) return render_template( - "activity.html", - prefLabel=activity["prefLabel"][LANG], - preamble=Markup(activity["preamble"][LANG]), + "protocol.html", + protocol_pref_label=protocol_name, + activity_pref_label=activity["prefLabel"][LANG], + activity_preamble=Markup(activity["preamble"][LANG]), + activities=activities, form=form, ) return render_template( - "activity.html", - prefLabel=activity["prefLabel"][LANG], - preamble=Markup(activity["preamble"][LANG]), + "protocol.html", + protocol_pref_label=protocol_name, + activity_pref_label=activity["prefLabel"][LANG], + activity_preamble=Markup(activity["preamble"][LANG]), + activities=activities, form=form, ) @@ -152,7 +170,7 @@ def update_visbility(items, form): return items -def generate_form(items): +def generate_form(items, prefix): for item_name, item in items.items(): validators = [] @@ -169,6 +187,7 @@ def generate_form(items): Markup(question), validators=validators, description=item["description"], + _prefix=prefix, ), ) continue @@ -197,6 +216,7 @@ def generate_form(items): validators=validators, description=item["description"], default=default, + _prefix=prefix, ), ) @@ -219,6 +239,7 @@ def generate_form(items): validators=validators, description=item["description"], choices=[key for key in item["choices"]], + _prefix=prefix, ), ) diff --git a/ui/templates/activity.html b/ui/templates/activity.html deleted file mode 100644 index 8c40abd2..00000000 --- a/ui/templates/activity.html +++ /dev/null @@ -1,14 +0,0 @@ -{% extends 'base.html' %} {% from 'bootstrap5/form.html' import render_form %} -{% block content %} - -
-
-
-

{{ prefLabel }}

- - {{ preamble }} {{ render_form(form) }} -
-
- - {% endblock %} -
diff --git a/ui/templates/protocol.html b/ui/templates/protocol.html index 993301ef..2b50fce6 100644 --- a/ui/templates/protocol.html +++ b/ui/templates/protocol.html @@ -1,10 +1,9 @@ {% extends 'base.html' %} {% from 'bootstrap5/form.html' import render_form %} {% block content %} -
-

{{ prefLabel }}

- {{ preamble }} +

{{ protocol_pref_label }}

+ {% if landing_page %} {{ protocol_preamble }} {% endif %}
-
{{ landing_page }}
+
+ {% if landing_page %} {{ landing_page }} {% else %} +

{{ activity_pref_label }}

+ {{ activity_preamble }} {{ render_form(form) }} {% endif %} +
- {% endblock %} From db86e449b98f47a8934476052c688a23a7c045c7 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Tue, 21 May 2024 10:03:09 -0400 Subject: [PATCH 04/31] fix issue new instance form --- ui/app.py | 54 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/ui/app.py b/ui/app.py index 1a72ae09..e112f363 100644 --- a/ui/app.py +++ b/ui/app.py @@ -2,7 +2,7 @@ from pathlib import Path import requests -from flask import Flask, render_template +from flask import Flask, render_template, request from flask_bootstrap import Bootstrap5 from flask_wtf import CSRFProtect, FlaskForm from markupsafe import Markup, escape @@ -33,10 +33,6 @@ csrf = CSRFProtect(app) -class DyanmicForm(FlaskForm): - pass - - @lru_cache def query_choices(url): try: @@ -117,6 +113,7 @@ def get_nav_bar_content(protocol_name, activity_name=None): @app.route("/protocol//", methods=["GET", "POST"]) def activity(protocol_name, activity_name): + protocol_name = escape(protocol_name) activity_name = escape(activity_name) @@ -126,22 +123,26 @@ def activity(protocol_name, activity_name): items = get_items_for_activity(protocol_name, activity_name) - form = generate_form(items, prefix=activity_name) + if request.method == "POST": - if form.validate_on_submit(): + form = generate_form(form=None, items=items, prefix=activity_name) - items = update_visbility(items, form) + if form.validate_on_submit(): - form = generate_form(items) + items = update_visbility(items, form) - return render_template( - "protocol.html", - protocol_pref_label=protocol_name, - activity_pref_label=activity["prefLabel"][LANG], - activity_preamble=Markup(activity["preamble"][LANG]), - activities=activities, - form=form, - ) + form = generate_form(items) + + return render_template( + "protocol.html", + protocol_pref_label=protocol_name, + activity_pref_label=activity["prefLabel"][LANG], + activity_preamble=Markup(activity["preamble"][LANG]), + activities=activities, + form=form, + ) + + form = generate_form(form=None, items=items, prefix=activity_name) return render_template( "protocol.html", @@ -170,7 +171,14 @@ def update_visbility(items, form): return items -def generate_form(items, prefix): +def generate_form(form=None, items=None, prefix=None): + + class DyanmicForm(FlaskForm): + pass + + if form is None: + form = DyanmicForm + for item_name, item in items.items(): validators = [] @@ -181,7 +189,7 @@ def generate_form(items, prefix): if not item["visibility"]: setattr( - DyanmicForm, + form, item_name, HiddenField( Markup(question), @@ -209,7 +217,7 @@ def generate_form(items, prefix): FieldType = TextAreaField setattr( - DyanmicForm, + form, item_name, FieldType( Markup(question), @@ -232,7 +240,7 @@ def generate_form(items, prefix): FieldType = RadioField setattr( - DyanmicForm, + form, item_name, FieldType( Markup(question), @@ -243,9 +251,9 @@ def generate_form(items, prefix): ), ) - setattr(DyanmicForm, "submit", SubmitField("Submit")) # noqa B010 + setattr(form, "submit", SubmitField("Submit")) # noqa B010 - return DyanmicForm() + return form() def get_items_for_activity(protocol_name, activity_name): From 1371a632c85f4ace1e3b4b6d9b46e2b5f774383e Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Tue, 21 May 2024 17:50:14 -0400 Subject: [PATCH 05/31] fix path activity --- ui/app.py | 147 +++++++++++++++++++++++++------------ ui/modules.py | 28 ++----- ui/templates/base.html | 47 +++++++++--- ui/templates/protocol.html | 4 +- 4 files changed, 144 insertions(+), 82 deletions(-) diff --git a/ui/app.py b/ui/app.py index e112f363..7db1a105 100644 --- a/ui/app.py +++ b/ui/app.py @@ -1,29 +1,32 @@ +import json from functools import lru_cache from pathlib import Path +from typing import Any import requests from flask import Flask, render_template, request from flask_bootstrap import Bootstrap5 from flask_wtf import CSRFProtect, FlaskForm from markupsafe import Markup, escape -from modules import activity_url, get_activity, get_item, get_protocol, protocol_url +from modules import get_item, get_protocol, protocol_url from rich import print from wtforms import ( + DateField, DecimalField, HiddenField, IntegerField, - MultipleFileField, RadioField, SelectField, + SelectMultipleField, StringField, SubmitField, TextAreaField, ) from wtforms.validators import DataRequired -LANG = "en" +LANG: str = "en" -app = Flask(__name__) +app: Flask = Flask(__name__) app.secret_key = "tO$&!|0wkamvVia0?n$NqIRVWOG" # Bootstrap-Flask requires this line @@ -34,7 +37,7 @@ @lru_cache -def query_choices(url): +def query_choices(url: str) -> None | dict[str, Any]: try: data = requests.get(url).json() except Exception as exc: @@ -44,13 +47,12 @@ def query_choices(url): @lru_cache -def get_landing_page(url: Path): +def get_landing_page(url: Path) -> None | dict[str, Any]: try: if str(url).startswith("https:"): data = requests.get(url) else: - with open(url) as f: - data = f.read() + data = Path(url).read_text() except Exception as exc: print(exc) data = None @@ -58,22 +60,22 @@ def get_landing_page(url: Path): @app.route("/", methods=["GET", "POST"]) -def index(): +def index() -> str: return render_template("index.html") @app.route("/about") -def about(): +def about() -> str: return render_template("about.html") @app.route("/new") -def new(): +def new() -> str: return render_template("new_checklist.html") @app.route("/protocol/", methods=["GET", "POST"]) -def protocol(protocol_name): +def protocol(protocol_name: str) -> str: protocol_content = get_protocol(protocol_name) @@ -91,58 +93,84 @@ def protocol(protocol_name): ) -def get_nav_bar_content(protocol_name, activity_name=None): +def sort_ui_properties(properties: list[dict[str, Any]], order: list[str]) -> list[dict[str, Any]]: + tmp = [] + for i in order: + for prop in properties: + if prop["isAbout"] == i: + tmp.append(prop) + break + return tmp + + +def get_nav_bar_content( + protocol_name: str, activity_name: str | None = None +) -> list[dict[str, str]]: protocol_content = get_protocol(protocol_name) + + order = protocol_content["ui"]["order"] + properties = protocol_content["ui"]["addProperties"] + properties = sort_ui_properties(properties=properties, order=order) + activities = [ - {"name": "Start", "link": "#"}, + {"name": "Start", "link": "#", "class": "nav-link active"}, ] activities.extend( { "name": activity["prefLabel"][LANG], "link": f"/protocol/{protocol_name}/{activity['variableName']}", + "class": "nav-link", } - for activity in protocol_content["ui"]["addProperties"] + for activity in properties ) + if activity_name: activities[0]["link"] = f"/protocol/{protocol_name}" + activities[0]["class"] = "nav-link" for activity in activities: if activity["name"] == activity_name: activity["link"] = "#" + activity["class"] = "nav-link active" + return activities @app.route("/protocol//", methods=["GET", "POST"]) -def activity(protocol_name, activity_name): +def activity(protocol_name, activity_name) -> str: protocol_name = escape(protocol_name) activity_name = escape(activity_name) - activity = get_activity(protocol_name, activity_name) - - activities = get_nav_bar_content(protocol_name, activity["prefLabel"][LANG]) - - items = get_items_for_activity(protocol_name, activity_name) + protocol_content = get_protocol(protocol_name) + properties = protocol_content["ui"]["addProperties"] + for activity in properties: + if activity["variableName"] == activity_name: + is_about_activity = activity["isAbout"] + break + activity_file = protocol_url(protocol_name).parent / is_about_activity - if request.method == "POST": + with open(activity_file) as f: + activity = json.load(f) - form = generate_form(form=None, items=items, prefix=activity_name) + activities = get_nav_bar_content(protocol_name, activity["prefLabel"][LANG]) - if form.validate_on_submit(): + items = get_items_for_activity(activity_file) - items = update_visbility(items, form) + form = generate_form(items=items, prefix=activity_name) - form = generate_form(items) + if request.method == "POST" and form.validate_on_submit(): + items = update_visibility(items, form) - return render_template( - "protocol.html", - protocol_pref_label=protocol_name, - activity_pref_label=activity["prefLabel"][LANG], - activity_preamble=Markup(activity["preamble"][LANG]), - activities=activities, - form=form, - ) + form = generate_form(items, prefix=activity_name) - form = generate_form(form=None, items=items, prefix=activity_name) + return render_template( + "protocol.html", + protocol_pref_label=protocol_name, + activity_pref_label=activity["prefLabel"][LANG], + activity_preamble=Markup(activity["preamble"][LANG]), + activities=activities, + form=form, + ) return render_template( "protocol.html", @@ -154,7 +182,7 @@ def activity(protocol_name, activity_name): ) -def update_visbility(items, form): +def update_visibility(items: dict[str, Any], form): for item, values in items.items(): isVis = values["isVis"] if isinstance(isVis, str): @@ -171,13 +199,12 @@ def update_visbility(items, form): return items -def generate_form(form=None, items=None, prefix=None): +def generate_form(items=None, prefix=None): class DyanmicForm(FlaskForm): pass - if form is None: - form = DyanmicForm + form = DyanmicForm for item_name, item in items.items(): @@ -204,13 +231,32 @@ class DyanmicForm(FlaskForm): default = None - if input_type not in ["select", "radio", "slider"]: + if input_type == "date": + + print(item_name) + + FieldType = DateField + + setattr( + form, + item_name, + FieldType( + Markup(question), + validators=validators, + description=item["description"], + default=default, + _prefix=prefix, + format="%Y-%m-%d", + ), + ) + + elif input_type not in ["select", "radio", "slider"]: FieldType = StringField if input_type == "number": FieldType = IntegerField default = 0 - elif input_type in ["float", "slider"]: + elif input_type in ["float"]: FieldType = DecimalField default = 0 elif input_type == "textarea": @@ -233,10 +279,10 @@ class DyanmicForm(FlaskForm): is_multiple = item["is_multiple"] if is_multiple: - FieldType = MultipleFileField + FieldType = SelectMultipleField if input_type == "select": FieldType = SelectField - elif input_type == "radio": + elif input_type in ["radio", "slider"]: FieldType = RadioField setattr( @@ -256,15 +302,20 @@ class DyanmicForm(FlaskForm): return form() -def get_items_for_activity(protocol_name, activity_name): - # TODO make sure items are presented in the right order - activity = get_activity(protocol_name, activity_name) +def get_items_for_activity(activity_file): + with open(activity_file) as f: + activity = json.load(f) + + order = activity["ui"]["order"] + properties = activity["ui"]["addProperties"] + properties = sort_ui_properties(properties=properties, order=order) + items = {} - for item in activity["ui"]["addProperties"]: + for item in properties: item_name = item["variableName"] - item_data = get_item(activity_url(protocol_name, activity_name).parent / item["isAbout"]) + item_data = get_item(activity_file.parent / item["isAbout"]) tmp = { "visibility": False, diff --git a/ui/modules.py b/ui/modules.py index 8657eeb7..d59e66ed 100644 --- a/ui/modules.py +++ b/ui/modules.py @@ -1,21 +1,11 @@ # functions to be used by the routes import json +from functools import lru_cache from pathlib import Path +from typing import Any -def activity_url(protocol_name, activity_name): - return ( - Path(__file__).parents[1] - / "cobidas_schema" - / "schemas" - / protocol_name - / "activities" - / activity_name - / f"{activity_name}_schema.jsonld" - ) - - -def protocol_url(protocol_name): +def protocol_url(protocol_name: Path) -> Path: return ( Path(__file__).parents[1] / "cobidas_schema" @@ -26,21 +16,15 @@ def protocol_url(protocol_name): ) -def get_protocol(protocol_name): +@lru_cache +def get_protocol(protocol_name: str) -> dict[str, Any]: file = protocol_url(protocol_name) with open(file) as f: content = json.load(f) return content -def get_activity(protocol_name, activity_name): - file = activity_url(protocol_name, activity_name) - with open(file) as f: - content = json.load(f) - return content - - -def get_item(file): +def get_item(file: Path) -> dict[str, Any]: with open(file) as f: content = json.load(f) return content diff --git a/ui/templates/base.html b/ui/templates/base.html index 97a25bf5..bee7f598 100644 --- a/ui/templates/base.html +++ b/ui/templates/base.html @@ -1,5 +1,3 @@ -{% from 'bootstrap4/nav.html' import render_nav_item %} - @@ -30,14 +28,43 @@

eCOBIDAS

- + {% block content %} {% endblock %}
diff --git a/ui/templates/protocol.html b/ui/templates/protocol.html index 2b50fce6..7d6d6492 100644 --- a/ui/templates/protocol.html +++ b/ui/templates/protocol.html @@ -5,11 +5,11 @@

{{ protocol_pref_label }}

{% if landing_page %} {{ protocol_preamble }} {% endif %}
-
@@ -140,10 +156,26 @@
-
-
-
-
eCOBIDAS
+
+
+
+
+ eCobidas +
+
+ + +
diff --git a/ui/ecobidas_ui/templates/index.html b/ui/ecobidas_ui/templates/index.html index fd220352..3c79b76a 100644 --- a/ui/ecobidas_ui/templates/index.html +++ b/ui/ecobidas_ui/templates/index.html @@ -1,12 +1,8 @@ -{% extends 'base.html' %} {% block title %} TBD {% endblock %} {% block content -%} - - - +{% extends 'base.html' %} + +{% block title %} eCOBIDAS {% endblock %} + +{% block content %}
@@ -14,5 +10,4 @@

TBD

- {% endblock %} diff --git a/ui/ecobidas_ui/templates/protocol.html b/ui/ecobidas_ui/templates/protocol.html index 09831912..8af5b156 100644 --- a/ui/ecobidas_ui/templates/protocol.html +++ b/ui/ecobidas_ui/templates/protocol.html @@ -1,18 +1,23 @@ {% extends 'base.html' %} {% from 'bootstrap5/form.html' import render_form %} + +{% block title %} eCOBIDAS - {{ protocol_pref_label }} {% endblock %} + {% block content %}
-

{{ protocol_pref_label }}

+

+ {{ protocol_pref_label }} +

diff --git a/ui/ecobidas_ui/templates/500.html b/ui/ecobidas_ui/templates/500.html index fa47eb51..54defb2f 100644 --- a/ui/ecobidas_ui/templates/500.html +++ b/ui/ecobidas_ui/templates/500.html @@ -7,6 +7,7 @@

Internal server error (500)

+

Go to search page

diff --git a/ui/ecobidas_ui/templates/index.html b/ui/ecobidas_ui/templates/index.html index 3c79b76a..7ae6f3a8 100644 --- a/ui/ecobidas_ui/templates/index.html +++ b/ui/ecobidas_ui/templates/index.html @@ -7,6 +7,16 @@

TBD

+ +

+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod + tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim + veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea + commodo consequat. Duis aute irure dolor in reprehenderit in voluptate + velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint + occaecat cupidatat non proident, sunt in culpa qui officia deserunt + mollit anim id est laborum." +

diff --git a/ui/ecobidas_ui/templates/protocol.html b/ui/ecobidas_ui/templates/protocol.html index 8af5b156..8cf318ee 100644 --- a/ui/ecobidas_ui/templates/protocol.html +++ b/ui/ecobidas_ui/templates/protocol.html @@ -21,6 +21,20 @@

> {% endfor %} + +

diff --git a/ui/ecobidas_ui/utils.py b/ui/ecobidas_ui/utils.py index 87ff25c8..7603dbb1 100644 --- a/ui/ecobidas_ui/utils.py +++ b/ui/ecobidas_ui/utils.py @@ -154,7 +154,7 @@ def get_items_for_activity(activity_file): tmp["input_type"] = item_data["ui"]["inputType"] tmp["description"] = ( - "
Details" + "
Details" "
    " f"
  • item name: {item_data.get('description')}
  • " "
" From 4e2346d86bd4e719a55d26fa3c9af291f89add39 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Fri, 24 May 2024 22:32:11 -0400 Subject: [PATCH 16/31] update visbility handling --- ecobidas/download_tsv.py | 20 +++ ecobidas/inputs/neurovault/neurovault.tsv | 174 +++++++++++----------- ui/ecobidas_ui/protocol.py | 28 ++-- 3 files changed, 126 insertions(+), 96 deletions(-) diff --git a/ecobidas/download_tsv.py b/ecobidas/download_tsv.py index 2cc2dc74..792503ce 100644 --- a/ecobidas/download_tsv.py +++ b/ecobidas/download_tsv.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 """Download the content of the different google spreadsheet in the inputs folder.""" +import ast import json from pathlib import Path @@ -95,6 +96,25 @@ def validate_downloaded_file(file: str | Path) -> None: f"\nThe following columns are missing from the data dictionary: {sorted(extra_columns)}" ) + invalid_vis = [] + visibility = df.visibility.values + for vis in visibility: + if not is_valid_python(vis): + invalid_vis.append(vis) + if invalid_vis: + logger.warning(f"\nThe following visibility are not valid python:\n{invalid_vis}") + + +def is_valid_python(code): + try: + ast.parse(code) + except SyntaxError: + return False + except ValueError as exc: + print(f"{exc}: {code}") + return True + return True + def main() -> None: # validates files diff --git a/ecobidas/inputs/neurovault/neurovault.tsv b/ecobidas/inputs/neurovault/neurovault.tsv index 327e1d07..c9a9c56c 100644 --- a/ecobidas/inputs/neurovault/neurovault.tsv +++ b/ecobidas/inputs/neurovault/neurovault.tsv @@ -1,88 +1,88 @@ activity_pref_label activity_order item_order question unit details field_type choices item item_pref_label visibility item_description include mandatory preamble bids_status bids_file bids_key bids_key_for_unit UUID -Experimental design 1 1 Type of design select blocked | event_related | hybrid block/event type_of_design type of design 1 type of design 1 1 Describe your experimental design 76c35f93-23e1-43b7-8f47-59b9e229cb71 -Experimental design 1 2 Number of imaging runs acquired integer 0 number of imaging runs 1 number of imaging runs 1 2 77423b25-3ee4-472b-bb25-8e9415189030 -Experimental design 1 3 Number of blocks, trials or experimental units per imaging run integer 0 number of experimental units 1 number of experimental units 1 2 131a5855-3fad-4b69-a9dd-a842cd7742d3 -Experimental design 1 4 Length of each imaging run seconds float 0 length of runs 1 length of runs 1 2 0b12a719-f6b8-4d1b-a353-d888d2d2fc7d -Experimental design 1 5 For blocked designs, length of blocks seconds float 0 length of blocks type_of_design in [0, 2] length of blocks 1 2 4e963713-4274-4cc3-addd-5b04f612b082 -Experimental design 1 6 Length of individual trials seconds float 0 length of trials 1 length of trials 1 2 63f7be62-80d4-4e8a-8dbb-dcb4441234de -Experimental design 1 7 Was the design optimized for efficiency? radio preset:boolean optimization 1 optimization 1 2 4bc92eea-ce45-40ce-8b2b-add6d5683585 -Experimental design 1 8 What method was used for optimization? textarea optimization method optimization == 1 optimization method 1 3 dbea3306-ad68-41de-8f5c-626bf878636d -Participants 2 1 Number of subjects entering into the analysis integer 0 number of subjects 1 number of subjects 1 1 Describe your participant sample 44bcca72-a745-4b9f-917b-2571eb73a695 -Participants 2 2 Mean age of subjects float 0 subject age mean 1 subject age mean 1 1 648db98e-e5ec-41a5-b6d4-f762bf8be2ea -Participants 2 3 Minimum age of subjects float 0 subject age min 1 subject age min 1 2 2a202af9-86c7-4cd0-95f6-2cf328608f54 -Participants 2 4 Maximum age of subjects float 0 subject age max 1 subject age max 1 2 933b1e07-9af1-4d99-adf9-81d8669dbe44 -Participants 2 5 Handedness of subjects radio right | left | both handedness 1 handedness 1 2 906b037e-b686-44a6-8440-5a05df6fe63c -Participants 2 6 The proportion of subjects who were male float 0 | 1 proportion male subjects 1 proportion male subjects 1 2 640df132-8c2e-4cd4-beee-97d9d64336a3 -Participants 2 7 Additional inclusion/exclusion criteria, if any. Including specific sampling strategies that limit inclusion to a specific group, such as laboratory members. textarea inclusion exclusion criteria 1 inclusion exclusion criteria 1 3 e061db40-8413-4ba0-ab20-1eeb89658a25 -Participants 2 8 Number of subjects scanned but rejected from analysis integer 0 number of rejected subjects 1 number of rejected subjects 1 2 6cc3460e-826f-4faf-bb4e-e66d78ab68af -Participants 2 9 Was this study a comparison between subject groups? radio preset:boolean group comparison 1 group comparison 1 1 0374fada-67e6-4d57-abf8-b0e4bd894ac4 -Participants 2 10 A description of the groups being compared textarea group description group_comparison == 1 group description 1 2 b27a7735-0393-479a-a9ee-f9e17decf720 -MRI acquisition 3 1 Manufacturer of MRI scanner select Siemens | Philips | General Electric | other Manufacturer scanner make 1 scanner make 1 1 Describe your acquisition parameters 19204f74-3646-4777-9a62-edff13947f59 -MRI acquisition 3 2 Model of MRI scanner textarea ManufacturersModelName scanner model 1 scanner model 1 1 3adcef71-b057-46ea-84e1-402c2deea39f -MRI acquisition 3 3 Field strength of MRI scanner Tesla float 0 MagneticFieldStrength field strength 1 field strength 1 1 2e7f18e2-b2e3-4310-9eb8-ff666e7383c2 -MRI acquisition 3 4 Description of pulse sequence used for fMRI select Gradient echo | Spin echo | Mutliband gradient echo | MPRAGE | MP2RAGE | FLASH PulseSequenceType pulse sequence 1 pulse sequence 1 1 20fc355f-0588-4a10-b185-851277ddc64f -MRI acquisition 3 5 Description of parallel imaging method and parameters textarea parallel imaging 1 parallel imaging 1 3 4bf06822-ee53-4e60-86bd-c54a5b8378e0 -MRI acquisition 3 6 Imaging field of view Millimeters float field of view 1 field of view 1 2 68b5c8e0-166b-42a8-ab33-9496d15e7859 -MRI acquisition 3 7 Matrix size for MRI acquisition integer matrix size 1 matrix size 1 2 4178e14e-a5f0-483a-a35f-5f7bb52d30e3 -MRI acquisition 3 8 Distance between slices (includes skip or distance factor). Millimeters float 0 slice thickness 1 slice thickness 1 1 e6b7971a-89f2-4b6a-b4c9-49fa6c4de697 -MRI acquisition 3 9 The size of the skipped area between slices. Millimeters float 0 skip factor 1 skip factor 1 2 bd9b28e1-58cf-4104-8694-350a504e9709 -MRI acquisition 3 10 The orientation of slices radio axial | sagittal | frontal acquisition orientation 1 acquisition orientation 1 2 8b5c1b46-64d5-4c36-aa19-154bd0e40a34 -MRI acquisition 3 11 Order of acquisition of slices select ascending | descending | interleaved SliceTiming order of acquisition 1 order of acquisition 1 3 37295a62-8084-42b2-b794-9bee8333b357 -MRI acquisition 3 12 Repetition time (TR) Milliseconds float 0 RepetitionTime repetition time 1 repetition time 1 1 fa71b4f7-015d-4d06-8728-fb5ef9591b71 -MRI acquisition 3 13 Echo time (TE) Milliseconds float 0 EchoTime echo time 1 echo time 1 1 a28a83be-cd4b-411e-9701-e0e711b28b05 -MRI acquisition 3 14 Flip angle Degrees float 0 FlipAngle flip angle 1 flip angle 1 2 653320d7-0dd3-412b-8464-f744d04a5f44 -Preprocessing 4 1 If a single software package was used for all analyses, specify that here select preset:mri_softwares SoftwareName software package 1 software package 1 1 Describe your preprocessing b92221e5-1b47-4692-81dd-c3c694e5f908 -Preprocessing 4 2 Version of software package used textarea SoftwareVersion software version 1 software version 1 1 c20093b4-df39-40d4-8610-ede0e4113b3f -Preprocessing 4 3 Specify order of preprocessing operations textarea order of preprocessing operations 1 order of preprocessing operations 1 2 af64fcae-c41e-4401-ab3a-3b162bf90933 -Preprocessing 4 4 Describe quality control measures textarea quality control 1 quality control 1 3 4fc681b9-9db9-4061-92b5-6a0396907ab3 -Preprocessing 4 5 Was B0 distortion correction used? radio preset:boolean used b0 unwarping 1 used b0 unwarping 1 2 5eea934f-4d84-49a5-bc79-b5ab6335d9de -Preprocessing 4 6 Specify software used for distortion correction if different from the main package select preset:mri_softwares b0 unwarping software used_b0_unwarping == 1 b0 unwarping software 1 3 7aa549bb-4c74-4859-82e6-e928e91787c4 -Preprocessing 4 7 Was slice timing correction used? radio preset:boolean used slice timing correction 1 used slice timing correction 1 1 90653c26-2d61-4e37-92e9-8a021d1a29b3 -Preprocessing 4 8 Specify software used for slice timing correction if different from the main package select preset:mri_softwares slice timing correction software used_slice_timing_correction == 1 slice timing correction software 1 3 e75c9a32-ec5a-4f3d-b048-57491f34b1bb -Preprocessing 4 9 Was motion correction used? radio preset:boolean used motion correction 1 used motion correction 1 1 ec63383c-0173-4c54-ba5b-0ff432d3e252 -Preprocessing 4 10 Specify software used for motion correction if different from the main package select preset:mri_softwares motion correction software used_motion_correction == 1 motion correction software 1 3 b4b0dd7d-1ac4-432f-a074-34b78ab021d0 -Preprocessing 4 11 Reference scan used for motion correction textarea motion correction reference used_motion_correction == 1 motion correction reference 1 3 b23f32cf-f81c-4d2b-b577-853c8da5e6c8 -Preprocessing 4 12 Similarity metric used for motion correction select preset:cost_functions motion correction metric used_motion_correction == 1 motion correction metric 1 3 24afd5d5-78fa-4a52-b196-654ddb3c9064 -Preprocessing 4 13 Interpolation method used for motion correction select preset:interpolations motion correction interpolation used_motion_correction == 1 motion correction interpolation 1 3 bd4f2aa3-7397-46bc-b63c-22f09431ac82 -Preprocessing 4 14 Was motion-susceptibility correction used? radio preset:boolean used motion susceptibiity correction 1 used motion susceptibiity correction 1 3 062960a8-0022-47ca-908b-c7fb6b89296b -Intersubject registration 5 1 Were subjects registered to a common stereotactic space? radio preset:boolean used intersubject registration 1 used intersubject registration 1 1 Describe your spatial normalization 1c13e108-0fe1-4d19-a707-9279f469a0e1 -Intersubject registration 5 2 Specify software used for intersubject registration if different from main package select preset:mri_softwares intersubject registration software used_intersubject_registration == 1 intersubject registration software 1 2 28b6d7fc-4168-48be-b6c7-fe518f9a7733 -Intersubject registration 5 3 Was linear or nonlinear registration used? select linear | non-linear intersubject transformation type used_intersubject_registration == 1 intersubject transformation type 1 1 dbbcba6b-2445-486a-b039-086f90f7f8c1 -Intersubject registration 5 4 If nonlinear registration was used, describe transform method textarea nonlinear transform type used_intersubject_registration == 1 and nonlinear_transform_type == 1 nonlinear transform type 1 2 b8cbc6b9-a3bd-4426-a2ef-860cf597f548 -Intersubject registration 5 5 Similarity metric used for intersubject registration textarea transform similarity metric used_intersubject_registration == 1 transform similarity metric 1 3 72e0b864-6950-4a15-a3ca-d6c6cc9264a8 -Intersubject registration 5 6 Interpolation method used for intersubject registration select preset:interpolations interpolation method used_intersubject_registration == 1 interpolation method 1 2 83a4f5ff-cd97-47a7-b272-e496ac1ad344 -Intersubject registration 5 7 What type of image was used to determine the transformation to the atlas? textarea object image type used_intersubject_registration == 1 object image type 1 1 0cbd4a83-80df-49ce-a3b3-50c5a63a723f -Intersubject registration 5 8 Were the functional images coregistered to the subject's structural image? radio preset:boolean functional coregistered to structural 1 functional coregistered to structural 1 2 331cfc44-6eb3-4c5b-ae7b-66dd6515e7a0 -Intersubject registration 5 9 Method used to coregister functional to structural images textarea functional coregistration method functional_coregistered_to_structural == 1 functional coregistration method 1 3 bcd0b566-2e73-4287-bc8f-2e370f43c03f -Intersubject registration 5 10 Name of coordinate space for registration target select MNI | Talairach | MNI2Tal | other coordinate space 1 coordinate space 1 1 6b8719e2-fde6-4805-a3a9-3a1dbc08df8e -Intersubject registration 5 11 Name of target template image textarea target template image 1 target template image 1 2 12331e78-51d6-47dd-8828-987de0333fdc -Intersubject registration 5 12 Voxel size of target template Millimeters float 0 target resolution 1 target resolution 1 1 265de527-ca2e-4ebe-a544-3224c7e89f3b -Intersubject registration 5 13 Was spatial smoothing applied? radio preset:boolean used smoothing 1 used smoothing 1 1 dc37a8a9-f2cf-4ed6-8610-028e92a6ec1f -Intersubject registration 5 14 Describe the type of smoothing applied textarea smoothing type used_smoothing == 1 smoothing type 1 1 bb9e0a6a-2d75-4604-89d5-54abee080ead -Intersubject registration 5 15 The full-width at half-maximum of the smoothing kernel Millimeters float 0 smoothing fwhm used_smoothing == 1 smoothing fwhm 1 1 68e4d3a2-447b-4cd3-baa1-4a131b9c41b1 -Intersubject registration 5 16 Voxel size in mm of the resampled, atlas-space images float 0 resampled voxel size 1 resampled voxel size 1 1 a64d9450-49d4-4bd5-9728-eb97a224a2b2 -Individual subject modeling 6 1 Type of group model used radio Regression | other intrasubject model type 1 intrasubject model type 1 1 Describe your model specification at the subejct level d1682682-6067-4014-aea8-651852c23ef1 -Individual subject modeling 6 2 Estimation method used for model select ordinary least squares | generalized least squares | other intrasubject estimation type 1 intrasubject estimation type 1 1 a9e542ec-fe76-4650-b54c-be144ccda2e3 -Individual subject modeling 6 3 Software used for intrasubject modeling if different from overall package select preset:mri_softwares intrasubject modeling software 1 intrasubject modeling software 1 2 93163af2-bb3a-407b-b632-18083ec4438c -Individual subject modeling 6 4 Nature of HRF model select spm HRF | glover HRF | double gamma | Fourrier set | Finite Impulse Response | FLOBS | other hemodynamic response function 1 hemodynamic response function 1 2 2cfdadcb-1aae-4653-ad09-69462b6f4bee -Individual subject modeling 6 5 Were temporal derivatives included? radio preset:boolean used temporal derivatives 1 used temporal derivatives 1 2 65c08e93-7d9f-4292-a346-750f2dee9123 -Individual subject modeling 6 6 Were dispersion derivatives included? radio preset:boolean used dispersion derivatives 1 used dispersion derivatives 1 3 1947cdad-aa5c-4747-9ea8-f72297b3fe3e -Individual subject modeling 6 7 Were motion regressors included? radio preset:boolean used motion regressors 1 used motion regressors 1 2 de73a483-2858-477d-b885-f9d64f35c97c -Individual subject modeling 6 8 Was a reaction time regressor included? radio preset:boolean used reaction time regressor 1 used reaction time regressor 1 2 7434909b-ec95-42c0-8a7f-7a785261dbde -Individual subject modeling 6 9 Were any regressors specifically orthogonalized with respect to others? radio preset:boolean used orthogonalization 1 used orthogonalization 1 1 0471ddd2-b424-4ef6-9586-dc7978a366b5 -Individual subject modeling 6 10 If orthogonalization was used, describe here textarea orthogonalization description used_orthogonalization == 1 orthogonalization description 1 2 d101653a-5004-4ccb-b15f-e5583512a08c -Individual subject modeling 6 11 Was high pass filtering applied? radio preset:boolean used high pass filter 1 used high pass filter 1 1 717f2fa9-580e-4498-96fa-acb6bf102691 -Individual subject modeling 6 12 Describe method used for high pass filtering textarea high pass filter method used_high_pass_filter == 1 high pass filter method 1 2 d1f221c9-ed0b-4fd6-bcfa-9dcdfed26709 -Individual subject modeling 6 13 What autocorrelation model was used ? select SPM: global approximate AR(1) | SPM: FAST | FSL: locally regularized autocorrelation function | AFNI: ARMA | none | other autocorrelation model 1 autocorrelation model 1 2 c662a33b-e242-4103-a2d2-9be9d1fd6ce1 -Individual subject modeling 6 14 Exactly what terms are subtracted from what? textarea contrast definition 1 contrast definition 1 1 d560f08a-62bf-4b56-b1e6-2599f906fb8a -Individual subject modeling 6 15 Link to Cognitive Atlas definition of this contrast Define these in terms of task or stimulus conditions (e.g., 'one-back task with objects versus zero-back task with objects') instead of underlying psychological concepts (e.g., 'working memory'). textarea contrast definition cogatlas 1 contrast definition cogatlas 1 3 f5dcb0b5-b94f-4dd9-81da-4abe4d6d923e -Group modeling 7 1 Type of group model used select Regression group model type 1 group model type 1 1 Describe the group level analysis 47d74a02-a1df-450a-89be-332e45acb1be -Group modeling 7 2 Estimation method used for model select ordinary least squares | generalized least squares group estimation type 1 group estimation type 1 1 01dbd376-3d69-4ac3-8779-45ff1e49796b -Group modeling 7 3 Software used for group modeling if different from overall package select preset:mri_softwares group modeling software 1 group modeling software 1 2 d617fa7d-219b-4ff1-9db2-f10ae3f29804 -Group modeling 7 4 Type of inference for group model select random effect | mixed effect | fixed effect group inference type 1 group inference type 1 1 012e837d-c1dc-4ae0-bdf5-234f410ca22d -Group modeling 7 5 If more than 2-levels, describe the levels and assumptions of the model. For example, are variances assumed equal between groups. textarea group model multilevel 1 group model multilevel 1 3 405903ff-8328-4733-852c-eac907750247 -Group modeling 7 6 Was this a repeated measures design at the group level? radio preset:boolean group repeated measures 1 group repeated measures 1 1 95d970ce-1ac2-4bb5-99fa-c6c07898ca20 -Group modeling 7 7 If multiple measurements per subject, list method to account for within subject correlation, exact assumptions made about correlation/variance textarea group repeated measures method group_repeated_measures == 1 group repeated measures method 1 3 66c51b5e-1992-4a30-8736-caa8f0c4736d -Group inference 8 1 Type of statistic that is the basis of the inference select Z | T | F | X2 | PostProb | Non-parametric Permutations | Monte Carlo Permutations group statistic type 1 group statistic type 1 2 Describe your statistical inference 3dfae2e3-4dfe-4fe7-a29d-1f3eaeec1950 -Group inference 8 2 Parameters of the null distribution of the test statisic. Typically degrees of freedom (should be clear from the test statistic what these are). float group statistic parameters 1 group statistic parameters 1 1 39e4fad9-00c7-45cf-a74a-b9c408514121 -Group inference 8 3 Noise smoothness for statistical inference This is the estimated smoothness used with Random Field Theory or a simulation-based inference method. float 0 group smoothness fwhm 1 group smoothness fwhm 1 1 4236b5c2-7e75-49c3-aa93-c1c1853f8162 +Experimental design 1 1 Type of design select blocked | event_related | hybrid block/event type_of_design type of design 1 type of design 1 1 Describe your experimental design #NAME? +Experimental design 1 2 Number of imaging runs acquired integer 0 number of imaging runs 1 number of imaging runs 1 2 #NAME? +Experimental design 1 3 Number of blocks, trials or experimental units per imaging run integer 0 number of experimental units 1 number of experimental units 1 2 #NAME? +Experimental design 1 4 Length of each imaging run seconds float 0 length of runs 1 length of runs 1 2 #NAME? +Experimental design 1 5 For blocked designs, length of blocks seconds float 0 length of blocks type_of_design in [0, 2] length of blocks 1 2 #NAME? +Experimental design 1 6 Length of individual trials seconds float 0 length of trials 1 length of trials 1 2 #NAME? +Experimental design 1 7 Was the design optimized for efficiency? radio preset:boolean optimization 1 optimization 1 2 #NAME? +Experimental design 1 8 What method was used for optimization? textarea optimization method optimization == 1 optimization method 1 3 #NAME? +Participants 2 1 Number of subjects entering into the analysis integer 0 number of subjects 1 number of subjects 1 1 Describe your participant sample #NAME? +Participants 2 2 Mean age of subjects float 0 subject age mean 1 subject age mean 1 1 #NAME? +Participants 2 3 Minimum age of subjects float 0 subject age min 1 subject age min 1 2 #NAME? +Participants 2 4 Maximum age of subjects float 0 subject age max 1 subject age max 1 2 #NAME? +Participants 2 5 Handedness of subjects radio right | left | both handedness 1 handedness 1 2 #NAME? +Participants 2 6 The proportion of subjects who were male float 0 | 1 proportion male subjects 1 proportion male subjects 1 2 #NAME? +Participants 2 7 Additional inclusion/exclusion criteria, if any. Including specific sampling strategies that limit inclusion to a specific group, such as laboratory members. textarea inclusion exclusion criteria 1 inclusion exclusion criteria 1 3 #NAME? +Participants 2 8 Number of subjects scanned but rejected from analysis integer 0 number of rejected subjects 1 number of rejected subjects 1 2 #NAME? +Participants 2 9 Was this study a comparison between subject groups? radio preset:boolean group comparison 1 group comparison 1 1 #NAME? +Participants 2 10 A description of the groups being compared textarea group description group_comparison == 1 group description 1 2 #NAME? +MRI acquisition 3 1 Manufacturer of MRI scanner select Siemens | Philips | General Electric | other Manufacturer scanner make 1 scanner make 1 1 Describe your acquisition parameters #NAME? +MRI acquisition 3 2 Model of MRI scanner textarea ManufacturersModelName scanner model 1 scanner model 1 1 #NAME? +MRI acquisition 3 3 Field strength of MRI scanner Tesla float 0 MagneticFieldStrength field strength 1 field strength 1 1 #NAME? +MRI acquisition 3 4 Description of pulse sequence used for fMRI select Gradient echo | Spin echo | Mutliband gradient echo | MPRAGE | MP2RAGE | FLASH PulseSequenceType pulse sequence 1 pulse sequence 1 1 #NAME? +MRI acquisition 3 5 Description of parallel imaging method and parameters textarea parallel imaging 1 parallel imaging 1 3 #NAME? +MRI acquisition 3 6 Imaging field of view Millimeters float field of view 1 field of view 1 2 #NAME? +MRI acquisition 3 7 Matrix size for MRI acquisition integer matrix size 1 matrix size 1 2 #NAME? +MRI acquisition 3 8 Distance between slices (includes skip or distance factor). Millimeters float 0 slice thickness 1 slice thickness 1 1 #NAME? +MRI acquisition 3 9 The size of the skipped area between slices. Millimeters float 0 skip factor 1 skip factor 1 2 #NAME? +MRI acquisition 3 10 The orientation of slices radio axial | sagittal | frontal acquisition orientation 1 acquisition orientation 1 2 #NAME? +MRI acquisition 3 11 Order of acquisition of slices select ascending | descending | interleaved SliceTiming order of acquisition 1 order of acquisition 1 3 #NAME? +MRI acquisition 3 12 Repetition time (TR) Milliseconds float 0 RepetitionTime repetition time 1 repetition time 1 1 #NAME? +MRI acquisition 3 13 Echo time (TE) Milliseconds float 0 EchoTime echo time 1 echo time 1 1 #NAME? +MRI acquisition 3 14 Flip angle Degrees float 0 FlipAngle flip angle 1 flip angle 1 2 #NAME? +Preprocessing 4 1 If a single software package was used for all analyses, specify that here select preset:mri_softwares SoftwareName software package 1 software package 1 1 Describe your preprocessing #NAME? +Preprocessing 4 2 Version of software package used textarea SoftwareVersion software version 1 software version 1 1 #NAME? +Preprocessing 4 3 Specify order of preprocessing operations textarea order of preprocessing operations 1 order of preprocessing operations 1 2 #NAME? +Preprocessing 4 4 Describe quality control measures textarea quality control 1 quality control 1 3 #NAME? +Preprocessing 4 5 Was B0 distortion correction used? radio preset:boolean used b0 unwarping 1 used b0 unwarping 1 2 #NAME? +Preprocessing 4 6 Specify software used for distortion correction if different from the main package select preset:mri_softwares b0 unwarping software used_b0_unwarping == 1 b0 unwarping software 1 3 #NAME? +Preprocessing 4 7 Was slice timing correction used? radio preset:boolean used slice timing correction 1 used slice timing correction 1 1 #NAME? +Preprocessing 4 8 Specify software used for slice timing correction if different from the main package select preset:mri_softwares slice timing correction software used_slice_timing_correction == 1 slice timing correction software 1 3 #NAME? +Preprocessing 4 9 Was motion correction used? radio preset:boolean used motion correction 1 used motion correction 1 1 #NAME? +Preprocessing 4 10 Specify software used for motion correction if different from the main package select preset:mri_softwares motion correction software used_motion_correction == 1 motion correction software 1 3 #NAME? +Preprocessing 4 11 Reference scan used for motion correction textarea motion correction reference used_motion_correction == 1 motion correction reference 1 3 #NAME? +Preprocessing 4 12 Similarity metric used for motion correction select preset:cost_functions motion correction metric used_motion_correction == 1 motion correction metric 1 3 #NAME? +Preprocessing 4 13 Interpolation method used for motion correction select preset:interpolations motion correction interpolation used_motion_correction == 1 motion correction interpolation 1 3 #NAME? +Preprocessing 4 14 Was motion-susceptibility correction used? radio preset:boolean used motion susceptibiity correction 1 used motion susceptibiity correction 1 3 #NAME? +Intersubject registration 5 1 Were subjects registered to a common stereotactic space? radio preset:boolean used intersubject registration 1 used intersubject registration 1 1 Describe your spatial normalization #NAME? +Intersubject registration 5 2 Specify software used for intersubject registration if different from main package select preset:mri_softwares intersubject registration software used_intersubject_registration == 1 intersubject registration software 1 2 #NAME? +Intersubject registration 5 3 Was linear or nonlinear registration used? select linear | non-linear intersubject transformation type used_intersubject_registration == 1 intersubject transformation type 1 1 #NAME? +Intersubject registration 5 4 If nonlinear registration was used, describe transform method textarea nonlinear transform type used_intersubject_registration == 1 and nonlinear_transform_type == 1 nonlinear transform type 1 2 #NAME? +Intersubject registration 5 5 Similarity metric used for intersubject registration textarea transform similarity metric used_intersubject_registration == 1 transform similarity metric 1 3 #NAME? +Intersubject registration 5 6 Interpolation method used for intersubject registration select preset:interpolations interpolation method used_intersubject_registration == 1 interpolation method 1 2 #NAME? +Intersubject registration 5 7 What type of image was used to determine the transformation to the atlas? textarea object image type used_intersubject_registration == 1 object image type 1 1 #NAME? +Intersubject registration 5 8 Were the functional images coregistered to the subject's structural image? radio preset:boolean functional coregistered to structural 1 functional coregistered to structural 1 2 #NAME? +Intersubject registration 5 9 Method used to coregister functional to structural images textarea functional coregistration method functional_coregistered_to_structural == 1 functional coregistration method 1 3 #NAME? +Intersubject registration 5 10 Name of coordinate space for registration target select MNI | Talairach | MNI2Tal | other coordinate space 1 coordinate space 1 1 #NAME? +Intersubject registration 5 11 Name of target template image textarea target template image 1 target template image 1 2 #NAME? +Intersubject registration 5 12 Voxel size of target template Millimeters float 0 target resolution 1 target resolution 1 1 #NAME? +Intersubject registration 5 13 Was spatial smoothing applied? radio preset:boolean used smoothing 1 used smoothing 1 1 #NAME? +Intersubject registration 5 14 Describe the type of smoothing applied textarea smoothing type used_smoothing == 1 smoothing type 1 1 #NAME? +Intersubject registration 5 15 The full-width at half-maximum of the smoothing kernel Millimeters float 0 smoothing fwhm used_smoothing == 1 smoothing fwhm 1 1 #NAME? +Intersubject registration 5 16 Voxel size in mm of the resampled, atlas-space images float 0 resampled voxel size 1 resampled voxel size 1 1 #NAME? +Individual subject modeling 6 1 Type of group model used radio Regression | other intrasubject model type 1 intrasubject model type 1 1 Describe your model specification at the subejct level #NAME? +Individual subject modeling 6 2 Estimation method used for model select ordinary least squares | generalized least squares | other intrasubject estimation type 1 intrasubject estimation type 1 1 #NAME? +Individual subject modeling 6 3 Software used for intrasubject modeling if different from overall package select preset:mri_softwares intrasubject modeling software 1 intrasubject modeling software 1 2 #NAME? +Individual subject modeling 6 4 Nature of HRF model select spm HRF | glover HRF | double gamma | Fourrier set | Finite Impulse Response | FLOBS | other hemodynamic response function 1 hemodynamic response function 1 2 #NAME? +Individual subject modeling 6 5 Were temporal derivatives included? radio preset:boolean used temporal derivatives 1 used temporal derivatives 1 2 #NAME? +Individual subject modeling 6 6 Were dispersion derivatives included? radio preset:boolean used dispersion derivatives 1 used dispersion derivatives 1 3 #NAME? +Individual subject modeling 6 7 Were motion regressors included? radio preset:boolean used motion regressors 1 used motion regressors 1 2 #NAME? +Individual subject modeling 6 8 Was a reaction time regressor included? radio preset:boolean used reaction time regressor 1 used reaction time regressor 1 2 #NAME? +Individual subject modeling 6 9 Were any regressors specifically orthogonalized with respect to others? radio preset:boolean used orthogonalization 1 used orthogonalization 1 1 #NAME? +Individual subject modeling 6 10 If orthogonalization was used, describe here textarea orthogonalization description used_orthogonalization == 1 orthogonalization description 1 2 #NAME? +Individual subject modeling 6 11 Was high pass filtering applied? radio preset:boolean used high pass filter 1 used high pass filter 1 1 #NAME? +Individual subject modeling 6 12 Describe method used for high pass filtering textarea high pass filter method used_high_pass_filter == 1 high pass filter method 1 2 #NAME? +Individual subject modeling 6 13 What autocorrelation model was used ? select SPM: global approximate AR(1) | SPM: FAST | FSL: locally regularized autocorrelation function | AFNI: ARMA | none | other autocorrelation model 1 autocorrelation model 1 2 #NAME? +Individual subject modeling 6 14 Exactly what terms are subtracted from what? textarea contrast definition 1 contrast definition 1 1 #NAME? +Individual subject modeling 6 15 Link to Cognitive Atlas definition of this contrast Define these in terms of task or stimulus conditions (e.g., 'one-back task with objects versus zero-back task with objects') instead of underlying psychological concepts (e.g., 'working memory'). textarea contrast definition cogatlas 1 contrast definition cogatlas 1 3 #NAME? +Group modeling 7 1 Type of group model used select Regression group model type 1 group model type 1 1 Describe the group level analysis #NAME? +Group modeling 7 2 Estimation method used for model select ordinary least squares | generalized least squares group estimation type 1 group estimation type 1 1 #NAME? +Group modeling 7 3 Software used for group modeling if different from overall package select preset:mri_softwares group modeling software 1 group modeling software 1 2 #NAME? +Group modeling 7 4 Type of inference for group model select random effect | mixed effect | fixed effect group inference type 1 group inference type 1 1 #NAME? +Group modeling 7 5 If more than 2-levels, describe the levels and assumptions of the model. For example, are variances assumed equal between groups. textarea group model multilevel 1 group model multilevel 1 3 #NAME? +Group modeling 7 6 Was this a repeated measures design at the group level? radio preset:boolean group repeated measures 1 group repeated measures 1 1 #NAME? +Group modeling 7 7 If multiple measurements per subject, list method to account for within subject correlation, exact assumptions made about correlation/variance textarea group repeated measures method group_repeated_measures == 1 group repeated measures method 1 3 #NAME? +Group inference 8 1 Type of statistic that is the basis of the inference select Z | T | F | X2 | PostProb | Non-parametric Permutations | Monte Carlo Permutations group statistic type 1 group statistic type 1 2 Describe your statistical inference #NAME? +Group inference 8 2 Parameters of the null distribution of the test statisic. Typically degrees of freedom (should be clear from the test statistic what these are). float group statistic parameters 1 group statistic parameters 1 1 #NAME? +Group inference 8 3 Noise smoothness for statistical inference This is the estimated smoothness used with Random Field Theory or a simulation-based inference method. float 0 group smoothness fwhm 1 group smoothness fwhm 1 1 #NAME? diff --git a/ui/ecobidas_ui/protocol.py b/ui/ecobidas_ui/protocol.py index ae5c1b89..cbd0c051 100644 --- a/ui/ecobidas_ui/protocol.py +++ b/ui/ecobidas_ui/protocol.py @@ -23,18 +23,28 @@ def update_visibility(items: dict[str, Any], form): + """Evaluate visibility condition of each item and make item visible if necessary.""" + # assign response to a variable with same name as the item it comees from + for key, value in form.data.items(): + if key not in items: + continue + if not value: + value = None + string_to_eval = f"{key} = {value}" + exec(string_to_eval) + + # evaluate visibility for item, values in items.items(): isVis = values["isVis"] if isinstance(isVis, str): - isVis = isVis.replace(" ", "").split("==") - # if len(isVis) > 2: - # app.logger.warning("More than 1 '=='") - # if len(isVis) < 2: - # app.logger.warning(f"Unsupported JavaScript expression: {isVis}") - if len(isVis) == 2 and form[isVis[0]].data: - response = int(form[isVis[0]].data) - expected = int(isVis[1]) - items[item]["visibility"] = response == expected + try: + items[item]["visibility"] = eval(isVis) + except Exception as exc: + # actually log this + print(f"Could not evaluate '{eval(isVis)}' as a valid python expression") + print(exc) + items[item]["visibility"] = False + return items From 91e0a21efccab01eed360186c103e3ff4dd032a1 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Sat, 25 May 2024 15:48:33 -0400 Subject: [PATCH 17/31] upload bold json --- inputs/bids_template/participants.json | 2 +- .../task-auditoryLocalizer_bold.json | 80 +++++++ pyproject.toml | 2 +- ui/README.md | 3 + ui/ecobidas_ui/about.py | 2 +- ui/ecobidas_ui/forms.py | 8 +- ui/ecobidas_ui/protocol.py | 197 ++++++++++++------ ui/ecobidas_ui/templates/base.html | 13 ++ ui/ecobidas_ui/templates/protocol.html | 52 ++++- ui/ecobidas_ui/utils.py | 42 +++- ui/tests/test_utils.py | 60 ++++++ 11 files changed, 394 insertions(+), 67 deletions(-) create mode 100755 inputs/bids_template/task-auditoryLocalizer_bold.json create mode 100644 ui/tests/test_utils.py diff --git a/inputs/bids_template/participants.json b/inputs/bids_template/participants.json index 4f6f9ff0..5cc2a253 100644 --- a/inputs/bids_template/participants.json +++ b/inputs/bids_template/participants.json @@ -14,7 +14,7 @@ "Description": "There should have been a description here, but there wasn't. :(" }, "participant_id": { - "Annottations": { + "Annotations": { "IsAbout": { "TermURL": "nb:ParticipantID", "Label": "" diff --git a/inputs/bids_template/task-auditoryLocalizer_bold.json b/inputs/bids_template/task-auditoryLocalizer_bold.json new file mode 100755 index 00000000..d61f4425 --- /dev/null +++ b/inputs/bids_template/task-auditoryLocalizer_bold.json @@ -0,0 +1,80 @@ +{ + "AcquisitionMatrixPE": 136, + "AcquisitionNumber": 1, + "AcquisitionTime": "11:06:33.777500", + "BandwidthPerPixelPhaseEncode": 37.388, + "BaseResolution": 134, + "BodyPartExamined": "BRAIN", + "CoilCombinationMethod": "Sum of Squares", + "CoilString": "A32", + "ConsistencyInfo": "N4_VE12U_LATEST_20181126", + "ConversionSoftware": "dcm2niix", + "ConversionSoftwareVersion": "v1.0.20220720", + "DerivedVendorReportedEchoSpacing": 0.000589997, + "DeviceSerialNumber": "79116", + "DwellTime": 1.8e-6, + "EchoTime": 0.022, + "EchoTrainLength": 45, + "EffectiveEchoSpacing": 0.000196666, + "FlipAngle": 70, + "HeudiconvVersion": "0.12.2", + "ImageComments": "Unaliased MB2/PE2/LB", + "ImageOrientationPatientDICOM": [ + 0.999976, 0.00314557, 0.00619129, -0.000174468, 0.902631, -0.430415 + ], + "ImageOrientationText": "Tra>Cor(-25.5)>Sag(0.4)", + "ImageType": ["ORIGINAL", "PRIMARY", "M", "MB", "ND", "MOSAIC"], + "ImagingFrequency": 297.161, + "InPlanePhaseEncodingDirectionDICOM": "COL", + "InstitutionAddress": "Allee du 6 Aout 8,Liege,Liege,BE,4000", + "InstitutionName": "CRC Liege", + "InstitutionalDepartmentName": "Department", + "MRAcquisitionType": "2D", + "MagneticFieldStrength": 7, + "Manufacturer": "Siemens", + "ManufacturersModelName": "Terra", + "MatrixCoilMode": "GRAPPA", + "Modality": "MR", + "MultibandAccelerationFactor": 2, + "NonlinearGradientCorrection": false, + "ParallelReductionFactorInPlane": 3, + "PartialFourier": 1, + "PatientPosition": "HFS", + "PercentPhaseFOV": 101.493, + "PercentSampling": 100, + "PhaseEncodingDirection": "j-", + "PhaseEncodingSteps": 135, + "PhaseResolution": 1, + "PixelBandwidth": 2075, + "ProcedureStepDescription": "BLAM", + "ProtocolName": "cmrr_mbep2d_p3_mb2_1.6iso_AABrain", + "PulseSequenceDetails": "%CustomerSeq%\\cmrr_mbep2d_bold", + "ReceiveCoilName": "1Tx32Rx_Head", + "ReconMatrixPE": 136, + "RefLinesPE": 36, + "RepetitionTime": 1.8, + "SAR": 0.0728539, + "ScanOptions": "FS\\EXT", + "ScanningSequence": "EP", + "SequenceName": "epfid2d1_136", + "SequenceVariant": "SK\\SS\\OSP", + "SeriesDescription": "cmrr_mbep2d_p3_mb2_1.6iso_AABrain", + "SeriesNumber": 11, + "ShimSetting": [180, 191, -50, 81, 46, -213, -216, -65], + "SliceThickness": 1.6, + "SliceTiming": [ + 0, 0.85, 1.7, 0.75, 1.6, 0.65, 1.5, 0.55, 1.4, 0.45, 1.3, 0.35, 1.2, 0.25, + 1.1, 0.15, 1, 0.05, 0.9, 1.75, 0.8, 1.65, 0.7, 1.55, 0.6, 1.45, 0.5, 1.35, + 0.4, 1.25, 0.3, 1.15, 0.2, 1.05, 0.1, 0.95, 0, 0.85, 1.7, 0.75, 1.6, 0.65, + 1.5, 0.55, 1.4, 0.45, 1.3, 0.35, 1.2, 0.25, 1.1, 0.15, 1, 0.05, 0.9, 1.75, + 0.8, 1.65, 0.7, 1.55, 0.6, 1.45, 0.5, 1.35, 0.4, 1.25, 0.3, 1.15, 0.2, 1.05, + 0.1, 0.95 + ], + "SoftwareVersions": "syngo MR E12", + "SpacingBetweenSlices": 1.6, + "StationName": "AWP79116", + "TaskName": "auditoryLocalizer", + "TotalReadoutTime": 0.0265499, + "TxRefAmp": 204.476, + "WipMemBlock": "892ba1da-48b0-4d69-9197-d97ef06e2eeb||Sequence: R016 ve12u/SP01_R016a r/af3652dd; Apr 1 2021 14:05:17 by eja" +} diff --git a/pyproject.toml b/pyproject.toml index 3402d887..50a32ad7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,7 +38,7 @@ ecobidas = "ecobidas.cli:cli" line-length = 100 [tool.codespell] -ignore-words-list = "jist,softwares,te,fwe,als" +ignore-words-list = "jist,softwares,te,fwe,als,nd" skip = "./.git,*.svg,reproschema-ui,node_modules,env,reproschema-py,htmlcov,package-lock.json" [tool.hatch.build.hooks.vcs] diff --git a/ui/README.md b/ui/README.md index 772eda3d..3501d332 100644 --- a/ui/README.md +++ b/ui/README.md @@ -18,3 +18,6 @@ flask --app ecobidas_ui --debug run https://github.com/helloflask/bootstrap-flask https://bootstrap-flask.readthedocs.io/ --> + + +🚧 diff --git a/ui/ecobidas_ui/about.py b/ui/ecobidas_ui/about.py index dce45834..0e2eb59c 100644 --- a/ui/ecobidas_ui/about.py +++ b/ui/ecobidas_ui/about.py @@ -3,6 +3,6 @@ bp = Blueprint("about", __name__) -@bp.route("/about") +@bp.route("/about", methods=["GET", "POST"]) def about() -> str: return render_template("about.html") diff --git a/ui/ecobidas_ui/forms.py b/ui/ecobidas_ui/forms.py index c0d5dcfc..f4ba1987 100644 --- a/ui/ecobidas_ui/forms.py +++ b/ui/ecobidas_ui/forms.py @@ -1,4 +1,5 @@ from flask_wtf import FlaskForm +from flask_wtf.file import FileField, FileRequired from markupsafe import Markup from wtforms import ( DateField, @@ -16,11 +17,16 @@ from wtforms.validators import DataRequired, NumberRange -class UploadForm(FlaskForm): +class UploadParticipantsForm(FlaskForm): participants = MultipleFileField("Upload participants.tsv and participants.json") submit = SubmitField("Upload") +class UploadBoldJsonForm(FlaskForm): + bold_json = FileField("Upload bold.json", validators=[FileRequired()]) + submit_bold_json = SubmitField("Upload") + + def generate_form(items=None, prefix=None): class DyanmicForm(FlaskForm): diff --git a/ui/ecobidas_ui/protocol.py b/ui/ecobidas_ui/protocol.py index cbd0c051..b5bd294f 100644 --- a/ui/ecobidas_ui/protocol.py +++ b/ui/ecobidas_ui/protocol.py @@ -2,17 +2,19 @@ from pathlib import Path from typing import Any -import pandas as pd -from ecobidas_ui.forms import UploadForm, generate_form +from ecobidas_ui.forms import UploadBoldJsonForm, UploadParticipantsForm, generate_form from ecobidas_ui.utils import ( LANG, allowed_file, + extract_values_participants, get_landing_page, get_nav_bar_content, get_protocol, prep_activity_page, protocol_url, update_format, + validate_participants_json, + validate_participants_tsv, ) from flask import Blueprint, current_app, flash, redirect, render_template, request from markupsafe import Markup @@ -31,7 +33,11 @@ def update_visibility(items: dict[str, Any], form): if not value: value = None string_to_eval = f"{key} = {value}" - exec(string_to_eval) + try: + exec(string_to_eval) + except Exception as exc: + print(f"Could not execute '{string_to_eval}' as a valid python statement.") + print(exc) # evaluate visibility for item, values in items.items(): @@ -41,7 +47,7 @@ def update_visibility(items: dict[str, Any], form): items[item]["visibility"] = eval(isVis) except Exception as exc: # actually log this - print(f"Could not evaluate '{eval(isVis)}' as a valid python expression") + print(f"Could not evaluate '{eval(isVis)}' as a valid python expression.") print(exc) items[item]["visibility"] = False @@ -72,9 +78,9 @@ def activity_get(protocol_name, activity_name) -> str: activities, activity, items = prep_activity_page(protocol_name, activity_name) - upload_form = None - if protocol_name == "neurovault" and activity_name == "participants": - upload_form = UploadForm(prefix="upload-") + upload_participants_form, upload_acquisition_form = generate_additional_forms( + protocol_name, activity_name + ) form = generate_form(items=items, prefix=activity_name) @@ -90,7 +96,8 @@ def activity_get(protocol_name, activity_name) -> str: form=form, nb_items=nb_items, completed_items=completed_items, - upload_form=upload_form, + upload_participants_form=upload_participants_form, + upload_acquisition_form=upload_acquisition_form, ) @@ -99,51 +106,38 @@ def activity_post(protocol_name, activity_name) -> str: activities, activity, items = prep_activity_page(protocol_name, activity_name) - upload_form = None - if protocol_name == "neurovault" and activity_name == "participants": - upload_form = UploadForm(prefix="upload-") + upload_participants_form, upload_acquisition_form = generate_additional_forms( + protocol_name, activity_name + ) form = generate_form(items=items, prefix=activity_name) - if upload_form and upload_form.participants.data: - - nb_files_uploaded = len(upload_form.participants.data) - participants_json_uploaded = any( - file.filename == "participants.json" for file in upload_form.participants.data - ) - participants_tsv_uploaded = any( - file.filename == "participants.tsv" for file in upload_form.participants.data - ) + if ( + upload_participants_form + and upload_participants_form.is_submitted() + and upload_participants_form.participants.data + ): - if nb_files_uploaded != 2: - message = "2 files must be uploaded." - if not participants_json_uploaded: - message = "No 'participants.json' was uploaded." - if not participants_tsv_uploaded: - message = "No 'participants.tsv' was uploaded." - - if ( - nb_files_uploaded != 2 - or not participants_json_uploaded - or not participants_tsv_uploaded - ): + if message := validate_participants_form(upload_participants_form): flash(message) return redirect(request.url) - for file in upload_form.participants.data: + for file in upload_participants_form.participants.data: if allowed_file(file.filename): filename = secure_filename(file.filename) file.save(Path(current_app.config["UPLOAD_FOLDER"]) / filename) - participants_tsv = pd.read_csv( - Path(current_app.config["UPLOAD_FOLDER"]) / "participants.tsv", sep="\t" - ) - with open(Path(current_app.config["UPLOAD_FOLDER"]) / "participants.json") as f: - participants_json = json.load(f) + tsv_file = Path(current_app.config["UPLOAD_FOLDER"]) / "participants.tsv" + if not validate_participants_tsv(tsv_file): + flash( + Markup( + "

The 'participants.tsv' does not seem to be valid: 'participant_id' column is missing.

" + ) + ) + return redirect(request.url) - if not participants_json.get("participant_id") or not participants_json[ - "participant_id" - ].get("Annotations"): + json_file = Path(current_app.config["UPLOAD_FOLDER"]) / "participants.json" + if not validate_participants_json(json_file): flash( Markup( "

The 'participants.json' was not annotated. " @@ -154,28 +148,115 @@ def activity_post(protocol_name, activity_name) -> str: ) return redirect(request.url) - print(participants_tsv) - print(participants_json) + form.number_of_subjects.data = extract_values_participants( + tsv_file, value="number_of_subjects" + ) + form.subject_age_mean.data = extract_values_participants(tsv_file, value="subject_age_mean") + form.subject_age_min.data = extract_values_participants(tsv_file, value="subject_age_min") + form.subject_age_max.data = extract_values_participants(tsv_file, value="subject_age_max") - elif form.is_submitted(): + # TODO + form.proportion_male_subjects.data = 0.5 items = update_visibility(items, form) + items = update_format(items, form) + form = generate_form(items, prefix=activity_name) + form.number_of_subjects.data = extract_values_participants( + tsv_file, target="number_of_subjects" + ) + form.subject_age_mean.data = extract_values_participants( + tsv_file, target="subject_age_mean" + ) + form.subject_age_min.data = extract_values_participants(tsv_file, vtarget="subject_age_min") + form.subject_age_max.data = extract_values_participants(tsv_file, target="subject_age_max") + form.proportion_male_subjects.data = 0.5 + + if upload_acquisition_form.validate_on_submit(): + + f = upload_acquisition_form.bold_json.data + filename = secure_filename(f.filename) + + if not allowed_file(filename): + message = "No '_bold.json' was uploaded." + flash(message) + return redirect(request.url) + + f.save(Path(current_app.instance_path) / filename) + + with open(Path(current_app.instance_path) / filename) as f: + bold_json = json.load(f) + + for key in bold_json: + if key in form: + form[key].data = bold_json[key] + + items = update_visibility(items, form) items = update_format(items, form) + form = generate_form(items, prefix=activity_name) + + for key in bold_json: + if key in form: + form[key].data = bold_json[key] + + elif form.is_submitted(): + items = update_visibility(items, form) + items = update_format(items, form) form = generate_form(items, prefix=activity_name) - completed_items = sum(bool(i["is_answered"]) for i in items.values()) - nb_items = sum(bool(i["visibility"]) for i in items.values()) - - return render_template( - "protocol.html", - protocol_pref_label=protocol_name, - activity_pref_label=activity["prefLabel"][LANG], - activity_preamble=Markup(activity["preamble"][LANG]), - activities=activities, - form=form, - nb_items=nb_items, - completed_items=completed_items, - upload_form=upload_form, - ) + completed_items = sum(bool(i["is_answered"]) for i in items.values()) + nb_items = sum(bool(i["visibility"]) for i in items.values()) + + return render_template( + "protocol.html", + protocol_pref_label=protocol_name, + activity_pref_label=activity["prefLabel"][LANG], + activity_preamble=Markup(activity["preamble"][LANG]), + activities=activities, + form=form, + nb_items=nb_items, + completed_items=completed_items, + upload_participants_form=upload_participants_form, + upload_acquisition_form=upload_acquisition_form, + ) + + +def validate_participants_form(upload_participants_form): + nb_files_uploaded = len(upload_participants_form.participants.data) + participants_json_uploaded = any( + file.filename == "participants.json" for file in upload_participants_form.participants.data + ) + participants_tsv_uploaded = any( + file.filename == "participants.tsv" for file in upload_participants_form.participants.data + ) + + if nb_files_uploaded != 2: + message = "2 files must be uploaded." + if not participants_json_uploaded: + message = "No 'participants.json' was uploaded." + if not participants_tsv_uploaded: + message = "No 'participants.tsv' was uploaded." + + if nb_files_uploaded != 2 or not participants_json_uploaded or not participants_tsv_uploaded: + + return message + + else: + return "" + + +def generate_additional_forms(protocol_name, activity_name): + + upload_participants_form = None + upload_acquisition_form = None + + if protocol_name != "neurovault": + return upload_participants_form, upload_acquisition_form + + if activity_name == "participants": + upload_participants_form = UploadParticipantsForm(prefix="upload-") + if activity_name == "mri_acquisition": + upload_acquisition_form = UploadBoldJsonForm(prefix="mri_acquisition-") + + return upload_participants_form, upload_acquisition_form diff --git a/ui/ecobidas_ui/templates/base.html b/ui/ecobidas_ui/templates/base.html index 17dcff07..dad901a5 100644 --- a/ui/ecobidas_ui/templates/base.html +++ b/ui/ecobidas_ui/templates/base.html @@ -42,6 +42,19 @@ +

+
+
+ +
+
+
+
{% with messages = get_flashed_messages() %} {% if messages %} {% for diff --git a/ui/ecobidas_ui/templates/protocol.html b/ui/ecobidas_ui/templates/protocol.html index 8cf318ee..2c590008 100644 --- a/ui/ecobidas_ui/templates/protocol.html +++ b/ui/ecobidas_ui/templates/protocol.html @@ -55,9 +55,55 @@

{{ activity_pref_label }}

>

- {{ activity_preamble }} {% if upload_form %} -
{{ render_form(upload_form) }}
- {% endif %} + {{ activity_preamble }} + +
+
+ {% if upload_participants_form %} +
+
+ +
+

+ To fill in this form faster you can upload a + participants.tsv file formatted according to the + BIDS specification + along with a participants.json file containing column + annotations generated by + the neurobagel annotation tool. +

+ {{ render_form(upload_participants_form) }} +
+ {% endif %} {% if upload_acquisition_form %} +
+
+ +
+

+ To fill in this form faster you can upload a + *_bold.json file formatted according to the + BIDS specification + containing the metadata for your fMRI runs. +

+ {{ render_form(upload_acquisition_form) }} +
+ {% endif %} +
+
Path: @@ -217,3 +218,40 @@ def get_choices(item_data): except KeyError: choices = {} return choices + + +def validate_participants_json(file: Path): + with open(file) as f: + participants_json = json.load(f) + return bool( + participants_json.get("participant_id") + and participants_json["participant_id"].get("Annotations") + ) + + +def validate_participants_tsv(file: Path): + df = pd.read_csv(file, sep="\t") + return "participant_id" in df.columns + + +def extract_values_participants(df, json_content, target): + if isinstance(df, Path): + df = pd.read_csv(df, sep="\t") + + if target == "number_of_subjects": + return len(df) + + column = next( + ( + key + for key, value in json_content.items() + if value["Annotations"]["IsAbout"]["TermURL"] == "nb:Age" + ), + None, + ) + if target == "subject_age_mean": + return df[column].mean() + if target == "subject_age_min": + return df[column].min() + if target == "subject_age_max": + return df[column].max() diff --git a/ui/tests/test_utils.py b/ui/tests/test_utils.py new file mode 100644 index 00000000..8dd27ef8 --- /dev/null +++ b/ui/tests/test_utils.py @@ -0,0 +1,60 @@ +import pandas as pd +from ecobidas_ui.utils import extract_values_participants + + +def test_extract_values_participants(): + tsv = pd.DataFrame( + { + "age": [ + 26, + 24, + 27, + 20, + 22, + 26, + 24, + 21, + 26, + 21, + 24, + 22, + 21, + 30, + 24, + 19, + ], + "sex": [ + "F", + "M", + "F", + "F", + "M,", + "F", + "M", + "M", + "M", + "F", + "F", + "F", + "F", + "F", + "F", + "M", + ], + } + ) + + json_content = { + "age": { + "Annotations": { + "IsAbout": {"TermURL": "nb:Age", "Label": ""}, + "Transformation": {"TermURL": "nb:FromInt", "Label": "integer data"}, + "MissingValues": ["", "n/a", " "], + } + } + } + + assert extract_values_participants(tsv, json_content, target="number_of_subjects") == 16 + assert extract_values_participants(tsv, json_content, target="subject_age_min") == 19 + assert extract_values_participants(tsv, json_content, target="subject_age_max") == 30 + # assert mean==23.5625 From af5f34bfeb7ba923801dd7493ad6b237e8574705 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Sat, 25 May 2024 15:49:44 -0400 Subject: [PATCH 18/31] adapt size --- ui/ecobidas_ui/templates/protocol.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/ecobidas_ui/templates/protocol.html b/ui/ecobidas_ui/templates/protocol.html index 2c590008..087d111b 100644 --- a/ui/ecobidas_ui/templates/protocol.html +++ b/ui/ecobidas_ui/templates/protocol.html @@ -86,7 +86,7 @@
From 0f4df8255b918eca9570414d197ceb0e251bbdc4 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Mon, 27 May 2024 15:47:48 +0200 Subject: [PATCH 19/31] refactor ui --- .pre-commit-config.yaml | 6 + ecobidas/inputs/spreadsheet_google_id.yml | 6 +- ui/ecobidas_ui/__init__.py | 89 - ui/ecobidas_ui/about.py | 8 - ui/ecobidas_ui/app.py | 73 + ui/ecobidas_ui/extensions.py | 11 + ui/ecobidas_ui/initializers/__init__.py | 0 ui/ecobidas_ui/initializers/assets.py | 11 + ui/ecobidas_ui/protocol.py | 19 +- ui/ecobidas_ui/public/__init__.py | 3 + ui/ecobidas_ui/public/views.py | 27 + ui/ecobidas_ui/settings.py | 28 + .../static/css/font-awesome.min.css | 1567 +++++++++++++++++ .../static/{style.css => css/main.css} | 0 ui/ecobidas_ui/static/favicon.ico | Bin 0 -> 766 bytes ui/ecobidas_ui/static/json/faq.json | 30 + ui/ecobidas_ui/templates/401.html | 21 + ui/ecobidas_ui/templates/404.html | 14 +- ui/ecobidas_ui/templates/500.html | 15 +- ui/ecobidas_ui/templates/auth/login.html | 2 +- ui/ecobidas_ui/templates/auth/register.html | 2 +- ui/ecobidas_ui/templates/base.html | 196 --- ui/ecobidas_ui/templates/layout/base.html | 92 + ui/ecobidas_ui/templates/layout/footer.html | 25 + ui/ecobidas_ui/templates/layout/nav.html | 82 + ui/ecobidas_ui/templates/layout/svg.html | 21 + ui/ecobidas_ui/templates/protocol.html | 51 +- .../templates/{ => public}/about.html | 49 +- ui/ecobidas_ui/templates/public/faq.html | 36 + .../templates/{ => public}/index.html | 2 +- ui/ecobidas_ui/templates/side_nav.html | 28 + ui/ecobidas_ui/utils.py | 8 + ui/pyproject.toml | 6 +- ui/requirements.txt | 1 + 34 files changed, 2165 insertions(+), 364 deletions(-) delete mode 100644 ui/ecobidas_ui/about.py create mode 100644 ui/ecobidas_ui/app.py create mode 100644 ui/ecobidas_ui/extensions.py create mode 100644 ui/ecobidas_ui/initializers/__init__.py create mode 100644 ui/ecobidas_ui/initializers/assets.py create mode 100644 ui/ecobidas_ui/public/__init__.py create mode 100644 ui/ecobidas_ui/public/views.py create mode 100644 ui/ecobidas_ui/settings.py create mode 100644 ui/ecobidas_ui/static/css/font-awesome.min.css rename ui/ecobidas_ui/static/{style.css => css/main.css} (100%) create mode 100644 ui/ecobidas_ui/static/favicon.ico create mode 100644 ui/ecobidas_ui/static/json/faq.json create mode 100644 ui/ecobidas_ui/templates/401.html delete mode 100644 ui/ecobidas_ui/templates/base.html create mode 100644 ui/ecobidas_ui/templates/layout/base.html create mode 100644 ui/ecobidas_ui/templates/layout/footer.html create mode 100644 ui/ecobidas_ui/templates/layout/nav.html create mode 100644 ui/ecobidas_ui/templates/layout/svg.html rename ui/ecobidas_ui/templates/{ => public}/about.html (72%) create mode 100644 ui/ecobidas_ui/templates/public/faq.html rename ui/ecobidas_ui/templates/{ => public}/index.html (96%) create mode 100644 ui/ecobidas_ui/templates/side_nav.html diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2e5f250b..9731853e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -84,6 +84,12 @@ repos: - id: prettier types_or: [css, html, json] +# Check formatting HTML / Jinja +# - repo: https://github.com/thibaudcolas/curlylint + # rev: v0.13.1 + # hooks: + # - id: curlylint + # Check that Python code complies with PEP8 guidelines # flake8 uses pydocstyle to check docstrings: https://flake8.pycqa.org/en/latest/ # flake8-docstrings: https://pypi.org/project/flake8-docstrings/ diff --git a/ecobidas/inputs/spreadsheet_google_id.yml b/ecobidas/inputs/spreadsheet_google_id.yml index 8cfcbcd9..ce729378 100644 --- a/ecobidas/inputs/spreadsheet_google_id.yml +++ b/ecobidas/inputs/spreadsheet_google_id.yml @@ -19,7 +19,7 @@ eyetracking: google_id: 1aQZINzS24oYDgu6PZ8djqZQZ2s2eNs2xP6kyzHokU8o citation: https://psyarxiv.com/f6qcy/ app_link: https://remi-gau.github.io/cobidas-eyetracker/#/ - landing_page: ../README_eyetracker-en.md + landing_page: ../README_eyetracker-en.html repo: https://github.com/Remi-Gau/cobidas-eyetracker neurovault: @@ -37,7 +37,7 @@ pet: google_id: 1HS-1KOP8nE7C3MHiyRmQ6hd823cBZnCRVq0UryXvDc8 citation: https://doi.org/10.1177/0271678X20905433 app_link: https://remi-gau.github.io/cobidas-PET/#/ - landing_page: ../README_PET-en.md + landing_page: ../README_PET-en.html repo: https://github.com/Remi-Gau/cobidas-PET reexecution: @@ -46,7 +46,7 @@ reexecution: google_id: 1M9H7Bkti4OEVrYETajLbpbwY0T-QqSkpRUiwTz6-5Vc citation: https://doi.org/10.12688/f1000research.25306.2 app_link: https://remi-gau.github.io/cobidas_reexecute/#/ - landing_page: ../README_reexecute-en.md + landing_page: ../README_reexecute-en.html repo: https://github.com/Remi-Gau/cobidas_reexecute diff --git a/ui/ecobidas_ui/__init__.py b/ui/ecobidas_ui/__init__.py index 5d4919e8..e69de29b 100644 --- a/ui/ecobidas_ui/__init__.py +++ b/ui/ecobidas_ui/__init__.py @@ -1,89 +0,0 @@ -from logging.config import dictConfig -from pathlib import Path - -from flask import Flask, flash, render_template -from flask_bootstrap import Bootstrap5 -from flask_wtf import CSRFProtect - - -def create_app(test_config=None): - from ecobidas_ui import about, auth, db, protocol - - dictConfig( - { - "version": 1, - "formatters": { - "default": { - "format": "[%(asctime)s] %(levelname)s in %(module)s: %(message)s", - } - }, - "handlers": { - "wsgi": { - "class": "logging.StreamHandler", - "stream": "ext://flask.logging.wsgi_errors_stream", - "formatter": "default", - } - }, - "root": {"level": "INFO", "handlers": ["wsgi"]}, - } - ) - - # create and configure the app - UPLOAD_FOLDER = Path(__file__).parent / "tmp" - UPLOAD_FOLDER.mkdir(parents=True, exist_ok=True) - - # create and configure the app - app = Flask(__name__, instance_relative_config=True) - app.config.from_mapping( - SECRET_KEY="tO$&!|0wkamvVia0?n$NqIRVWOG", - DATABASE=Path(app.instance_path) / "flaskr.sqlite", - UPLOAD_FOLDER=UPLOAD_FOLDER, - MAX_CONTENT_LENGTH=16 * 1000 * 1000, - ) - - if test_config is None: - # load the instance config, if it exists, when not testing - app.config.from_pyfile("config.py", silent=True) - else: - # load the test config if passed in - app.config.from_mapping(test_config) - - # ensure the instance folder exists - Path(app.instance_path).mkdir(parents=True, exist_ok=True) - - # Bootstrap-Flask requires this line - bootstrap = Bootstrap5(app) # noqa - - # Flask-WTF requires this line - csrf = CSRFProtect(app) # noqa - - db.init_app(app) - - app.register_blueprint(auth.bp) - app.register_blueprint(about.bp) - app.register_blueprint(protocol.bp) - app.add_url_rule("/about", endpoint="about") - - @app.route("/", methods=["GET", "POST"]) - def index() -> str: - return render_template("index.html") - - @app.route("/export") - def export() -> str: - flash("Not implemented yet!") - return render_template("index.html") - - @app.route("/generate") - def generate() -> str: - flash("Not implemented yet!") - return render_template("index.html") - - @app.errorhandler(404) - def page_not_found(e): - return render_template("404.html"), 404 - - @app.errorhandler(500) - def internal_server_error(e): - return render_template("500.html"), 500 - - return app diff --git a/ui/ecobidas_ui/about.py b/ui/ecobidas_ui/about.py deleted file mode 100644 index 0e2eb59c..00000000 --- a/ui/ecobidas_ui/about.py +++ /dev/null @@ -1,8 +0,0 @@ -from flask import Blueprint, render_template - -bp = Blueprint("about", __name__) - - -@bp.route("/about", methods=["GET", "POST"]) -def about() -> str: - return render_template("about.html") diff --git a/ui/ecobidas_ui/app.py b/ui/ecobidas_ui/app.py new file mode 100644 index 00000000..099a6ca1 --- /dev/null +++ b/ui/ecobidas_ui/app.py @@ -0,0 +1,73 @@ +import logging +import sys + +from ecobidas_ui import auth, db, protocol, public +from ecobidas_ui.extensions import bootstrap, cache, csrf_protect, debug_toolbar +from ecobidas_ui.initializers.assets import init_assets +from flask import Flask, flash, render_template + + +def create_app(config_object="ecobidas_ui.settings"): + + # create and configure the app + app = Flask(__name__, instance_relative_config=True) + + app.config.from_object(config_object) + + register_extensions(app) + db.init_app(app) + + init_assets(app) + register_blueprints(app) + register_errorhandlers(app) + configure_logger(app) + + @app.route("/export") + def export() -> str: + flash("Not implemented yet!") + return render_template("index.html") + + @app.route("/generate") + def generate() -> str: + flash("Not implemented yet!") + return render_template("index.html") + + return app + + +def register_extensions(app): + """Register Flask extensions.""" + bootstrap.init_app(app) + csrf_protect.init_app(app) + cache.init_app(app) + debug_toolbar.init_app(app) + return None + + +def register_blueprints(app): + """Register Flask blueprints.""" + app.register_blueprint(public.views.blueprint) + app.register_blueprint(auth.bp) + app.register_blueprint(protocol.bp) + return None + + +def register_errorhandlers(app): + """Register error handlers.""" + + def render_error(error): + """Render error template.""" + # If a HTTPException, pull the `code` attribute; default to 500 + error_code = getattr(error, "code", 500) + return render_template(f"{error_code}.html"), error_code + + for errcode in [401, 404, 500]: + app.errorhandler(errcode)(render_error) + return None + + +def configure_logger(app): + """Configure loggers.""" + handler = logging.StreamHandler(sys.stdout) + if not app.logger.handlers: + app.logger.addHandler(handler) diff --git a/ui/ecobidas_ui/extensions.py b/ui/ecobidas_ui/extensions.py new file mode 100644 index 00000000..6b4ace46 --- /dev/null +++ b/ui/ecobidas_ui/extensions.py @@ -0,0 +1,11 @@ +"""Extensions module. Each extension is initialized in the app factory located in app.py.""" + +from flask_bootstrap import Bootstrap5 +from flask_caching import Cache +from flask_debugtoolbar import DebugToolbarExtension +from flask_wtf import CSRFProtect + +bootstrap = Bootstrap5() +csrf_protect = CSRFProtect() +cache = Cache() +debug_toolbar = DebugToolbarExtension() diff --git a/ui/ecobidas_ui/initializers/__init__.py b/ui/ecobidas_ui/initializers/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ui/ecobidas_ui/initializers/assets.py b/ui/ecobidas_ui/initializers/assets.py new file mode 100644 index 00000000..ccd99e40 --- /dev/null +++ b/ui/ecobidas_ui/initializers/assets.py @@ -0,0 +1,11 @@ +from ecobidas_ui import settings +from flask_assets import Bundle, Environment + +# consolidated css bundle +css_bundle = Bundle("css/font-awesome.min.css") + + +def init_assets(app): + app.config["ASSETS_DEBUG"] = settings.DEBUG + webassets = Environment(app) + webassets.register("css", css_bundle) diff --git a/ui/ecobidas_ui/protocol.py b/ui/ecobidas_ui/protocol.py index b5bd294f..ed2ab69e 100644 --- a/ui/ecobidas_ui/protocol.py +++ b/ui/ecobidas_ui/protocol.py @@ -69,10 +69,19 @@ def protocol(protocol_name: str) -> str: protocol_pref_label=protocol_name, protocol_preamble=protocol_content["preamble"][LANG], activities=activities, - landing_page=Markup(landing_page), + landing_page=landing_page, + show_export_button=show_export_button(protocol_name), ) +def show_export_button(protocol_name): + print(protocol_name) + if protocol_name in ["neurovault", "cobidas"]: + return True + else: + return False + + @bp.get("//") def activity_get(protocol_name, activity_name) -> str: @@ -91,13 +100,14 @@ def activity_get(protocol_name, activity_name) -> str: "protocol.html", protocol_pref_label=protocol_name, activity_pref_label=activity["prefLabel"][LANG], - activity_preamble=Markup(activity["preamble"][LANG]), + activity_preamble=activity["preamble"][LANG], activities=activities, form=form, nb_items=nb_items, completed_items=completed_items, upload_participants_form=upload_participants_form, upload_acquisition_form=upload_acquisition_form, + show_export_button=show_export_button(protocol_name), ) @@ -142,7 +152,7 @@ def activity_post(protocol_name, activity_name) -> str: Markup( "

The 'participants.json' was not annotated. " "Annotate your data with " - "the neurobagel online annotation tool

" ) ) @@ -212,13 +222,14 @@ def activity_post(protocol_name, activity_name) -> str: "protocol.html", protocol_pref_label=protocol_name, activity_pref_label=activity["prefLabel"][LANG], - activity_preamble=Markup(activity["preamble"][LANG]), + activity_preamble=activity["preamble"][LANG], activities=activities, form=form, nb_items=nb_items, completed_items=completed_items, upload_participants_form=upload_participants_form, upload_acquisition_form=upload_acquisition_form, + show_export_button=show_export_button(protocol_name), ) diff --git a/ui/ecobidas_ui/public/__init__.py b/ui/ecobidas_ui/public/__init__.py new file mode 100644 index 00000000..05af8588 --- /dev/null +++ b/ui/ecobidas_ui/public/__init__.py @@ -0,0 +1,3 @@ +"""The public module, including the homepage and user auth.""" + +from . import views # noqa diff --git a/ui/ecobidas_ui/public/views.py b/ui/ecobidas_ui/public/views.py new file mode 100644 index 00000000..4d874025 --- /dev/null +++ b/ui/ecobidas_ui/public/views.py @@ -0,0 +1,27 @@ +"""Public section, including homepage and signup.""" + +import json + +from ecobidas_ui.settings import STATIC_FOLDER +from flask import Blueprint, current_app, render_template + +blueprint = Blueprint("public", __name__, static_folder="../static") + + +@blueprint.route("/", methods=["GET", "POST"]) +def home(): + """Home page.""" + current_app.logger.info("Hello from the home page!") + return render_template("public/index.html") + + +@blueprint.route("/faq/") +def faq(): + data = json.load(open(STATIC_FOLDER / "json" / "faq.json")) + return render_template("public/faq.html", data=data) + + +@blueprint.route("/about/") +def about(): + """About page.""" + return render_template("public/about.html") diff --git a/ui/ecobidas_ui/settings.py b/ui/ecobidas_ui/settings.py new file mode 100644 index 00000000..42e8cd6d --- /dev/null +++ b/ui/ecobidas_ui/settings.py @@ -0,0 +1,28 @@ +from pathlib import Path + +from environs import Env + +env = Env() +env.read_env() + +ROOT_DIR = Path(__file__).parent + +# Static content +STATIC_FOLDER = ROOT_DIR / "static" + +# Templates +TEMPLATE_FOLDER = ROOT_DIR / "templates" + +UPLOAD_FOLDER = Path(__file__).parent / "tmp" +UPLOAD_FOLDER.mkdir(parents=True, exist_ok=True) + +# ---- SETUP INSTRUCTIONS AND APP BEHAVIOR #### + +# ------ App-level configuration ### +DEBUG = True + +PROTOTYPE = True + +SECRET_KEY = env.str("SECRET_KEY") + +CACHE_TYPE = "flask_caching.backends.SimpleCache" # Can be "MemcachedCache", "RedisCache", etc. diff --git a/ui/ecobidas_ui/static/css/font-awesome.min.css b/ui/ecobidas_ui/static/css/font-awesome.min.css new file mode 100644 index 00000000..cbe88b5e --- /dev/null +++ b/ui/ecobidas_ui/static/css/font-awesome.min.css @@ -0,0 +1,1567 @@ +/*! + * Font Awesome 4.1.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */ +@font-face { + font-family: "FontAwesome"; + src: url("../fonts/fontawesome-webfont.eot?v=4.1.0"); + src: + url("../fonts/fontawesome-webfont.eot?#iefix&v=4.1.0") + format("embedded-opentype"), + url("../fonts/fontawesome-webfont.woff?v=4.1.0") format("woff"), + url("../fonts/fontawesome-webfont.ttf?v=4.1.0") format("truetype"), + url("../fonts/fontawesome-webfont.svg?v=4.1.0#fontawesomeregular") + format("svg"); + font-weight: normal; + font-style: normal; +} +.fa { + display: inline-block; + font-family: FontAwesome; + font-style: normal; + font-weight: normal; + line-height: 1; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +.fa-lg { + font-size: 1.33333333em; + line-height: 0.75em; + vertical-align: -15%; +} +.fa-2x { + font-size: 2em; +} +.fa-3x { + font-size: 3em; +} +.fa-4x { + font-size: 4em; +} +.fa-5x { + font-size: 5em; +} +.fa-fw { + width: 1.28571429em; + text-align: center; +} +.fa-ul { + padding-left: 0; + margin-left: 2.14285714em; + list-style-type: none; +} +.fa-ul > li { + position: relative; +} +.fa-li { + position: absolute; + left: -2.14285714em; + width: 2.14285714em; + top: 0.14285714em; + text-align: center; +} +.fa-li.fa-lg { + left: -1.85714286em; +} +.fa-border { + padding: 0.2em 0.25em 0.15em; + border: solid 0.08em #eee; + border-radius: 0.1em; +} +.pull-right { + float: right; +} +.pull-left { + float: left; +} +.fa.pull-left { + margin-right: 0.3em; +} +.fa.pull-right { + margin-left: 0.3em; +} +.fa-spin { + -webkit-animation: spin 2s infinite linear; + -moz-animation: spin 2s infinite linear; + -o-animation: spin 2s infinite linear; + animation: spin 2s infinite linear; +} +@-moz-keyframes spin { + 0% { + -moz-transform: rotate(0deg); + } + 100% { + -moz-transform: rotate(359deg); + } +} +@-webkit-keyframes spin { + 0% { + -webkit-transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + } +} +@-o-keyframes spin { + 0% { + -o-transform: rotate(0deg); + } + 100% { + -o-transform: rotate(359deg); + } +} +@keyframes spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} +.fa-rotate-90 { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1); + -webkit-transform: rotate(90deg); + -moz-transform: rotate(90deg); + -ms-transform: rotate(90deg); + -o-transform: rotate(90deg); + transform: rotate(90deg); +} +.fa-rotate-180 { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2); + -webkit-transform: rotate(180deg); + -moz-transform: rotate(180deg); + -ms-transform: rotate(180deg); + -o-transform: rotate(180deg); + transform: rotate(180deg); +} +.fa-rotate-270 { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3); + -webkit-transform: rotate(270deg); + -moz-transform: rotate(270deg); + -ms-transform: rotate(270deg); + -o-transform: rotate(270deg); + transform: rotate(270deg); +} +.fa-flip-horizontal { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1); + -webkit-transform: scale(-1, 1); + -moz-transform: scale(-1, 1); + -ms-transform: scale(-1, 1); + -o-transform: scale(-1, 1); + transform: scale(-1, 1); +} +.fa-flip-vertical { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1); + -webkit-transform: scale(1, -1); + -moz-transform: scale(1, -1); + -ms-transform: scale(1, -1); + -o-transform: scale(1, -1); + transform: scale(1, -1); +} +.fa-stack { + position: relative; + display: inline-block; + width: 2em; + height: 2em; + line-height: 2em; + vertical-align: middle; +} +.fa-stack-1x, +.fa-stack-2x { + position: absolute; + left: 0; + width: 100%; + text-align: center; +} +.fa-stack-1x { + line-height: inherit; +} +.fa-stack-2x { + font-size: 2em; +} +.fa-inverse { + color: #fff; +} +.fa-glass:before { + content: "\f000"; +} +.fa-music:before { + content: "\f001"; +} +.fa-search:before { + content: "\f002"; +} +.fa-envelope-o:before { + content: "\f003"; +} +.fa-heart:before { + content: "\f004"; +} +.fa-star:before { + content: "\f005"; +} +.fa-star-o:before { + content: "\f006"; +} +.fa-user:before { + content: "\f007"; +} +.fa-film:before { + content: "\f008"; +} +.fa-th-large:before { + content: "\f009"; +} +.fa-th:before { + content: "\f00a"; +} +.fa-th-list:before { + content: "\f00b"; +} +.fa-check:before { + content: "\f00c"; +} +.fa-times:before { + content: "\f00d"; +} +.fa-search-plus:before { + content: "\f00e"; +} +.fa-search-minus:before { + content: "\f010"; +} +.fa-power-off:before { + content: "\f011"; +} +.fa-signal:before { + content: "\f012"; +} +.fa-gear:before, +.fa-cog:before { + content: "\f013"; +} +.fa-trash-o:before { + content: "\f014"; +} +.fa-home:before { + content: "\f015"; +} +.fa-file-o:before { + content: "\f016"; +} +.fa-clock-o:before { + content: "\f017"; +} +.fa-road:before { + content: "\f018"; +} +.fa-download:before { + content: "\f019"; +} +.fa-arrow-circle-o-down:before { + content: "\f01a"; +} +.fa-arrow-circle-o-up:before { + content: "\f01b"; +} +.fa-inbox:before { + content: "\f01c"; +} +.fa-play-circle-o:before { + content: "\f01d"; +} +.fa-rotate-right:before, +.fa-repeat:before { + content: "\f01e"; +} +.fa-refresh:before { + content: "\f021"; +} +.fa-list-alt:before { + content: "\f022"; +} +.fa-lock:before { + content: "\f023"; +} +.fa-flag:before { + content: "\f024"; +} +.fa-headphones:before { + content: "\f025"; +} +.fa-volume-off:before { + content: "\f026"; +} +.fa-volume-down:before { + content: "\f027"; +} +.fa-volume-up:before { + content: "\f028"; +} +.fa-qrcode:before { + content: "\f029"; +} +.fa-barcode:before { + content: "\f02a"; +} +.fa-tag:before { + content: "\f02b"; +} +.fa-tags:before { + content: "\f02c"; +} +.fa-book:before { + content: "\f02d"; +} +.fa-bookmark:before { + content: "\f02e"; +} +.fa-print:before { + content: "\f02f"; +} +.fa-camera:before { + content: "\f030"; +} +.fa-font:before { + content: "\f031"; +} +.fa-bold:before { + content: "\f032"; +} +.fa-italic:before { + content: "\f033"; +} +.fa-text-height:before { + content: "\f034"; +} +.fa-text-width:before { + content: "\f035"; +} +.fa-align-left:before { + content: "\f036"; +} +.fa-align-center:before { + content: "\f037"; +} +.fa-align-right:before { + content: "\f038"; +} +.fa-align-justify:before { + content: "\f039"; +} +.fa-list:before { + content: "\f03a"; +} +.fa-dedent:before, +.fa-outdent:before { + content: "\f03b"; +} +.fa-indent:before { + content: "\f03c"; +} +.fa-video-camera:before { + content: "\f03d"; +} +.fa-photo:before, +.fa-image:before, +.fa-picture-o:before { + content: "\f03e"; +} +.fa-pencil:before { + content: "\f040"; +} +.fa-map-marker:before { + content: "\f041"; +} +.fa-adjust:before { + content: "\f042"; +} +.fa-tint:before { + content: "\f043"; +} +.fa-edit:before, +.fa-pencil-square-o:before { + content: "\f044"; +} +.fa-share-square-o:before { + content: "\f045"; +} +.fa-check-square-o:before { + content: "\f046"; +} +.fa-arrows:before { + content: "\f047"; +} +.fa-step-backward:before { + content: "\f048"; +} +.fa-fast-backward:before { + content: "\f049"; +} +.fa-backward:before { + content: "\f04a"; +} +.fa-play:before { + content: "\f04b"; +} +.fa-pause:before { + content: "\f04c"; +} +.fa-stop:before { + content: "\f04d"; +} +.fa-forward:before { + content: "\f04e"; +} +.fa-fast-forward:before { + content: "\f050"; +} +.fa-step-forward:before { + content: "\f051"; +} +.fa-eject:before { + content: "\f052"; +} +.fa-chevron-left:before { + content: "\f053"; +} +.fa-chevron-right:before { + content: "\f054"; +} +.fa-plus-circle:before { + content: "\f055"; +} +.fa-minus-circle:before { + content: "\f056"; +} +.fa-times-circle:before { + content: "\f057"; +} +.fa-check-circle:before { + content: "\f058"; +} +.fa-question-circle:before { + content: "\f059"; +} +.fa-info-circle:before { + content: "\f05a"; +} +.fa-crosshairs:before { + content: "\f05b"; +} +.fa-times-circle-o:before { + content: "\f05c"; +} +.fa-check-circle-o:before { + content: "\f05d"; +} +.fa-ban:before { + content: "\f05e"; +} +.fa-arrow-left:before { + content: "\f060"; +} +.fa-arrow-right:before { + content: "\f061"; +} +.fa-arrow-up:before { + content: "\f062"; +} +.fa-arrow-down:before { + content: "\f063"; +} +.fa-mail-forward:before, +.fa-share:before { + content: "\f064"; +} +.fa-expand:before { + content: "\f065"; +} +.fa-compress:before { + content: "\f066"; +} +.fa-plus:before { + content: "\f067"; +} +.fa-minus:before { + content: "\f068"; +} +.fa-asterisk:before { + content: "\f069"; +} +.fa-exclamation-circle:before { + content: "\f06a"; +} +.fa-gift:before { + content: "\f06b"; +} +.fa-leaf:before { + content: "\f06c"; +} +.fa-fire:before { + content: "\f06d"; +} +.fa-eye:before { + content: "\f06e"; +} +.fa-eye-slash:before { + content: "\f070"; +} +.fa-warning:before, +.fa-exclamation-triangle:before { + content: "\f071"; +} +.fa-plane:before { + content: "\f072"; +} +.fa-calendar:before { + content: "\f073"; +} +.fa-random:before { + content: "\f074"; +} +.fa-comment:before { + content: "\f075"; +} +.fa-magnet:before { + content: "\f076"; +} +.fa-chevron-up:before { + content: "\f077"; +} +.fa-chevron-down:before { + content: "\f078"; +} +.fa-retweet:before { + content: "\f079"; +} +.fa-shopping-cart:before { + content: "\f07a"; +} +.fa-folder:before { + content: "\f07b"; +} +.fa-folder-open:before { + content: "\f07c"; +} +.fa-arrows-v:before { + content: "\f07d"; +} +.fa-arrows-h:before { + content: "\f07e"; +} +.fa-bar-chart-o:before { + content: "\f080"; +} +.fa-twitter-square:before { + content: "\f081"; +} +.fa-facebook-square:before { + content: "\f082"; +} +.fa-camera-retro:before { + content: "\f083"; +} +.fa-key:before { + content: "\f084"; +} +.fa-gears:before, +.fa-cogs:before { + content: "\f085"; +} +.fa-comments:before { + content: "\f086"; +} +.fa-thumbs-o-up:before { + content: "\f087"; +} +.fa-thumbs-o-down:before { + content: "\f088"; +} +.fa-star-half:before { + content: "\f089"; +} +.fa-heart-o:before { + content: "\f08a"; +} +.fa-sign-out:before { + content: "\f08b"; +} +.fa-linkedin-square:before { + content: "\f08c"; +} +.fa-thumb-tack:before { + content: "\f08d"; +} +.fa-external-link:before { + content: "\f08e"; +} +.fa-sign-in:before { + content: "\f090"; +} +.fa-trophy:before { + content: "\f091"; +} +.fa-github-square:before { + content: "\f092"; +} +.fa-upload:before { + content: "\f093"; +} +.fa-lemon-o:before { + content: "\f094"; +} +.fa-phone:before { + content: "\f095"; +} +.fa-square-o:before { + content: "\f096"; +} +.fa-bookmark-o:before { + content: "\f097"; +} +.fa-phone-square:before { + content: "\f098"; +} +.fa-twitter:before { + content: "\f099"; +} +.fa-facebook:before { + content: "\f09a"; +} +.fa-github:before { + content: "\f09b"; +} +.fa-unlock:before { + content: "\f09c"; +} +.fa-credit-card:before { + content: "\f09d"; +} +.fa-rss:before { + content: "\f09e"; +} +.fa-hdd-o:before { + content: "\f0a0"; +} +.fa-bullhorn:before { + content: "\f0a1"; +} +.fa-bell:before { + content: "\f0f3"; +} +.fa-certificate:before { + content: "\f0a3"; +} +.fa-hand-o-right:before { + content: "\f0a4"; +} +.fa-hand-o-left:before { + content: "\f0a5"; +} +.fa-hand-o-up:before { + content: "\f0a6"; +} +.fa-hand-o-down:before { + content: "\f0a7"; +} +.fa-arrow-circle-left:before { + content: "\f0a8"; +} +.fa-arrow-circle-right:before { + content: "\f0a9"; +} +.fa-arrow-circle-up:before { + content: "\f0aa"; +} +.fa-arrow-circle-down:before { + content: "\f0ab"; +} +.fa-globe:before { + content: "\f0ac"; +} +.fa-wrench:before { + content: "\f0ad"; +} +.fa-tasks:before { + content: "\f0ae"; +} +.fa-filter:before { + content: "\f0b0"; +} +.fa-briefcase:before { + content: "\f0b1"; +} +.fa-arrows-alt:before { + content: "\f0b2"; +} +.fa-group:before, +.fa-users:before { + content: "\f0c0"; +} +.fa-chain:before, +.fa-link:before { + content: "\f0c1"; +} +.fa-cloud:before { + content: "\f0c2"; +} +.fa-flask:before { + content: "\f0c3"; +} +.fa-cut:before, +.fa-scissors:before { + content: "\f0c4"; +} +.fa-copy:before, +.fa-files-o:before { + content: "\f0c5"; +} +.fa-paperclip:before { + content: "\f0c6"; +} +.fa-save:before, +.fa-floppy-o:before { + content: "\f0c7"; +} +.fa-square:before { + content: "\f0c8"; +} +.fa-navicon:before, +.fa-reorder:before, +.fa-bars:before { + content: "\f0c9"; +} +.fa-list-ul:before { + content: "\f0ca"; +} +.fa-list-ol:before { + content: "\f0cb"; +} +.fa-strikethrough:before { + content: "\f0cc"; +} +.fa-underline:before { + content: "\f0cd"; +} +.fa-table:before { + content: "\f0ce"; +} +.fa-magic:before { + content: "\f0d0"; +} +.fa-truck:before { + content: "\f0d1"; +} +.fa-pinterest:before { + content: "\f0d2"; +} +.fa-pinterest-square:before { + content: "\f0d3"; +} +.fa-google-plus-square:before { + content: "\f0d4"; +} +.fa-google-plus:before { + content: "\f0d5"; +} +.fa-money:before { + content: "\f0d6"; +} +.fa-caret-down:before { + content: "\f0d7"; +} +.fa-caret-up:before { + content: "\f0d8"; +} +.fa-caret-left:before { + content: "\f0d9"; +} +.fa-caret-right:before { + content: "\f0da"; +} +.fa-columns:before { + content: "\f0db"; +} +.fa-unsorted:before, +.fa-sort:before { + content: "\f0dc"; +} +.fa-sort-down:before, +.fa-sort-desc:before { + content: "\f0dd"; +} +.fa-sort-up:before, +.fa-sort-asc:before { + content: "\f0de"; +} +.fa-envelope:before { + content: "\f0e0"; +} +.fa-linkedin:before { + content: "\f0e1"; +} +.fa-rotate-left:before, +.fa-undo:before { + content: "\f0e2"; +} +.fa-legal:before, +.fa-gavel:before { + content: "\f0e3"; +} +.fa-dashboard:before, +.fa-tachometer:before { + content: "\f0e4"; +} +.fa-comment-o:before { + content: "\f0e5"; +} +.fa-comments-o:before { + content: "\f0e6"; +} +.fa-flash:before, +.fa-bolt:before { + content: "\f0e7"; +} +.fa-sitemap:before { + content: "\f0e8"; +} +.fa-umbrella:before { + content: "\f0e9"; +} +.fa-paste:before, +.fa-clipboard:before { + content: "\f0ea"; +} +.fa-lightbulb-o:before { + content: "\f0eb"; +} +.fa-exchange:before { + content: "\f0ec"; +} +.fa-cloud-download:before { + content: "\f0ed"; +} +.fa-cloud-upload:before { + content: "\f0ee"; +} +.fa-user-md:before { + content: "\f0f0"; +} +.fa-stethoscope:before { + content: "\f0f1"; +} +.fa-suitcase:before { + content: "\f0f2"; +} +.fa-bell-o:before { + content: "\f0a2"; +} +.fa-coffee:before { + content: "\f0f4"; +} +.fa-cutlery:before { + content: "\f0f5"; +} +.fa-file-text-o:before { + content: "\f0f6"; +} +.fa-building-o:before { + content: "\f0f7"; +} +.fa-hospital-o:before { + content: "\f0f8"; +} +.fa-ambulance:before { + content: "\f0f9"; +} +.fa-medkit:before { + content: "\f0fa"; +} +.fa-fighter-jet:before { + content: "\f0fb"; +} +.fa-beer:before { + content: "\f0fc"; +} +.fa-h-square:before { + content: "\f0fd"; +} +.fa-plus-square:before { + content: "\f0fe"; +} +.fa-angle-double-left:before { + content: "\f100"; +} +.fa-angle-double-right:before { + content: "\f101"; +} +.fa-angle-double-up:before { + content: "\f102"; +} +.fa-angle-double-down:before { + content: "\f103"; +} +.fa-angle-left:before { + content: "\f104"; +} +.fa-angle-right:before { + content: "\f105"; +} +.fa-angle-up:before { + content: "\f106"; +} +.fa-angle-down:before { + content: "\f107"; +} +.fa-desktop:before { + content: "\f108"; +} +.fa-laptop:before { + content: "\f109"; +} +.fa-tablet:before { + content: "\f10a"; +} +.fa-mobile-phone:before, +.fa-mobile:before { + content: "\f10b"; +} +.fa-circle-o:before { + content: "\f10c"; +} +.fa-quote-left:before { + content: "\f10d"; +} +.fa-quote-right:before { + content: "\f10e"; +} +.fa-spinner:before { + content: "\f110"; +} +.fa-circle:before { + content: "\f111"; +} +.fa-mail-reply:before, +.fa-reply:before { + content: "\f112"; +} +.fa-github-alt:before { + content: "\f113"; +} +.fa-folder-o:before { + content: "\f114"; +} +.fa-folder-open-o:before { + content: "\f115"; +} +.fa-smile-o:before { + content: "\f118"; +} +.fa-frown-o:before { + content: "\f119"; +} +.fa-meh-o:before { + content: "\f11a"; +} +.fa-gamepad:before { + content: "\f11b"; +} +.fa-keyboard-o:before { + content: "\f11c"; +} +.fa-flag-o:before { + content: "\f11d"; +} +.fa-flag-checkered:before { + content: "\f11e"; +} +.fa-terminal:before { + content: "\f120"; +} +.fa-code:before { + content: "\f121"; +} +.fa-mail-reply-all:before, +.fa-reply-all:before { + content: "\f122"; +} +.fa-star-half-empty:before, +.fa-star-half-full:before, +.fa-star-half-o:before { + content: "\f123"; +} +.fa-location-arrow:before { + content: "\f124"; +} +.fa-crop:before { + content: "\f125"; +} +.fa-code-fork:before { + content: "\f126"; +} +.fa-unlink:before, +.fa-chain-broken:before { + content: "\f127"; +} +.fa-question:before { + content: "\f128"; +} +.fa-info:before { + content: "\f129"; +} +.fa-exclamation:before { + content: "\f12a"; +} +.fa-superscript:before { + content: "\f12b"; +} +.fa-subscript:before { + content: "\f12c"; +} +.fa-eraser:before { + content: "\f12d"; +} +.fa-puzzle-piece:before { + content: "\f12e"; +} +.fa-microphone:before { + content: "\f130"; +} +.fa-microphone-slash:before { + content: "\f131"; +} +.fa-shield:before { + content: "\f132"; +} +.fa-calendar-o:before { + content: "\f133"; +} +.fa-fire-extinguisher:before { + content: "\f134"; +} +.fa-rocket:before { + content: "\f135"; +} +.fa-maxcdn:before { + content: "\f136"; +} +.fa-chevron-circle-left:before { + content: "\f137"; +} +.fa-chevron-circle-right:before { + content: "\f138"; +} +.fa-chevron-circle-up:before { + content: "\f139"; +} +.fa-chevron-circle-down:before { + content: "\f13a"; +} +.fa-html5:before { + content: "\f13b"; +} +.fa-css3:before { + content: "\f13c"; +} +.fa-anchor:before { + content: "\f13d"; +} +.fa-unlock-alt:before { + content: "\f13e"; +} +.fa-bullseye:before { + content: "\f140"; +} +.fa-ellipsis-h:before { + content: "\f141"; +} +.fa-ellipsis-v:before { + content: "\f142"; +} +.fa-rss-square:before { + content: "\f143"; +} +.fa-play-circle:before { + content: "\f144"; +} +.fa-ticket:before { + content: "\f145"; +} +.fa-minus-square:before { + content: "\f146"; +} +.fa-minus-square-o:before { + content: "\f147"; +} +.fa-level-up:before { + content: "\f148"; +} +.fa-level-down:before { + content: "\f149"; +} +.fa-check-square:before { + content: "\f14a"; +} +.fa-pencil-square:before { + content: "\f14b"; +} +.fa-external-link-square:before { + content: "\f14c"; +} +.fa-share-square:before { + content: "\f14d"; +} +.fa-compass:before { + content: "\f14e"; +} +.fa-toggle-down:before, +.fa-caret-square-o-down:before { + content: "\f150"; +} +.fa-toggle-up:before, +.fa-caret-square-o-up:before { + content: "\f151"; +} +.fa-toggle-right:before, +.fa-caret-square-o-right:before { + content: "\f152"; +} +.fa-euro:before, +.fa-eur:before { + content: "\f153"; +} +.fa-gbp:before { + content: "\f154"; +} +.fa-dollar:before, +.fa-usd:before { + content: "\f155"; +} +.fa-rupee:before, +.fa-inr:before { + content: "\f156"; +} +.fa-cny:before, +.fa-rmb:before, +.fa-yen:before, +.fa-jpy:before { + content: "\f157"; +} +.fa-ruble:before, +.fa-rouble:before, +.fa-rub:before { + content: "\f158"; +} +.fa-won:before, +.fa-krw:before { + content: "\f159"; +} +.fa-bitcoin:before, +.fa-btc:before { + content: "\f15a"; +} +.fa-file:before { + content: "\f15b"; +} +.fa-file-text:before { + content: "\f15c"; +} +.fa-sort-alpha-asc:before { + content: "\f15d"; +} +.fa-sort-alpha-desc:before { + content: "\f15e"; +} +.fa-sort-amount-asc:before { + content: "\f160"; +} +.fa-sort-amount-desc:before { + content: "\f161"; +} +.fa-sort-numeric-asc:before { + content: "\f162"; +} +.fa-sort-numeric-desc:before { + content: "\f163"; +} +.fa-thumbs-up:before { + content: "\f164"; +} +.fa-thumbs-down:before { + content: "\f165"; +} +.fa-youtube-square:before { + content: "\f166"; +} +.fa-youtube:before { + content: "\f167"; +} +.fa-xing:before { + content: "\f168"; +} +.fa-xing-square:before { + content: "\f169"; +} +.fa-youtube-play:before { + content: "\f16a"; +} +.fa-dropbox:before { + content: "\f16b"; +} +.fa-stack-overflow:before { + content: "\f16c"; +} +.fa-instagram:before { + content: "\f16d"; +} +.fa-flickr:before { + content: "\f16e"; +} +.fa-adn:before { + content: "\f170"; +} +.fa-bitbucket:before { + content: "\f171"; +} +.fa-bitbucket-square:before { + content: "\f172"; +} +.fa-tumblr:before { + content: "\f173"; +} +.fa-tumblr-square:before { + content: "\f174"; +} +.fa-long-arrow-down:before { + content: "\f175"; +} +.fa-long-arrow-up:before { + content: "\f176"; +} +.fa-long-arrow-left:before { + content: "\f177"; +} +.fa-long-arrow-right:before { + content: "\f178"; +} +.fa-apple:before { + content: "\f179"; +} +.fa-windows:before { + content: "\f17a"; +} +.fa-android:before { + content: "\f17b"; +} +.fa-linux:before { + content: "\f17c"; +} +.fa-dribbble:before { + content: "\f17d"; +} +.fa-skype:before { + content: "\f17e"; +} +.fa-foursquare:before { + content: "\f180"; +} +.fa-trello:before { + content: "\f181"; +} +.fa-female:before { + content: "\f182"; +} +.fa-male:before { + content: "\f183"; +} +.fa-gittip:before { + content: "\f184"; +} +.fa-sun-o:before { + content: "\f185"; +} +.fa-moon-o:before { + content: "\f186"; +} +.fa-archive:before { + content: "\f187"; +} +.fa-bug:before { + content: "\f188"; +} +.fa-vk:before { + content: "\f189"; +} +.fa-weibo:before { + content: "\f18a"; +} +.fa-renren:before { + content: "\f18b"; +} +.fa-pagelines:before { + content: "\f18c"; +} +.fa-stack-exchange:before { + content: "\f18d"; +} +.fa-arrow-circle-o-right:before { + content: "\f18e"; +} +.fa-arrow-circle-o-left:before { + content: "\f190"; +} +.fa-toggle-left:before, +.fa-caret-square-o-left:before { + content: "\f191"; +} +.fa-dot-circle-o:before { + content: "\f192"; +} +.fa-wheelchair:before { + content: "\f193"; +} +.fa-vimeo-square:before { + content: "\f194"; +} +.fa-turkish-lira:before, +.fa-try:before { + content: "\f195"; +} +.fa-plus-square-o:before { + content: "\f196"; +} +.fa-space-shuttle:before { + content: "\f197"; +} +.fa-slack:before { + content: "\f198"; +} +.fa-envelope-square:before { + content: "\f199"; +} +.fa-wordpress:before { + content: "\f19a"; +} +.fa-openid:before { + content: "\f19b"; +} +.fa-institution:before, +.fa-bank:before, +.fa-university:before { + content: "\f19c"; +} +.fa-mortar-board:before, +.fa-graduation-cap:before { + content: "\f19d"; +} +.fa-yahoo:before { + content: "\f19e"; +} +.fa-google:before { + content: "\f1a0"; +} +.fa-reddit:before { + content: "\f1a1"; +} +.fa-reddit-square:before { + content: "\f1a2"; +} +.fa-stumbleupon-circle:before { + content: "\f1a3"; +} +.fa-stumbleupon:before { + content: "\f1a4"; +} +.fa-delicious:before { + content: "\f1a5"; +} +.fa-digg:before { + content: "\f1a6"; +} +.fa-pied-piper-square:before, +.fa-pied-piper:before { + content: "\f1a7"; +} +.fa-pied-piper-alt:before { + content: "\f1a8"; +} +.fa-drupal:before { + content: "\f1a9"; +} +.fa-joomla:before { + content: "\f1aa"; +} +.fa-language:before { + content: "\f1ab"; +} +.fa-fax:before { + content: "\f1ac"; +} +.fa-building:before { + content: "\f1ad"; +} +.fa-child:before { + content: "\f1ae"; +} +.fa-paw:before { + content: "\f1b0"; +} +.fa-spoon:before { + content: "\f1b1"; +} +.fa-cube:before { + content: "\f1b2"; +} +.fa-cubes:before { + content: "\f1b3"; +} +.fa-behance:before { + content: "\f1b4"; +} +.fa-behance-square:before { + content: "\f1b5"; +} +.fa-steam:before { + content: "\f1b6"; +} +.fa-steam-square:before { + content: "\f1b7"; +} +.fa-recycle:before { + content: "\f1b8"; +} +.fa-automobile:before, +.fa-car:before { + content: "\f1b9"; +} +.fa-cab:before, +.fa-taxi:before { + content: "\f1ba"; +} +.fa-tree:before { + content: "\f1bb"; +} +.fa-spotify:before { + content: "\f1bc"; +} +.fa-deviantart:before { + content: "\f1bd"; +} +.fa-soundcloud:before { + content: "\f1be"; +} +.fa-database:before { + content: "\f1c0"; +} +.fa-file-pdf-o:before { + content: "\f1c1"; +} +.fa-file-word-o:before { + content: "\f1c2"; +} +.fa-file-excel-o:before { + content: "\f1c3"; +} +.fa-file-powerpoint-o:before { + content: "\f1c4"; +} +.fa-file-photo-o:before, +.fa-file-picture-o:before, +.fa-file-image-o:before { + content: "\f1c5"; +} +.fa-file-zip-o:before, +.fa-file-archive-o:before { + content: "\f1c6"; +} +.fa-file-sound-o:before, +.fa-file-audio-o:before { + content: "\f1c7"; +} +.fa-file-movie-o:before, +.fa-file-video-o:before { + content: "\f1c8"; +} +.fa-file-code-o:before { + content: "\f1c9"; +} +.fa-vine:before { + content: "\f1ca"; +} +.fa-codepen:before { + content: "\f1cb"; +} +.fa-jsfiddle:before { + content: "\f1cc"; +} +.fa-life-bouy:before, +.fa-life-saver:before, +.fa-support:before, +.fa-life-ring:before { + content: "\f1cd"; +} +.fa-circle-o-notch:before { + content: "\f1ce"; +} +.fa-ra:before, +.fa-rebel:before { + content: "\f1d0"; +} +.fa-ge:before, +.fa-empire:before { + content: "\f1d1"; +} +.fa-git-square:before { + content: "\f1d2"; +} +.fa-git:before { + content: "\f1d3"; +} +.fa-hacker-news:before { + content: "\f1d4"; +} +.fa-tencent-weibo:before { + content: "\f1d5"; +} +.fa-qq:before { + content: "\f1d6"; +} +.fa-wechat:before, +.fa-weixin:before { + content: "\f1d7"; +} +.fa-send:before, +.fa-paper-plane:before { + content: "\f1d8"; +} +.fa-send-o:before, +.fa-paper-plane-o:before { + content: "\f1d9"; +} +.fa-history:before { + content: "\f1da"; +} +.fa-circle-thin:before { + content: "\f1db"; +} +.fa-header:before { + content: "\f1dc"; +} +.fa-paragraph:before { + content: "\f1dd"; +} +.fa-sliders:before { + content: "\f1de"; +} +.fa-share-alt:before { + content: "\f1e0"; +} +.fa-share-alt-square:before { + content: "\f1e1"; +} +.fa-bomb:before { + content: "\f1e2"; +} diff --git a/ui/ecobidas_ui/static/style.css b/ui/ecobidas_ui/static/css/main.css similarity index 100% rename from ui/ecobidas_ui/static/style.css rename to ui/ecobidas_ui/static/css/main.css diff --git a/ui/ecobidas_ui/static/favicon.ico b/ui/ecobidas_ui/static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..be74abd69ad6a32de7375df13cab9354798e328f GIT binary patch literal 766 zcmc(dze~eV5XUd2fg&jH87YDYDQKxq1{4b-_ydP-wqS9vgGh17QXQQAwOE{VaBvi* zmu^z9t({y-&1ey8Y_x;?x+`BviV9;aRjMgZ8M*!jgkRrFqSI9;F zHyfX@Az|AvVmn~YWWZP`0&JWEY~BFm?*Vq}VD7&_%x%MP$p`D`4JMC!K|B7pt?Mmp zUJAB7rxMXS6=!P+AtLU9V)J#61WPxwipRXCHO{BJ`l{m53#=t97a!znv~vfmr|AaP zRGIT7#0FyJy3Z*hL{GQp-0TRhX8UzZ)+>%?mK0^goaX4Q;x +{% block page_title %}500 Error - Unauthorized{% endblock %} + +{% block content %} +
+
+
+ +

+ You are not authorized to see this page. Please + log in or + create a new account. +

+

+ Want to go home instead? +

+
+
+
+{% endblock %} diff --git a/ui/ecobidas_ui/templates/404.html b/ui/ecobidas_ui/templates/404.html index c196c766..7e446981 100644 --- a/ui/ecobidas_ui/templates/404.html +++ b/ui/ecobidas_ui/templates/404.html @@ -1,14 +1,16 @@ -{% extends 'base.html' %} +{% extends 'layout/base.html' %} -{% block title %} 404 Error - Page Not Found {% endblock %} +{% block title %}404 Error - Page Not Found{% endblock %} {% block content %}
-
-

Page not found (Error 404)

- -

Go to home page

+
+ +

Sorry, that page doesn't exist.

+

+ Want to go home instead? +

diff --git a/ui/ecobidas_ui/templates/500.html b/ui/ecobidas_ui/templates/500.html index 54defb2f..b3594f29 100644 --- a/ui/ecobidas_ui/templates/500.html +++ b/ui/ecobidas_ui/templates/500.html @@ -1,14 +1,19 @@ -{% extends 'base.html' %} +{% extends 'layout/base.html' %} -{% block title %} 500 Error - Internal Server Error {% endblock %} +{% block title %}500 Error - Internal Server Error{% endblock %} {% block content %}
-
-

Internal server error (500)

+
-

Go to search page

+

+ Sorry, something went wrong on our system. Don't panic, we are fixing + it! Please try again later. +

+

+ Want to go home instead? +

diff --git a/ui/ecobidas_ui/templates/auth/login.html b/ui/ecobidas_ui/templates/auth/login.html index f40b0047..6cfe371d 100644 --- a/ui/ecobidas_ui/templates/auth/login.html +++ b/ui/ecobidas_ui/templates/auth/login.html @@ -1,4 +1,4 @@ -{% extends 'base.html' %} +{% extends 'layout/base.html' %} {% block content %} diff --git a/ui/ecobidas_ui/templates/auth/register.html b/ui/ecobidas_ui/templates/auth/register.html index e36a1af7..b5cbc764 100644 --- a/ui/ecobidas_ui/templates/auth/register.html +++ b/ui/ecobidas_ui/templates/auth/register.html @@ -1,4 +1,4 @@ -{% extends 'base.html' %} +{% extends 'layout/base.html' %} {% block content %} diff --git a/ui/ecobidas_ui/templates/base.html b/ui/ecobidas_ui/templates/base.html deleted file mode 100644 index dad901a5..00000000 --- a/ui/ecobidas_ui/templates/base.html +++ /dev/null @@ -1,196 +0,0 @@ - - - - - - - {% block title %} {% endblock %} - - {{ bootstrap.load_css() }} - - - - - - - - - - - - - - - - - - - -
-
-
- -
-
-
- -
-
- {% with messages = get_flashed_messages() %} {% if messages %} {% for - message in messages %} - - {% endfor %} {% endif %} {% endwith %} -
-
- -
-
- -
- -
-
- {% block content %} {% endblock %} -
-
- - - {{ bootstrap.load_js() }} -
- - -
-
-
-
-
- eCobidas -
-
- - -
-
-
-
-
- diff --git a/ui/ecobidas_ui/templates/layout/base.html b/ui/ecobidas_ui/templates/layout/base.html new file mode 100644 index 00000000..520a01b2 --- /dev/null +++ b/ui/ecobidas_ui/templates/layout/base.html @@ -0,0 +1,92 @@ + + + + + + + {% block title %} {% endblock %} + + + + + {{ bootstrap.load_css() }} {% assets "css" %} + + {% endassets %} + + + + + {% include "layout/svg.html" %} + +
+
+
+ +
+
+
+ + {% with messages = get_flashed_messages() %} + + {% if messages %} + + {% for message in messages %} +
+
+ +
+
+ {% endfor %} + + {% endif %} + + {% endwith %} + +
+ {% include "layout/nav.html" %} + +
+
+ {% block content %} + + {% endblock %} +
+
+ + + {{ bootstrap.load_js() }} +
+ + + {% include "layout/footer.html" %} + diff --git a/ui/ecobidas_ui/templates/layout/footer.html b/ui/ecobidas_ui/templates/layout/footer.html new file mode 100644 index 00000000..60b14cd8 --- /dev/null +++ b/ui/ecobidas_ui/templates/layout/footer.html @@ -0,0 +1,25 @@ +
+
+
+
+
eCobidas
+
+ + +
+
+
+
+
diff --git a/ui/ecobidas_ui/templates/layout/nav.html b/ui/ecobidas_ui/templates/layout/nav.html new file mode 100644 index 00000000..ef4e2ad9 --- /dev/null +++ b/ui/ecobidas_ui/templates/layout/nav.html @@ -0,0 +1,82 @@ +
+ +
diff --git a/ui/ecobidas_ui/templates/layout/svg.html b/ui/ecobidas_ui/templates/layout/svg.html new file mode 100644 index 00000000..655bc1d1 --- /dev/null +++ b/ui/ecobidas_ui/templates/layout/svg.html @@ -0,0 +1,21 @@ + + + + + + + + + + + diff --git a/ui/ecobidas_ui/templates/protocol.html b/ui/ecobidas_ui/templates/protocol.html index 087d111b..1f7408b9 100644 --- a/ui/ecobidas_ui/templates/protocol.html +++ b/ui/ecobidas_ui/templates/protocol.html @@ -1,4 +1,6 @@ -{% extends 'base.html' %} {% from 'bootstrap5/form.html' import render_form %} +{% extends 'layout/base.html' %} + +{% from 'bootstrap5/form.html' import render_form %} {% block title %} eCOBIDAS - {{ protocol_pref_label }} {% endblock %} @@ -9,39 +11,15 @@

{{ protocol_pref_label }}

- + {% include "side_nav.html" %}
+
- {% if landing_page %} {{ protocol_preamble }} {{ landing_page }} {% else - %} + {% if landing_page %} {{ protocol_preamble|safe }} {{ landing_page|safe }} + {% else %}

{{ activity_pref_label }}

+ + {% if form %}

{{ activity_pref_label }}

>{{ completed_items }} / {{ nb_items }} items completed

- - {{ activity_preamble }} + {% endif %} {{ activity_preamble|safe }}
@@ -72,11 +49,12 @@
participants.tsv file formatted according to the BIDS specification along with a participants.json file containing column annotations generated by - the neurobagel annotation tool.

@@ -95,6 +73,7 @@
*_bold.json file formatted according to the BIDS specification containing the metadata for your fMRI runs. @@ -105,14 +84,14 @@
+ {% if form %}
{{ render_form(form) }}
- - {% endif %} + {% endif %} {% endif %}
diff --git a/ui/ecobidas_ui/templates/about.html b/ui/ecobidas_ui/templates/public/about.html similarity index 72% rename from ui/ecobidas_ui/templates/about.html rename to ui/ecobidas_ui/templates/public/about.html index a36f35d6..b581b65d 100644 --- a/ui/ecobidas_ui/templates/about.html +++ b/ui/ecobidas_ui/templates/public/about.html @@ -1,4 +1,4 @@ -{% extends 'base.html' %} +{% extends 'layout/base.html' %} {% block title %} eCOBIDAS - About {% endblock %} @@ -10,22 +10,28 @@

Have any questions? Something is missing? Let us know.

  • drop us an email on our - google group.
  • open an issue this - github repository. + github repository.
  • leave a message on the cobidas_checklist channel on the brainhack channel. @@ -42,7 +48,9 @@

    Why this project?

    Follow the link if you want to know more about the - motivations behind this project.

    @@ -50,12 +58,17 @@

    Background

    This checklist is a project to make a user friendly checklist out the best practices - report of - the Committee on Best Practices in Data Analysis and Sharing (report + of the Committee on Best Practices in Data Analysis and Sharing (COBIDAS) of the - Organization for Human Brain Mapping.

    @@ -63,7 +76,9 @@

    Background

    This is very much of a work in progress but the next step is to expand the list to cover all the items of the COBIDAS report for fMRI as well as for the recent - extension to EEG and MEG. + extension to EEG and MEG.

    Want to help?

    @@ -76,12 +91,16 @@

    Want to help?

    Want to know more?

    Most of the information concerning this project can be found on this - github repository. + github repository.

    If you want to be kept posted about the progress of the project, you can join our - google group

    @@ -91,6 +110,7 @@

    Want to know more?

    cobidas_checklist channel on the brainhack Want to know more?

    - There is also an OSF project to - centralize all the information and repos. + There is also an OSF + project to centralize all the information and repos.

    We have a - list of short, middle, long term goals: if you are interested by any of those @@ -118,6 +140,7 @@

    Contributors

    The list of the people involved in this project can be found here.

    diff --git a/ui/ecobidas_ui/templates/public/faq.html b/ui/ecobidas_ui/templates/public/faq.html new file mode 100644 index 00000000..a004c667 --- /dev/null +++ b/ui/ecobidas_ui/templates/public/faq.html @@ -0,0 +1,36 @@ +{% extends "layout/base.html" %} {% block title %} eCOBIDAS - FAQ {% endblock %} +{% block content %} +
    +
    +
    + {% set count = [0] %} {% for s in data['sections'] %} +

    {{ s['name'] }}

    + {% for item in s['questions'] %} {% set _ = count.append(count.pop()+1) %} +
    +
    +

    + +

    +
    +
    {{ item['a']|safe }}
    +
    +
    +
    + {% endfor %} {% endfor %} +
    +
    + {% endblock %} +
    diff --git a/ui/ecobidas_ui/templates/index.html b/ui/ecobidas_ui/templates/public/index.html similarity index 96% rename from ui/ecobidas_ui/templates/index.html rename to ui/ecobidas_ui/templates/public/index.html index 7ae6f3a8..32c9b55a 100644 --- a/ui/ecobidas_ui/templates/index.html +++ b/ui/ecobidas_ui/templates/public/index.html @@ -1,4 +1,4 @@ -{% extends 'base.html' %} +{% extends 'layout/base.html' %} {% block title %} eCOBIDAS {% endblock %} diff --git a/ui/ecobidas_ui/templates/side_nav.html b/ui/ecobidas_ui/templates/side_nav.html new file mode 100644 index 00000000..0e9519b2 --- /dev/null +++ b/ui/ecobidas_ui/templates/side_nav.html @@ -0,0 +1,28 @@ + diff --git a/ui/ecobidas_ui/utils.py b/ui/ecobidas_ui/utils.py index 0a26adb2..75898d7f 100644 --- a/ui/ecobidas_ui/utils.py +++ b/ui/ecobidas_ui/utils.py @@ -6,6 +6,7 @@ import pandas as pd import requests +from flask import flash from markupsafe import escape from rich import print @@ -255,3 +256,10 @@ def extract_values_participants(df, json_content, target): return df[column].min() if target == "subject_age_max": return df[column].max() + + +def flash_errors(form, category="warning"): + """Flash all errors for a form.""" + for field, errors in form.errors.items(): + for error in errors: + flash(f"{getattr(form, field).label.text} - {error}", category) diff --git a/ui/pyproject.toml b/ui/pyproject.toml index fa0357b9..9d0c7cf6 100644 --- a/ui/pyproject.toml +++ b/ui/pyproject.toml @@ -7,10 +7,14 @@ authors = [{name = "Remi Gau"}] dependencies = [ "flask", "Flask-WTF", + "Flask-Assets", "bootstrap-flask", "pandas", "rich", - "requests" + "requests", + "Flask-Caching", + "Flask-DebugToolbar", + "environs" ] description = "UI for eCOBIDAS" license = {text = "GPL 3.0"} diff --git a/ui/requirements.txt b/ui/requirements.txt index 07a0ae39..302b83bb 100644 --- a/ui/requirements.txt +++ b/ui/requirements.txt @@ -4,6 +4,7 @@ # # pip-compile --output-file=requirements.txt --strip-extras pyproject.toml # +Flask-Assets blinker==1.8.2 # via flask bootstrap-flask==2.4.0 From b51104f651e7e0e2a439d5b003cc5cf3d551ee8b Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Mon, 27 May 2024 21:44:18 +0200 Subject: [PATCH 20/31] refactor tests --- .flake8 | 2 +- ecobidas/generate_landing_page.py | 22 -- ecobidas/templates/contact.j2 | 16 - ecobidas/templates/how_to_use.j2 | 14 - ecobidas/templates/landing_page.j2 | 14 - ecobidas/templates/want_to_help.j2 | 6 - ecobidas/templates/want_to_know_more.j2 | 9 - ecobidas/templates/why_this_project.j2 | 11 - ecobidas/utils.py | 2 +- tests/data/protocols/test_schema.jsonld | 2 +- tests/test_generate_files.py | 6 - tests/test_utils.py | 4 +- ui/ecobidas_ui/app.py | 27 +- ui/ecobidas_ui/auth/__init__.py | 3 + ui/ecobidas_ui/{auth.py => auth/views.py} | 14 +- ui/ecobidas_ui/protocols/__init__.py | 3 + ui/ecobidas_ui/{ => protocols}/forms.py | 28 +- ui/ecobidas_ui/protocols/utils.py | 282 ++++++++++++++++++ .../{protocol.py => protocols/views.py} | 197 +++++++----- ui/ecobidas_ui/settings.py | 2 +- .../static/images/BIDS_logo_black.svg | 1 + ui/ecobidas_ui/templates/extra_forms.html | 51 ++++ ui/ecobidas_ui/templates/layout/base.html | 20 +- ui/ecobidas_ui/templates/layout/footer.html | 1 + ui/ecobidas_ui/templates/protocol.html | 69 +---- ui/ecobidas_ui/utils.py | 264 ---------------- ui/tests/__init__.py | 0 ui/tests/conftest.py | 41 --- ui/tests/data.sql | 8 - ui/tests/protocols/__init__.py | 0 ui/tests/{ => protocols}/test_utils.py | 33 +- 31 files changed, 561 insertions(+), 591 deletions(-) delete mode 100644 ecobidas/generate_landing_page.py delete mode 100644 ecobidas/templates/contact.j2 delete mode 100644 ecobidas/templates/how_to_use.j2 delete mode 100644 ecobidas/templates/landing_page.j2 delete mode 100644 ecobidas/templates/want_to_help.j2 delete mode 100644 ecobidas/templates/want_to_know_more.j2 delete mode 100644 ecobidas/templates/why_this_project.j2 create mode 100644 ui/ecobidas_ui/auth/__init__.py rename ui/ecobidas_ui/{auth.py => auth/views.py} (87%) create mode 100644 ui/ecobidas_ui/protocols/__init__.py rename ui/ecobidas_ui/{ => protocols}/forms.py (87%) create mode 100644 ui/ecobidas_ui/protocols/utils.py rename ui/ecobidas_ui/{protocol.py => protocols/views.py} (58%) create mode 100644 ui/ecobidas_ui/static/images/BIDS_logo_black.svg create mode 100644 ui/ecobidas_ui/templates/extra_forms.html create mode 100644 ui/tests/__init__.py delete mode 100644 ui/tests/conftest.py delete mode 100644 ui/tests/data.sql create mode 100644 ui/tests/protocols/__init__.py rename ui/tests/{ => protocols}/test_utils.py (58%) diff --git a/.flake8 b/.flake8 index 3133b205..46a95fe5 100644 --- a/.flake8 +++ b/.flake8 @@ -9,7 +9,7 @@ max-line-length = 150 max_complexity = 15 max_function_length = 150 max_parameters_amount = 10 -max_returns_amount = 6 +max_returns_amount = 7 # ----------------------- errors to include / exclude ----------------------- diff --git a/ecobidas/generate_landing_page.py b/ecobidas/generate_landing_page.py deleted file mode 100644 index a9c70347..00000000 --- a/ecobidas/generate_landing_page.py +++ /dev/null @@ -1,22 +0,0 @@ -"""Generates a typical landing page in english for an app.""" - -from pathlib import Path - -from ecobidas.template_manager import TemplateManager - - -def main(output_dir: Path | None = None) -> None: - if output_dir is None: - output_dir = Path() / "output" - - TemplateManager.initialize() - - template = TemplateManager.env.get_template("landing_page.j2") - - rendered_template = template.render() - with open(output_dir / "landing_page.html", "w") as out: - out.write(f"{rendered_template}") - - -if __name__ == "__main__": - main() diff --git a/ecobidas/templates/contact.j2 b/ecobidas/templates/contact.j2 deleted file mode 100644 index b63ed38e..00000000 --- a/ecobidas/templates/contact.j2 +++ /dev/null @@ -1,16 +0,0 @@ -

    Have any questions? Something is missing? Let us know.

    - diff --git a/ecobidas/templates/how_to_use.j2 b/ecobidas/templates/how_to_use.j2 deleted file mode 100644 index b8274636..00000000 --- a/ecobidas/templates/how_to_use.j2 +++ /dev/null @@ -1,14 +0,0 @@ -

    How to use it

    -

    - You can navigate each section on the left and then answer the questions - corresponding to your design, acquisition, analysis... - This is meant to make sure that you have not forgotten any of the essential - information in the methods and results parts of your article. -

    -

    - At the end, you can click on Export (bottom left) to get a zip file - containing machine readable jsonld files that captures information about - your method/results section: our next step is to use this to automate the - part of the methods writing and to submit the information alongside data - submission to data archives. -

    diff --git a/ecobidas/templates/landing_page.j2 b/ecobidas/templates/landing_page.j2 deleted file mode 100644 index af5a188c..00000000 --- a/ecobidas/templates/landing_page.j2 +++ /dev/null @@ -1,14 +0,0 @@ -
    -
    -

    Information Collection Protocol

    - {% include 'how_to_use.j2' %} - {% include 'contact.j2' %} - {% include 'why_this_project.j2' %} -

    Background

    - {% include 'want_to_help.j2' %} - {% include 'want_to_know_more.j2' %} -

    Contributors

    -

    License

    -

    The protocol is licensed CC-BY-4.0

    -
    -
    diff --git a/ecobidas/templates/want_to_help.j2 b/ecobidas/templates/want_to_help.j2 deleted file mode 100644 index 6ec752da..00000000 --- a/ecobidas/templates/want_to_help.j2 +++ /dev/null @@ -1,6 +0,0 @@ -

    Want to help?

    -

    - We are looking for people to give us feedback or help us move forward. - If you are interested, check our - documentation for contributors. -

    diff --git a/ecobidas/templates/want_to_know_more.j2 b/ecobidas/templates/want_to_know_more.j2 deleted file mode 100644 index 92588091..00000000 --- a/ecobidas/templates/want_to_know_more.j2 +++ /dev/null @@ -1,9 +0,0 @@ -

    Want to know more?

    -

    - Most of the information concerning this project can be found in - our documentation. -

    -

    - If you want to be kept posted about the progress of the project, - check our contact page -

    diff --git a/ecobidas/templates/why_this_project.j2 b/ecobidas/templates/why_this_project.j2 deleted file mode 100644 index 4814ea92..00000000 --- a/ecobidas/templates/why_this_project.j2 +++ /dev/null @@ -1,11 +0,0 @@ -

    Why this project?

    -

    - Poor methods and results description hinders the reproducibility and the replicability of research. - It also makes it hard to compare new and old results and generally increases inefficiency in the research process. - This project is built on the hope that improving methods and results reporting could improve our research. -

    -

    - Follow the link if you want to know more about the - motivations behind this project. -

    diff --git a/ecobidas/utils.py b/ecobidas/utils.py index fac70318..1cd21159 100644 --- a/ecobidas/utils.py +++ b/ecobidas/utils.py @@ -55,7 +55,7 @@ def get_landing_page(schema_info: dict[str, str]) -> str: if schema_info["landing_page"]: return schema_info["landing_page"] else: - return "../README_eCOBIDAS-en.md" + return "../README_eCOBIDAS-en.html" def get_schema_info(this_schema: str | Path) -> dict[str, str]: diff --git a/tests/data/protocols/test_schema.jsonld b/tests/data/protocols/test_schema.jsonld index 757d6169..66f2adc0 100644 --- a/tests/data/protocols/test_schema.jsonld +++ b/tests/data/protocols/test_schema.jsonld @@ -88,7 +88,7 @@ ] }, "landingPage": { - "@id": "../README_eCOBIDAS-en.md", + "@id": "../README_eCOBIDAS-en.html", "inLanguage": "en" } } diff --git a/tests/test_generate_files.py b/tests/test_generate_files.py index 56b4604a..e9dd0008 100644 --- a/tests/test_generate_files.py +++ b/tests/test_generate_files.py @@ -1,4 +1,3 @@ -from ecobidas.generate_landing_page import main as landing_page_main from ecobidas.macros import main as app_list_table_main @@ -6,8 +5,3 @@ def test_generate_table(tmp_path): app_list_table_main(tmp_path) assert (tmp_path / "apps_table.md").exists() assert (tmp_path / "preset_responses_table.md").exists() - - -def test_landing_page(tmp_path): - landing_page_main(tmp_path) - assert (tmp_path / "landing_page.html").exists() diff --git a/tests/test_utils.py b/tests/test_utils.py index 279f4092..864b35bb 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -38,8 +38,8 @@ def test_get_output_dir(tmp_path): "this_schema, filename", [ ("neurovault", "../README_eCOBIDAS-en.html"), - ("test", "../README_eCOBIDAS-en.md"), - ("pet", "../README_PET-en.md"), + ("test", "../README_eCOBIDAS-en.html"), + ("pet", "../README_PET-en.html"), ], ) def test_get_landing_page(this_schema, filename): diff --git a/ui/ecobidas_ui/app.py b/ui/ecobidas_ui/app.py index 099a6ca1..fb08aaf5 100644 --- a/ui/ecobidas_ui/app.py +++ b/ui/ecobidas_ui/app.py @@ -1,8 +1,11 @@ import logging import sys -from ecobidas_ui import auth, db, protocol, public -from ecobidas_ui.extensions import bootstrap, cache, csrf_protect, debug_toolbar +from ecobidas_ui import auth, db, protocols, public +from ecobidas_ui._version import version +from ecobidas_ui.extensions import bootstrap, csrf_protect + +# from ecobidas_ui.extensions import cache, debug_toolbar from ecobidas_ui.initializers.assets import init_assets from flask import Flask, flash, render_template @@ -22,15 +25,19 @@ def create_app(config_object="ecobidas_ui.settings"): register_errorhandlers(app) configure_logger(app) + @app.context_processor + def inject_version(): + return dict(version=version) + @app.route("/export") def export() -> str: - flash("Not implemented yet!") - return render_template("index.html") + flash("'Export' not implemented yet!", category="warning") + return render_template("public/index.html") @app.route("/generate") def generate() -> str: - flash("Not implemented yet!") - return render_template("index.html") + flash("'Generate' Not implemented yet!", category="warning") + return render_template("public/index.html") return app @@ -39,16 +46,16 @@ def register_extensions(app): """Register Flask extensions.""" bootstrap.init_app(app) csrf_protect.init_app(app) - cache.init_app(app) - debug_toolbar.init_app(app) + # cache.init_app(app) + # debug_toolbar.init_app(app) return None def register_blueprints(app): """Register Flask blueprints.""" app.register_blueprint(public.views.blueprint) - app.register_blueprint(auth.bp) - app.register_blueprint(protocol.bp) + app.register_blueprint(auth.views.blueprint) + app.register_blueprint(protocols.views.blueprint) return None diff --git a/ui/ecobidas_ui/auth/__init__.py b/ui/ecobidas_ui/auth/__init__.py new file mode 100644 index 00000000..05af8588 --- /dev/null +++ b/ui/ecobidas_ui/auth/__init__.py @@ -0,0 +1,3 @@ +"""The public module, including the homepage and user auth.""" + +from . import views # noqa diff --git a/ui/ecobidas_ui/auth.py b/ui/ecobidas_ui/auth/views.py similarity index 87% rename from ui/ecobidas_ui/auth.py rename to ui/ecobidas_ui/auth/views.py index 571eebac..30824f72 100644 --- a/ui/ecobidas_ui/auth.py +++ b/ui/ecobidas_ui/auth/views.py @@ -4,10 +4,10 @@ from flask import Blueprint, flash, g, redirect, render_template, request, session, url_for from werkzeug.security import check_password_hash, generate_password_hash -bp = Blueprint("auth", __name__, url_prefix="/auth") +blueprint = Blueprint("auth", __name__, url_prefix="/auth") -@bp.route("/register", methods=("GET", "POST")) +@blueprint.route("/register", methods=("GET", "POST")) def register(): if request.method == "POST": username = request.form["username"] @@ -32,12 +32,12 @@ def register(): else: return redirect(url_for("auth.login")) - flash(error) + flash(error, category="warning") return render_template("auth/register.html") -@bp.route("/login", methods=("GET", "POST")) +@blueprint.route("/login", methods=("GET", "POST")) def login(): if request.method == "POST": username = request.form["username"] @@ -56,12 +56,12 @@ def login(): session["user_id"] = user["id"] return redirect(url_for("index")) - flash(error) + flash(error, category="warning") return render_template("auth/login.html") -@bp.before_app_request +@blueprint.before_app_request def load_logged_in_user(): user_id = session.get("user_id") @@ -71,7 +71,7 @@ def load_logged_in_user(): g.user = get_db().execute("SELECT * FROM user WHERE id = ?", (user_id,)).fetchone() -@bp.route("/logout") +@blueprint.route("/logout") def logout(): session.clear() return redirect(url_for("index")) diff --git a/ui/ecobidas_ui/protocols/__init__.py b/ui/ecobidas_ui/protocols/__init__.py new file mode 100644 index 00000000..05af8588 --- /dev/null +++ b/ui/ecobidas_ui/protocols/__init__.py @@ -0,0 +1,3 @@ +"""The public module, including the homepage and user auth.""" + +from . import views # noqa diff --git a/ui/ecobidas_ui/forms.py b/ui/ecobidas_ui/protocols/forms.py similarity index 87% rename from ui/ecobidas_ui/forms.py rename to ui/ecobidas_ui/protocols/forms.py index f4ba1987..60b3d2eb 100644 --- a/ui/ecobidas_ui/forms.py +++ b/ui/ecobidas_ui/protocols/forms.py @@ -1,12 +1,11 @@ from flask_wtf import FlaskForm -from flask_wtf.file import FileField, FileRequired +from flask_wtf.file import FileAllowed, FileField, FileRequired, MultipleFileField from markupsafe import Markup from wtforms import ( DateField, DecimalField, HiddenField, IntegerField, - MultipleFileField, RadioField, SelectField, SelectMultipleField, @@ -18,16 +17,25 @@ class UploadParticipantsForm(FlaskForm): - participants = MultipleFileField("Upload participants.tsv and participants.json") + participants = MultipleFileField( + "Upload participants.tsv and participants.json", + validators=[ + FileRequired(), + FileAllowed(["tsv", "json"], "File must be '.tsv' and '.json' files."), + ], + ) submit = SubmitField("Upload") class UploadBoldJsonForm(FlaskForm): - bold_json = FileField("Upload bold.json", validators=[FileRequired()]) + bold_json = FileField( + "Upload bold.json", + validators=[FileRequired(), FileAllowed(["json"], "The file must be a '.json' file.")], + ) submit_bold_json = SubmitField("Upload") -def generate_form(items=None, prefix=None): +def generate_form(items=None, prefix=None, obj=None) -> FlaskForm: class DyanmicForm(FlaskForm): pass @@ -115,12 +123,6 @@ class DyanmicForm(FlaskForm): elif input_type == "slider": - # FieldType = DecimalRangeField - # render_kw["value"]= "50.0" - # render_kw["min"]= "0.0" - # render_kw["max"]= "100.0" - # render_kw["step"]= "0.5" - min_label = float(item["choices"][0][1]) max_label = float(item["choices"][-1][1]) @@ -147,10 +149,10 @@ class DyanmicForm(FlaskForm): setattr(form, "submit", SubmitField("Save")) # noqa B010 - return form() + return form(obj=obj) -def add_choice_based_items(form, prefix, item_name, item): +def add_choice_based_items(form: FlaskForm, prefix: str, item_name: str, item: dict) -> FlaskForm: question = f"{item['question']} {item['unit']}" diff --git a/ui/ecobidas_ui/protocols/utils.py b/ui/ecobidas_ui/protocols/utils.py new file mode 100644 index 00000000..fae13cc3 --- /dev/null +++ b/ui/ecobidas_ui/protocols/utils.py @@ -0,0 +1,282 @@ +# functions to be used by the routes +import json +from functools import lru_cache +from pathlib import Path +from typing import Any + +import pandas as pd +import requests +from ecobidas_ui.utils import LANG +from flask import flash +from markupsafe import escape +from rich import print + +ALLOWED_EXTENSIONS = {".tsv", ".json"} + + +def local_cobidas_schema(): + return Path(__file__).parents[3] / "cobidas_schema" + + +def allowed_file(filename: str | Path): + return Path(filename).suffix in ALLOWED_EXTENSIONS + + +def protocol_url(protocol_name: Path) -> Path: + return ( + local_cobidas_schema() + / "schemas" + / protocol_name + / "protocols" + / f"{protocol_name}_schema.jsonld" + ) + + +@lru_cache +def get_protocol(protocol_name: str) -> dict[str, Any]: + file = protocol_url(protocol_name) + with open(file) as f: + content = json.load(f) + return content + + +def get_item(file: Path) -> dict[str, Any]: + with open(file) as f: + content = json.load(f) + return content + + +@lru_cache +def query_choices(url: str) -> None | dict[str, Any]: + try: + data = requests.get(url).json() + except Exception as exc: + print(exc) + data = None + return data + + +@lru_cache +def get_landing_page(url: Path) -> None | dict[str, Any]: + try: + if str(url).startswith("https:"): + data = requests.get(url) + else: + data = Path(url).read_text() + except Exception as exc: + print(exc) + data = None + return data + + +def get_nav_bar_content( + protocol_name: str, activity_name: str | None = None +) -> list[dict[str, str]]: + protocol_content = get_protocol(protocol_name) + + order = protocol_content["ui"]["order"] + properties = protocol_content["ui"]["addProperties"] + properties = sort_ui_properties(properties=properties, order=order) + + activities = [ + {"name": "Start", "link": "#", "class": "nav-link active"}, + ] + activities.extend( + { + "name": activity["prefLabel"][LANG], + "link": f"/protocol/{protocol_name}/{activity['variableName']}", + "class": "nav-link", + } + for activity in properties + ) + + if activity_name: + activities[0]["link"] = f"/protocol/{protocol_name}" + activities[0]["class"] = "nav-link" + for activity in activities: + if activity["name"] == activity_name: + activity["link"] = "#" + activity["class"] = "nav-link active" + + return activities + + +def update_format(items: dict[str, Any], form): + for i in items: + if form[i].data: + items[i]["is_answered"] = True + return items + + +def prep_activity_page(protocol_name: str, activity_name: str): + protocol_name = escape(protocol_name) + activity_name = escape(activity_name) + + protocol_content = get_protocol(protocol_name) + properties = protocol_content["ui"]["addProperties"] + is_about_activity = "" + for activity in properties: + if activity["variableName"] == activity_name: + is_about_activity = activity["isAbout"] + break + activity_file = protocol_url(protocol_name).parent / is_about_activity + + with open(activity_file) as f: + activity = json.load(f) + + activities = get_nav_bar_content(protocol_name, activity["prefLabel"][LANG]) + + items = get_items_for_activity(activity_file) + + return activities, activity, items + + +@lru_cache +def get_items_for_activity(activity_file): + with open(activity_file) as f: + activity = json.load(f) + + order = activity["ui"]["order"] + properties = activity["ui"]["addProperties"] + properties = sort_ui_properties(properties=properties, order=order) + + items = {} + for i, item in enumerate(properties): + + item_name = item["variableName"] + + item_data = get_item(activity_file.parent / item["isAbout"]) + + tmp = { + "visibility": False, + "required": False, + "isVis": item["isVis"], + "choices": get_choices(item_data), + "is_answered": False, + } + + tmp["question"] = f"{i + 1} - {item_data['question'][LANG]}" + tmp["input_type"] = item_data["ui"]["inputType"] + + tmp["description"] = ( + "
    Details" + "
      " + f"
    • item name: {item_data.get('description')}
    • " + "
    " + "
    " + ) + details = "" + if item_data.get("details"): + details = item_data["details"].get(LANG) + tmp["description"] = f"{details}
    {tmp['description']}" + + if item["isVis"] == 1: + tmp["visibility"] = True + + if item["requiredValue"]: + tmp["required"] = True + + if response_options := item_data.get("responseOptions"): + try: + unit = f"({response_options['unitOptions'][0]['prefLabel'][LANG]})" + except KeyError: + unit = "" + tmp["unit"] = unit + + tmp["min"] = response_options.get("minValue") + tmp["max"] = response_options.get("maxValue") + + try: + is_multiple = response_options.get("multipleChoice", False) + except KeyError: + is_multiple = False + tmp["is_multiple"] = is_multiple + + else: + tmp["unit"] = "" + tmp["min"] = None + tmp["max"] = None + tmp["is_multiple"] = None + + items[item_name] = tmp + + return items + + +def sort_ui_properties(properties: list[dict[str, Any]], order: list[str]) -> list[dict[str, Any]]: + tmp = [] + for i in order: + for prop in properties: + if prop["isAbout"] == i: + tmp.append(prop) + break + return tmp + + +def get_choices(item_data): + try: + choices = item_data["responseOptions"]["choices"] + if isinstance(choices, str): + # hack to load local data + if "https://raw.githubusercontent.com/ohbm/cobidas_schema/master/" in choices: + choices = choices.replace( + "https://raw.githubusercontent.com/ohbm/cobidas_schema/master/", + str(local_cobidas_schema()) + "/", + ) + with open(choices) as f: + choices = json.load(f) + else: + choices = query_choices(choices) + choices = choices["choices"] + choices = [(x["value"], x["name"][LANG]) for x in choices] + except KeyError: + choices = {} + return choices + + +def validate_participants_json(file: Path): + with open(file) as f: + participants_json = json.load(f) + return bool( + participants_json.get("participant_id") + and participants_json["participant_id"].get("Annotations") + ) + + +def validate_participants_tsv(file: Path): + df = pd.read_csv(file, sep="\t") + return "participant_id" in df.columns + + +def extract_values_participants(df, json_content): + + if isinstance(df, Path): + df = pd.read_csv(df, sep="\t") + + age_column = next( + ( + key + for key, value in json_content.items() + if value["Annotations"]["IsAbout"]["TermURL"] == "nb:Age" + ), + None, + ) + + return Found(df, age_column) + + +class Found: + + def __init__(self, df, age_column) -> None: + self.number_of_subjects = len(df) + self.subject_age_mean = df[age_column].mean() + self.subject_age_min = df[age_column].min() + self.subject_age_max = df[age_column].max() + self.proportion_male_subjects = None + + +def flash_errors(form, category="warning"): + """Flash all errors for a form.""" + for field, errors in form.errors.items(): + for error in errors: + flash(f"{getattr(form, field).label.text} - {error}", category) diff --git a/ui/ecobidas_ui/protocol.py b/ui/ecobidas_ui/protocols/views.py similarity index 58% rename from ui/ecobidas_ui/protocol.py rename to ui/ecobidas_ui/protocols/views.py index ed2ab69e..10b1063a 100644 --- a/ui/ecobidas_ui/protocol.py +++ b/ui/ecobidas_ui/protocols/views.py @@ -2,8 +2,8 @@ from pathlib import Path from typing import Any -from ecobidas_ui.forms import UploadBoldJsonForm, UploadParticipantsForm, generate_form -from ecobidas_ui.utils import ( +from ecobidas_ui.protocols.forms import UploadBoldJsonForm, UploadParticipantsForm, generate_form +from ecobidas_ui.protocols.utils import ( LANG, allowed_file, extract_values_participants, @@ -17,11 +17,11 @@ validate_participants_tsv, ) from flask import Blueprint, current_app, flash, redirect, render_template, request +from flask_wtf import FlaskForm from markupsafe import Markup -from rich import print from werkzeug.utils import secure_filename -bp = Blueprint("protocol", __name__, url_prefix="/protocol") +blueprint = Blueprint("protocol", __name__, url_prefix="/protocol") def update_visibility(items: dict[str, Any], form): @@ -36,8 +36,9 @@ def update_visibility(items: dict[str, Any], form): try: exec(string_to_eval) except Exception as exc: - print(f"Could not execute '{string_to_eval}' as a valid python statement.") - print(exc) + current_app.logger.error( + f"Could not execute '{string_to_eval}' as a valid python statement.\n{exc}" + ) # evaluate visibility for item, values in items.items(): @@ -47,14 +48,15 @@ def update_visibility(items: dict[str, Any], form): items[item]["visibility"] = eval(isVis) except Exception as exc: # actually log this - print(f"Could not evaluate '{eval(isVis)}' as a valid python expression.") - print(exc) + current_app.logger.error( + f"Could not evaluate '{eval(isVis)}' as a valid python expression.\n{exc}" + ) items[item]["visibility"] = False return items -@bp.route("/", methods=["GET", "POST"]) +@blueprint.route("/", methods=["GET", "POST"]) def protocol(protocol_name: str) -> str: protocol_content = get_protocol(protocol_name) @@ -75,21 +77,18 @@ def protocol(protocol_name: str) -> str: def show_export_button(protocol_name): - print(protocol_name) if protocol_name in ["neurovault", "cobidas"]: return True else: return False -@bp.get("//") +@blueprint.get("//") def activity_get(protocol_name, activity_name) -> str: activities, activity, items = prep_activity_page(protocol_name, activity_name) - upload_participants_form, upload_acquisition_form = generate_additional_forms( - protocol_name, activity_name - ) + upload_participants_form, extra_form = generate_extra_forms(protocol_name, activity_name) form = generate_form(items=items, prefix=activity_name) @@ -106,33 +105,36 @@ def activity_get(protocol_name, activity_name) -> str: nb_items=nb_items, completed_items=completed_items, upload_participants_form=upload_participants_form, - upload_acquisition_form=upload_acquisition_form, + upload_acquisition_form=extra_form, show_export_button=show_export_button(protocol_name), ) -@bp.post("//") +@blueprint.post("//") def activity_post(protocol_name, activity_name) -> str: + current_app.logger.info(f"{protocol_name}-{activity_name}") activities, activity, items = prep_activity_page(protocol_name, activity_name) - upload_participants_form, upload_acquisition_form = generate_additional_forms( - protocol_name, activity_name - ) + upload_participants_form, extra_form = generate_extra_forms(protocol_name, activity_name) form = generate_form(items=items, prefix=activity_name) if ( upload_participants_form and upload_participants_form.is_submitted() - and upload_participants_form.participants.data + and upload_participants_form.validate_on_submit() ): if message := validate_participants_form(upload_participants_form): - flash(message) + flash(message, category="warning") return redirect(request.url) - for file in upload_participants_form.participants.data: + data = upload_participants_form.participants.data + if not isinstance(data, list): + data = [data] + + for file in data: if allowed_file(file.filename): filename = secure_filename(file.filename) file.save(Path(current_app.config["UPLOAD_FOLDER"]) / filename) @@ -142,7 +144,8 @@ def activity_post(protocol_name, activity_name) -> str: flash( Markup( "

    The 'participants.tsv' does not seem to be valid: 'participant_id' column is missing.

    " - ) + ), + category="warning", ) return redirect(request.url) @@ -154,66 +157,55 @@ def activity_post(protocol_name, activity_name) -> str: "Annotate your data with " "the neurobagel online annotation tool

    " - ) + ), + category="warning", ) return redirect(request.url) - form.number_of_subjects.data = extract_values_participants( - tsv_file, value="number_of_subjects" + form, items, fields = process_participants_form( + form, activity_name, items, tsv_file, json_file ) - form.subject_age_mean.data = extract_values_participants(tsv_file, value="subject_age_mean") - form.subject_age_min.data = extract_values_participants(tsv_file, value="subject_age_min") - form.subject_age_max.data = extract_values_participants(tsv_file, value="subject_age_max") - # TODO - form.proportion_male_subjects.data = 0.5 + if not fields: + message = "No field could be updated." + flash(message, category="warning") + return redirect(request.url) - items = update_visibility(items, form) - items = update_format(items, form) - form = generate_form(items, prefix=activity_name) + message = f"The following fields were updated: {fields}" + flash(message, category="success") - form.number_of_subjects.data = extract_values_participants( - tsv_file, target="number_of_subjects" - ) - form.subject_age_mean.data = extract_values_participants( - tsv_file, target="subject_age_mean" - ) - form.subject_age_min.data = extract_values_participants(tsv_file, vtarget="subject_age_min") - form.subject_age_max.data = extract_values_participants(tsv_file, target="subject_age_max") - form.proportion_male_subjects.data = 0.5 + if extra_form and extra_form.is_submitted() and extra_form.validate_on_submit(): - if upload_acquisition_form.validate_on_submit(): + data = extra_form.bold_json.data + if not isinstance(data, list): + data = [data] - f = upload_acquisition_form.bold_json.data - filename = secure_filename(f.filename) + uploaded_files = [] + for file in data: + if allowed_file(file.filename): + filename = secure_filename(file.filename) + file.save(Path(current_app.config["UPLOAD_FOLDER"]) / filename) + uploaded_files.append(filename) + else: + message = "No '_bold.json' was uploaded." + flash(message, category="warning") + return redirect(request.url) + + form, items, fields = process_acquisition_form( + form, activity_name, items, filename=Path(current_app.instance_path) / uploaded_files[0] + ) - if not allowed_file(filename): - message = "No '_bold.json' was uploaded." - flash(message) + if not fields: + message = "No field could be updated." + flash(message, category="warning") return redirect(request.url) - f.save(Path(current_app.instance_path) / filename) - - with open(Path(current_app.instance_path) / filename) as f: - bold_json = json.load(f) - - for key in bold_json: - if key in form: - form[key].data = bold_json[key] - - items = update_visibility(items, form) - items = update_format(items, form) - form = generate_form(items, prefix=activity_name) - - for key in bold_json: - if key in form: - form[key].data = bold_json[key] + message = f"The following fields were updated: {fields}" + flash(message, category="success") elif form.is_submitted(): - items = update_visibility(items, form) - items = update_format(items, form) - form = generate_form(items, prefix=activity_name) + form, items = update_items_and_forms(form, items, activity_name) completed_items = sum(bool(i["is_answered"]) for i in items.values()) nb_items = sum(bool(i["visibility"]) for i in items.values()) @@ -228,36 +220,36 @@ def activity_post(protocol_name, activity_name) -> str: nb_items=nb_items, completed_items=completed_items, upload_participants_form=upload_participants_form, - upload_acquisition_form=upload_acquisition_form, + upload_acquisition_form=extra_form, show_export_button=show_export_button(protocol_name), ) def validate_participants_form(upload_participants_form): nb_files_uploaded = len(upload_participants_form.participants.data) + if nb_files_uploaded != 2: + message = f"2 files must be uploaded. Received: {nb_files_uploaded}" + return message + participants_json_uploaded = any( file.filename == "participants.json" for file in upload_participants_form.participants.data ) + if not participants_json_uploaded: + message = "No 'participants.json' was uploaded." + return message + participants_tsv_uploaded = any( file.filename == "participants.tsv" for file in upload_participants_form.participants.data ) - - if nb_files_uploaded != 2: - message = "2 files must be uploaded." - if not participants_json_uploaded: - message = "No 'participants.json' was uploaded." if not participants_tsv_uploaded: message = "No 'participants.tsv' was uploaded." - - if nb_files_uploaded != 2 or not participants_json_uploaded or not participants_tsv_uploaded: - return message else: return "" -def generate_additional_forms(protocol_name, activity_name): +def generate_extra_forms(protocol_name, activity_name) -> tuple[FlaskForm | None]: upload_participants_form = None upload_acquisition_form = None @@ -271,3 +263,52 @@ def generate_additional_forms(protocol_name, activity_name): upload_acquisition_form = UploadBoldJsonForm(prefix="mri_acquisition-") return upload_participants_form, upload_acquisition_form + + +def process_acquisition_form(form: FlaskForm, activity_name: str, items, filename): + """Use uploaded bold.json to prefill the form.""" + with open(filename) as f: + bold_json = json.load(f) + + found = JsonMeta(bold_json) + + fields = [] + for key in found.__dir__(): + if not getattr(found, key) or key not in form: + continue + fields.append(key) + + form, items = update_items_and_forms(form, items, activity_name, obj=found) + + return form, items, fields + + +class JsonMeta: + + def __init__(self, json_content) -> None: + + for key in json_content: + self.__setattr__(key, json_content[key]) + + +def process_participants_form(form: FlaskForm, activity_name: str, items, tsv_file, json_file): + json_content = json.load(open(json_file)) + + found = extract_values_participants(tsv_file, json_content=json_content) + + fields = [] + for key in found.__dir__(): + if not getattr(found, key) or key not in form: + continue + fields.append(key) + + form, items = update_items_and_forms(form, items, activity_name, obj=found) + + return form, items, fields + + +def update_items_and_forms(form: FlaskForm, items, activity_name: str, obj=None): + items = update_visibility(items, form) + items = update_format(items, form) + form = generate_form(items, prefix=activity_name, obj=obj) + return form, items diff --git a/ui/ecobidas_ui/settings.py b/ui/ecobidas_ui/settings.py index 42e8cd6d..40539c48 100644 --- a/ui/ecobidas_ui/settings.py +++ b/ui/ecobidas_ui/settings.py @@ -25,4 +25,4 @@ SECRET_KEY = env.str("SECRET_KEY") -CACHE_TYPE = "flask_caching.backends.SimpleCache" # Can be "MemcachedCache", "RedisCache", etc. +# CACHE_TYPE = "flask_caching.backends.SimpleCache" # Can be "MemcachedCache", "RedisCache", etc. diff --git a/ui/ecobidas_ui/static/images/BIDS_logo_black.svg b/ui/ecobidas_ui/static/images/BIDS_logo_black.svg new file mode 100644 index 00000000..9f1718f7 --- /dev/null +++ b/ui/ecobidas_ui/static/images/BIDS_logo_black.svg @@ -0,0 +1 @@ +Ресурс 2 diff --git a/ui/ecobidas_ui/templates/extra_forms.html b/ui/ecobidas_ui/templates/extra_forms.html new file mode 100644 index 00000000..e3771097 --- /dev/null +++ b/ui/ecobidas_ui/templates/extra_forms.html @@ -0,0 +1,51 @@ +
    +
    + {% if upload_participants_form %} +
    +
    + BIDS +
    +

    + To fill in this form faster you can upload a + participants.tsv file formatted according to the + BIDS specification + along with a participants.json file containing column + annotations generated by + the neurobagel annotation tool. +

    + {{ render_form(upload_participants_form) }} +
    + {% endif %} {% if upload_acquisition_form %} +
    +
    + BIDS +
    +

    + To fill in this form faster you can upload a + *_bold.json file formatted according to the + BIDS specification + containing the metadata for your fMRI runs. +

    + {{ render_form(upload_acquisition_form) }} +
    + {% endif %} +
    +
    diff --git a/ui/ecobidas_ui/templates/layout/base.html b/ui/ecobidas_ui/templates/layout/base.html index 520a01b2..239ba9bf 100644 --- a/ui/ecobidas_ui/templates/layout/base.html +++ b/ui/ecobidas_ui/templates/layout/base.html @@ -6,8 +6,10 @@ {% block title %} {% endblock %} - - + {{ bootstrap.load_css() }} {% assets "css" %} @@ -34,15 +36,15 @@

    🚧 This website is under construction !!!!!! 🚧

- {% with messages = get_flashed_messages() %} + {% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} - {% for message in messages %} + {% for category, message in messages %}
diff --git a/ui/ecobidas_ui/utils.py b/ui/ecobidas_ui/utils.py index 75898d7f..d527089b 100644 --- a/ui/ecobidas_ui/utils.py +++ b/ui/ecobidas_ui/utils.py @@ -1,265 +1 @@ -# functions to be used by the routes -import json -from functools import lru_cache -from pathlib import Path -from typing import Any - -import pandas as pd -import requests -from flask import flash -from markupsafe import escape -from rich import print - LANG: str = "en" - -ALLOWED_EXTENSIONS = {".tsv", ".json"} - - -def allowed_file(filename): - return Path(filename).suffix in ALLOWED_EXTENSIONS - - -def protocol_url(protocol_name: Path) -> Path: - return ( - Path(__file__).parents[2] - / "cobidas_schema" - / "schemas" - / protocol_name - / "protocols" - / f"{protocol_name}_schema.jsonld" - ) - - -@lru_cache -def get_protocol(protocol_name: str) -> dict[str, Any]: - file = protocol_url(protocol_name) - with open(file) as f: - content = json.load(f) - return content - - -def get_item(file: Path) -> dict[str, Any]: - with open(file) as f: - content = json.load(f) - return content - - -@lru_cache -def query_choices(url: str) -> None | dict[str, Any]: - try: - data = requests.get(url).json() - except Exception as exc: - print(exc) - data = None - return data - - -@lru_cache -def get_landing_page(url: Path) -> None | dict[str, Any]: - try: - if str(url).startswith("https:"): - data = requests.get(url) - else: - data = Path(url).read_text() - except Exception as exc: - print(exc) - data = None - return data - - -def get_nav_bar_content( - protocol_name: str, activity_name: str | None = None -) -> list[dict[str, str]]: - protocol_content = get_protocol(protocol_name) - - order = protocol_content["ui"]["order"] - properties = protocol_content["ui"]["addProperties"] - properties = sort_ui_properties(properties=properties, order=order) - - activities = [ - {"name": "Start", "link": "#", "class": "nav-link active"}, - ] - activities.extend( - { - "name": activity["prefLabel"][LANG], - "link": f"/protocol/{protocol_name}/{activity['variableName']}", - "class": "nav-link", - } - for activity in properties - ) - - if activity_name: - activities[0]["link"] = f"/protocol/{protocol_name}" - activities[0]["class"] = "nav-link" - for activity in activities: - if activity["name"] == activity_name: - activity["link"] = "#" - activity["class"] = "nav-link active" - - return activities - - -def update_format(items: dict[str, Any], form): - for i in items: - if form[i].data: - items[i]["is_answered"] = True - return items - - -def prep_activity_page(protocol_name, activity_name): - protocol_name = escape(protocol_name) - activity_name = escape(activity_name) - - protocol_content = get_protocol(protocol_name) - properties = protocol_content["ui"]["addProperties"] - for activity in properties: - if activity["variableName"] == activity_name: - is_about_activity = activity["isAbout"] - break - activity_file = protocol_url(protocol_name).parent / is_about_activity - - with open(activity_file) as f: - activity = json.load(f) - - activities = get_nav_bar_content(protocol_name, activity["prefLabel"][LANG]) - - items = get_items_for_activity(activity_file) - - return activities, activity, items - - -@lru_cache -def get_items_for_activity(activity_file): - with open(activity_file) as f: - activity = json.load(f) - - order = activity["ui"]["order"] - properties = activity["ui"]["addProperties"] - properties = sort_ui_properties(properties=properties, order=order) - - items = {} - for i, item in enumerate(properties): - - item_name = item["variableName"] - - item_data = get_item(activity_file.parent / item["isAbout"]) - - tmp = { - "visibility": False, - "required": False, - "isVis": item["isVis"], - "choices": get_choices(item_data), - "is_answered": False, - } - - tmp["question"] = f"{i + 1} - {item_data['question'][LANG]}" - tmp["input_type"] = item_data["ui"]["inputType"] - - tmp["description"] = ( - "
Details" - "
    " - f"
  • item name: {item_data.get('description')}
  • " - "
" - "
" - ) - details = "" - if item_data.get("details"): - details = item_data["details"].get(LANG) - tmp["description"] = f"{details}
{tmp['description']}" - - if item["isVis"] == 1: - tmp["visibility"] = True - - if item["requiredValue"]: - tmp["required"] = True - - if response_options := item_data.get("responseOptions"): - try: - unit = f"({response_options['unitOptions'][0]['prefLabel'][LANG]})" - except KeyError: - unit = "" - tmp["unit"] = unit - - tmp["min"] = response_options.get("minValue") - tmp["max"] = response_options.get("maxValue") - - try: - is_multiple = response_options.get("multipleChoice", False) - except KeyError: - is_multiple = False - tmp["is_multiple"] = is_multiple - - else: - tmp["unit"] = "" - tmp["min"] = None - tmp["max"] = None - tmp["is_multiple"] = None - - items[item_name] = tmp - - return items - - -def sort_ui_properties(properties: list[dict[str, Any]], order: list[str]) -> list[dict[str, Any]]: - tmp = [] - for i in order: - for prop in properties: - if prop["isAbout"] == i: - tmp.append(prop) - break - return tmp - - -def get_choices(item_data): - try: - choices = item_data["responseOptions"]["choices"] - if isinstance(choices, str): - choices = query_choices(choices)["choices"] - choices = [(x["value"], x["name"][LANG]) for x in choices] - except KeyError: - choices = {} - return choices - - -def validate_participants_json(file: Path): - with open(file) as f: - participants_json = json.load(f) - return bool( - participants_json.get("participant_id") - and participants_json["participant_id"].get("Annotations") - ) - - -def validate_participants_tsv(file: Path): - df = pd.read_csv(file, sep="\t") - return "participant_id" in df.columns - - -def extract_values_participants(df, json_content, target): - if isinstance(df, Path): - df = pd.read_csv(df, sep="\t") - - if target == "number_of_subjects": - return len(df) - - column = next( - ( - key - for key, value in json_content.items() - if value["Annotations"]["IsAbout"]["TermURL"] == "nb:Age" - ), - None, - ) - if target == "subject_age_mean": - return df[column].mean() - if target == "subject_age_min": - return df[column].min() - if target == "subject_age_max": - return df[column].max() - - -def flash_errors(form, category="warning"): - """Flash all errors for a form.""" - for field, errors in form.errors.items(): - for error in errors: - flash(f"{getattr(form, field).label.text} - {error}", category) diff --git a/ui/tests/__init__.py b/ui/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ui/tests/conftest.py b/ui/tests/conftest.py deleted file mode 100644 index 94bece32..00000000 --- a/ui/tests/conftest.py +++ /dev/null @@ -1,41 +0,0 @@ -import os -import tempfile -from pathlib import Path - -import pytest -from ecobidas_ui import create_app -from ecobidas_ui.db import get_db, init_db - -with open(Path(__file__).parent / "data.sql", "rb") as f: - _data_sql = f.read().decode("utf8") - - -@pytest.fixture -def app(): - db_fd, db_path = tempfile.mkstemp() - - app = create_app( - { - "TESTING": True, - "DATABASE": db_path, - } - ) - - with app.app_context(): - init_db() - get_db().executescript(_data_sql) - - yield app - - os.close(db_fd) - os.unlink(db_path) - - -@pytest.fixture -def client(app): - return app.test_client() - - -@pytest.fixture -def runner(app): - return app.test_cli_runner() diff --git a/ui/tests/data.sql b/ui/tests/data.sql deleted file mode 100644 index 9b680065..00000000 --- a/ui/tests/data.sql +++ /dev/null @@ -1,8 +0,0 @@ -INSERT INTO user (username, password) -VALUES - ('test', 'pbkdf2:sha256:50000$TCI4GzcX$0de171a4f4dac32e3364c7ddc7c14f3e2fa61f2d17574483f7ffbb431b4acb2f'), - ('other', 'pbkdf2:sha256:50000$kJPKsz6N$d2d4784f1b030a9761f5ccaeeaca413f27f2ecb76d6168407af962ddce849f79'); - -INSERT INTO post (title, body, author_id, created) -VALUES - ('test title', 'test' || x'0a' || 'body', 1, '2018-01-01 00:00:00'); diff --git a/ui/tests/protocols/__init__.py b/ui/tests/protocols/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ui/tests/test_utils.py b/ui/tests/protocols/test_utils.py similarity index 58% rename from ui/tests/test_utils.py rename to ui/tests/protocols/test_utils.py index 8dd27ef8..f8f4e10b 100644 --- a/ui/tests/test_utils.py +++ b/ui/tests/protocols/test_utils.py @@ -1,5 +1,31 @@ import pandas as pd -from ecobidas_ui.utils import extract_values_participants +from ecobidas_ui.protocols.utils import ( + extract_values_participants, + get_nav_bar_content, + get_protocol, + prep_activity_page, + protocol_url, +) + + +def test_protocol_url(): + assert protocol_url("neurovault").suffix == ".jsonld" + assert protocol_url("neurovault").stem == "neurovault_schema" + + +def test_get_protocol(): + protocol_content = get_protocol("neurovault") + assert protocol_content["@id"] == "neurovault_schema.jsonld" + + +def test_get_nav_bar_content(): + nav_bar = get_nav_bar_content("neurovault", "Participants") + assert len(nav_bar) == 9 + assert nav_bar[2]["link"] == "#" + + +def test_prep_activity_page(): + activities, activity, items = prep_activity_page("neurovault", "participants") def test_extract_values_participants(): @@ -54,7 +80,4 @@ def test_extract_values_participants(): } } - assert extract_values_participants(tsv, json_content, target="number_of_subjects") == 16 - assert extract_values_participants(tsv, json_content, target="subject_age_min") == 19 - assert extract_values_participants(tsv, json_content, target="subject_age_max") == 30 - # assert mean==23.5625 + assert extract_values_participants(tsv, json_content).subject_age_min == 19 From 3519a0953d8f79fcf749bd701de4cdd2bc0ac2b0 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Mon, 27 May 2024 23:21:28 +0200 Subject: [PATCH 21/31] refactor --- ui/ecobidas_ui/app.py | 5 ++- ui/ecobidas_ui/protocols/forms.py | 19 ++++++++++ ui/ecobidas_ui/protocols/utils.py | 24 +++--------- ui/ecobidas_ui/protocols/views.py | 57 ++++++++++++++++------------ ui/ecobidas_ui/public/views.py | 3 +- ui/tests/conftest.py | 29 +++++++++++++++ ui/tests/protocols/__init__.py | 0 ui/tests/protocols/conftest.py | 60 ++++++++++++++++++++++++++++++ ui/tests/protocols/test_forms.py | 12 ++++++ ui/tests/protocols/test_utils.py | 62 +++---------------------------- ui/tests/test_app.py | 9 +++++ 11 files changed, 179 insertions(+), 101 deletions(-) create mode 100644 ui/tests/conftest.py delete mode 100644 ui/tests/protocols/__init__.py create mode 100644 ui/tests/protocols/conftest.py create mode 100644 ui/tests/protocols/test_forms.py create mode 100644 ui/tests/test_app.py diff --git a/ui/ecobidas_ui/app.py b/ui/ecobidas_ui/app.py index fb08aaf5..cb5ed344 100644 --- a/ui/ecobidas_ui/app.py +++ b/ui/ecobidas_ui/app.py @@ -1,5 +1,6 @@ import logging import sys +from pathlib import Path from ecobidas_ui import auth, db, protocols, public from ecobidas_ui._version import version @@ -13,7 +14,9 @@ def create_app(config_object="ecobidas_ui.settings"): # create and configure the app - app = Flask(__name__, instance_relative_config=True) + app = Flask( + __name__, instance_relative_config=True, instance_path=Path(__file__).parent / "instance" + ) app.config.from_object(config_object) diff --git a/ui/ecobidas_ui/protocols/forms.py b/ui/ecobidas_ui/protocols/forms.py index 60b3d2eb..f1077c8f 100644 --- a/ui/ecobidas_ui/protocols/forms.py +++ b/ui/ecobidas_ui/protocols/forms.py @@ -1,3 +1,7 @@ +import json +from pathlib import Path + +import pandas as pd from flask_wtf import FlaskForm from flask_wtf.file import FileAllowed, FileField, FileRequired, MultipleFileField from markupsafe import Markup @@ -27,6 +31,21 @@ class UploadParticipantsForm(FlaskForm): submit = SubmitField("Upload") +def validate_participants_json(participants_json: Path | str | dict): + if not isinstance(participants_json, dict): + with open(Path(participants_json)) as f: + participants_json = json.load(f) + return bool( + participants_json.get("participant_id") + and participants_json["participant_id"].get("Annotations") + ) + + +def validate_participants_tsv(file: Path | pd.DataFrame): + df = pd.read_csv(file, sep="\t") + return "participant_id" in df.columns + + class UploadBoldJsonForm(FlaskForm): bold_json = FileField( "Upload bold.json", diff --git a/ui/ecobidas_ui/protocols/utils.py b/ui/ecobidas_ui/protocols/utils.py index fae13cc3..a103e74d 100644 --- a/ui/ecobidas_ui/protocols/utils.py +++ b/ui/ecobidas_ui/protocols/utils.py @@ -101,9 +101,10 @@ def get_nav_bar_content( return activities -def update_format(items: dict[str, Any], form): +def update_format(items: dict[str, Any], form_data): + for i in items: - if form[i].data: + if form_data[i]: items[i]["is_answered"] = True return items @@ -234,20 +235,6 @@ def get_choices(item_data): return choices -def validate_participants_json(file: Path): - with open(file) as f: - participants_json = json.load(f) - return bool( - participants_json.get("participant_id") - and participants_json["participant_id"].get("Annotations") - ) - - -def validate_participants_tsv(file: Path): - df = pd.read_csv(file, sep="\t") - return "participant_id" in df.columns - - def extract_values_participants(df, json_content): if isinstance(df, Path): @@ -268,10 +255,11 @@ def extract_values_participants(df, json_content): class Found: def __init__(self, df, age_column) -> None: - self.number_of_subjects = len(df) - self.subject_age_mean = df[age_column].mean() + self.number_of_subjects = int(len(df)) + self.subject_age_mean = float(df[age_column].mean()) self.subject_age_min = df[age_column].min() self.subject_age_max = df[age_column].max() + # TODO Actually compute the percent male self.proportion_male_subjects = None diff --git a/ui/ecobidas_ui/protocols/views.py b/ui/ecobidas_ui/protocols/views.py index 10b1063a..2692c184 100644 --- a/ui/ecobidas_ui/protocols/views.py +++ b/ui/ecobidas_ui/protocols/views.py @@ -2,7 +2,13 @@ from pathlib import Path from typing import Any -from ecobidas_ui.protocols.forms import UploadBoldJsonForm, UploadParticipantsForm, generate_form +from ecobidas_ui.protocols.forms import ( + UploadBoldJsonForm, + UploadParticipantsForm, + generate_form, + validate_participants_json, + validate_participants_tsv, +) from ecobidas_ui.protocols.utils import ( LANG, allowed_file, @@ -13,8 +19,6 @@ prep_activity_page, protocol_url, update_format, - validate_participants_json, - validate_participants_tsv, ) from flask import Blueprint, current_app, flash, redirect, render_template, request from flask_wtf import FlaskForm @@ -24,10 +28,10 @@ blueprint = Blueprint("protocol", __name__, url_prefix="/protocol") -def update_visibility(items: dict[str, Any], form): +def update_visibility(items: dict[str, Any], form_data): """Evaluate visibility condition of each item and make item visible if necessary.""" # assign response to a variable with same name as the item it comees from - for key, value in form.data.items(): + for key, value in form_data.items(): if key not in items: continue if not value: @@ -126,14 +130,14 @@ def activity_post(protocol_name, activity_name) -> str: and upload_participants_form.validate_on_submit() ): - if message := validate_participants_form(upload_participants_form): - flash(message, category="warning") - return redirect(request.url) - data = upload_participants_form.participants.data if not isinstance(data, list): data = [data] + if message := validate_participants_form(data): + flash(message, category="warning") + return redirect(request.url) + for file in data: if allowed_file(file.filename): filename = secure_filename(file.filename) @@ -162,6 +166,7 @@ def activity_post(protocol_name, activity_name) -> str: ) return redirect(request.url) + # TODO values in fields for participant data are not updated. form, items, fields = process_participants_form( form, activity_name, items, tsv_file, json_file ) @@ -192,7 +197,10 @@ def activity_post(protocol_name, activity_name) -> str: return redirect(request.url) form, items, fields = process_acquisition_form( - form, activity_name, items, filename=Path(current_app.instance_path) / uploaded_files[0] + form, + activity_name, + items, + filename=Path(current_app.config["UPLOAD_FOLDER"]) / uploaded_files[0], ) if not fields: @@ -205,7 +213,7 @@ def activity_post(protocol_name, activity_name) -> str: elif form.is_submitted(): - form, items = update_items_and_forms(form, items, activity_name) + form, items = update_items_and_forms(form.data, items, activity_name) completed_items = sum(bool(i["is_answered"]) for i in items.values()) nb_items = sum(bool(i["visibility"]) for i in items.values()) @@ -225,22 +233,18 @@ def activity_post(protocol_name, activity_name) -> str: ) -def validate_participants_form(upload_participants_form): - nb_files_uploaded = len(upload_participants_form.participants.data) +def validate_participants_form(data): + nb_files_uploaded = len(data) if nb_files_uploaded != 2: message = f"2 files must be uploaded. Received: {nb_files_uploaded}" return message - participants_json_uploaded = any( - file.filename == "participants.json" for file in upload_participants_form.participants.data - ) + participants_json_uploaded = any(file.filename == "participants.json" for file in data) if not participants_json_uploaded: message = "No 'participants.json' was uploaded." return message - participants_tsv_uploaded = any( - file.filename == "participants.tsv" for file in upload_participants_form.participants.data - ) + participants_tsv_uploaded = any(file.filename == "participants.tsv" for file in data) if not participants_tsv_uploaded: message = "No 'participants.tsv' was uploaded." return message @@ -278,7 +282,7 @@ def process_acquisition_form(form: FlaskForm, activity_name: str, items, filenam continue fields.append(key) - form, items = update_items_and_forms(form, items, activity_name, obj=found) + form, items = update_items_and_forms(form.data, items, activity_name, obj=found) return form, items, fields @@ -302,13 +306,18 @@ def process_participants_form(form: FlaskForm, activity_name: str, items, tsv_fi continue fields.append(key) - form, items = update_items_and_forms(form, items, activity_name, obj=found) + form, items = update_items_and_forms(form.data, items, activity_name, obj=found) return form, items, fields -def update_items_and_forms(form: FlaskForm, items, activity_name: str, obj=None): - items = update_visibility(items, form) - items = update_format(items, form) +def update_items_and_forms(form_data: dict, items, activity_name: str, obj=None): + if obj is not None: + for key in obj.__dir__(): + if key in form_data: + form_data[key] = getattr(obj, key) + + items = update_visibility(items, form_data) + items = update_format(items, form_data) form = generate_form(items, prefix=activity_name, obj=obj) return form, items diff --git a/ui/ecobidas_ui/public/views.py b/ui/ecobidas_ui/public/views.py index 4d874025..88829745 100644 --- a/ui/ecobidas_ui/public/views.py +++ b/ui/ecobidas_ui/public/views.py @@ -3,7 +3,7 @@ import json from ecobidas_ui.settings import STATIC_FOLDER -from flask import Blueprint, current_app, render_template +from flask import Blueprint, render_template blueprint = Blueprint("public", __name__, static_folder="../static") @@ -11,7 +11,6 @@ @blueprint.route("/", methods=["GET", "POST"]) def home(): """Home page.""" - current_app.logger.info("Hello from the home page!") return render_template("public/index.html") diff --git a/ui/tests/conftest.py b/ui/tests/conftest.py new file mode 100644 index 00000000..44452705 --- /dev/null +++ b/ui/tests/conftest.py @@ -0,0 +1,29 @@ +import pytest +from ecobidas_ui.app import create_app + + +@pytest.fixture() +def app(): + app = create_app() + app.config.update( + { + "TESTING": True, + } + ) + + # other setup can go here + + yield app + + # clean up / reset resources here + + +@pytest.fixture() +def client(app): + return app.test_client() + + +@pytest.fixture +def app_context(app): + with app.app_context(): + yield diff --git a/ui/tests/protocols/__init__.py b/ui/tests/protocols/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/ui/tests/protocols/conftest.py b/ui/tests/protocols/conftest.py new file mode 100644 index 00000000..2da42613 --- /dev/null +++ b/ui/tests/protocols/conftest.py @@ -0,0 +1,60 @@ +import pandas as pd +import pytest + + +@pytest.fixture +def participants_json(): + return { + "participant_id": {"Annotations": {"IsAbout": {"TermURL": "", "Label": ""}}}, + "age": { + "Annotations": { + "IsAbout": {"TermURL": "nb:Age", "Label": ""}, + "Transformation": {"TermURL": "nb:FromInt", "Label": "integer data"}, + "MissingValues": ["", "n/a", " "], + } + }, + } + + +@pytest.fixture +def participants_df(): + return pd.DataFrame( + { + "age": [ + 26, + 24, + 27, + 20, + 22, + 26, + 24, + 21, + 26, + 21, + 24, + 22, + 21, + 30, + 24, + 19, + ], + "sex": [ + "F", + "M", + "F", + "F", + "M,", + "F", + "M", + "M", + "M", + "F", + "F", + "F", + "F", + "F", + "F", + "M", + ], + } + ) diff --git a/ui/tests/protocols/test_forms.py b/ui/tests/protocols/test_forms.py new file mode 100644 index 00000000..1884ace7 --- /dev/null +++ b/ui/tests/protocols/test_forms.py @@ -0,0 +1,12 @@ +import pandas as pd +from ecobidas_ui.protocols.forms import validate_participants_json, validate_participants_tsv + + +def test_validate_participants_tsv(participants_df): + assert validate_participants_tsv(participants_df) + assert not validate_participants_tsv(pd.DataFrame()) + + +def test_validate_participants_json(participants_json): + assert validate_participants_json(participants_json) + assert not validate_participants_json({}) diff --git a/ui/tests/protocols/test_utils.py b/ui/tests/protocols/test_utils.py index f8f4e10b..53736209 100644 --- a/ui/tests/protocols/test_utils.py +++ b/ui/tests/protocols/test_utils.py @@ -1,4 +1,4 @@ -import pandas as pd +import pytest from ecobidas_ui.protocols.utils import ( extract_values_participants, get_nav_bar_content, @@ -24,60 +24,10 @@ def test_get_nav_bar_content(): assert nav_bar[2]["link"] == "#" -def test_prep_activity_page(): - activities, activity, items = prep_activity_page("neurovault", "participants") +@pytest.mark.parametrize("activity_name", ["participants", "mri_acquisition"]) +def test_prep_activity_page(activity_name): + activities, activity, items = prep_activity_page("neurovault", activity_name) -def test_extract_values_participants(): - tsv = pd.DataFrame( - { - "age": [ - 26, - 24, - 27, - 20, - 22, - 26, - 24, - 21, - 26, - 21, - 24, - 22, - 21, - 30, - 24, - 19, - ], - "sex": [ - "F", - "M", - "F", - "F", - "M,", - "F", - "M", - "M", - "M", - "F", - "F", - "F", - "F", - "F", - "F", - "M", - ], - } - ) - - json_content = { - "age": { - "Annotations": { - "IsAbout": {"TermURL": "nb:Age", "Label": ""}, - "Transformation": {"TermURL": "nb:FromInt", "Label": "integer data"}, - "MissingValues": ["", "n/a", " "], - } - } - } - - assert extract_values_participants(tsv, json_content).subject_age_min == 19 +def test_extract_values_participants(participants_df, participants_json): + assert extract_values_participants(participants_df, participants_json).subject_age_min == 19 diff --git a/ui/tests/test_app.py b/ui/tests/test_app.py new file mode 100644 index 00000000..7cc2db04 --- /dev/null +++ b/ui/tests/test_app.py @@ -0,0 +1,9 @@ +def test_request_example(client): + response = client.get("/") + assert b"eCOBIDAS" in response.data + response = client.get("/faq/") + assert b"FAQ" in response.data + response = client.get("/about/") + assert b"about" in response.data + response = client.get("/protocols/neurovault/mri_acquisition") + assert b"neurovault" in response.data From 07d6ba39c358eb5377dfa4590fbed6fcc5b0eff8 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Tue, 28 May 2024 01:25:54 +0200 Subject: [PATCH 22/31] generate and download methods --- .pre-commit-config.yaml | 4 +++ .../mri/preprocessing/brain-extraction.md | 7 ----- .../mri/preprocessing/coregistration.md | 8 ----- .../mri/preprocessing/intensity-norm.md | 11 ------- .../mri/preprocessing/operations-performed.md | 5 ---- .../preprocessing/quality-control-reports.md | 6 ---- .../mri/preprocessing/segmentation.md | 7 ----- .../preprocessing/slice-timing-correction.md | 8 ----- .../mri/preprocessing/smoothing.md | 13 -------- .../boilerplate/mri/preprocessing/software.md | 6 ---- .../mri/preprocessing/t1-stabilization.md | 6 ---- .../mri/preprocessing/volume-censoring.md | 10 ------- ui/ecobidas_ui/app.py | 10 ++----- ui/ecobidas_ui/generate/__init__.py | 3 ++ ui/ecobidas_ui/generate/views.py | 30 +++++++++++++++++++ ui/ecobidas_ui/protocols/views.py | 10 +++++-- ui/ecobidas_ui/templates/405.html | 17 +++++++++++ .../templates/generate/device_info.html | 3 ++ ui/ecobidas_ui/templates/generate/index.html | 22 ++++++++++++++ .../templates/generate/institution.html | 2 ++ .../generate/meeg/device_channel_count.tmp | 1 + .../generate/meeg/device_channels.tmp | 2 ++ .../generate/meeg/device_freq_config.tmp | 1 + .../generate/meeg/dewar_positioning.tmp | 1 + .../generate/meeg/eeg_channel_placement.tmp | 1 + .../templates/generate/meeg/eeg_report.tmp | 13 ++++++++ .../generate/meeg/head_coil_frequency.tmp | 1 + .../generate/meeg/head_localisation.tmp | 1 + .../templates/generate/meeg/meg_report.tmp | 21 +++++++++++++ .../generate/meeg/recording_properties.tmp | 1 + .../generate/mri/acquisition/info.html | 8 +++++ .../acquisition/inplane_spatial_encoding.html | 6 ++++ .../mri/acquisition/rf_contrasts.html | 1 + .../mri/acquisition/scanner_hardware.html | 10 +++++++ .../generate/mri/acquisition/sequence.html | 4 +++ .../mri/acquisition/slice_acceleration.html | 2 ++ .../mri/acquisition/timing_parameters.html | 2 ++ .../mri/preprocessing/brain-extraction.html | 3 ++ .../mri/preprocessing/coregistration.html | 5 ++++ .../mri/preprocessing/intensity-norm.html | 5 ++++ .../preprocessing/operations-performed.html | 1 + .../quality-control-reports.html | 2 ++ .../mri/preprocessing/segmentation.html | 3 ++ .../slice-timing-correction.html | 4 +++ .../generate/mri/preprocessing/smoothing.html | 3 ++ .../generate/mri/preprocessing/software.html | 1 + .../mri/preprocessing/t1-stabilization.html | 2 ++ .../mri/preprocessing/volume-censoring.html | 5 ++++ ui/ecobidas_ui/templates/generate/report.html | 17 +++++++++++ .../templates/generate/task_name.html | 1 + ui/ecobidas_ui/templates/layout/base.html | 4 +-- ui/ecobidas_ui/templates/side_nav.html | 2 +- ui/pyproject.toml | 3 +- 53 files changed, 224 insertions(+), 101 deletions(-) delete mode 100644 inputs/boilerplate/mri/preprocessing/brain-extraction.md delete mode 100644 inputs/boilerplate/mri/preprocessing/coregistration.md delete mode 100644 inputs/boilerplate/mri/preprocessing/intensity-norm.md delete mode 100644 inputs/boilerplate/mri/preprocessing/operations-performed.md delete mode 100644 inputs/boilerplate/mri/preprocessing/quality-control-reports.md delete mode 100644 inputs/boilerplate/mri/preprocessing/segmentation.md delete mode 100644 inputs/boilerplate/mri/preprocessing/slice-timing-correction.md delete mode 100644 inputs/boilerplate/mri/preprocessing/smoothing.md delete mode 100644 inputs/boilerplate/mri/preprocessing/software.md delete mode 100644 inputs/boilerplate/mri/preprocessing/t1-stabilization.md delete mode 100644 inputs/boilerplate/mri/preprocessing/volume-censoring.md create mode 100644 ui/ecobidas_ui/generate/__init__.py create mode 100644 ui/ecobidas_ui/generate/views.py create mode 100644 ui/ecobidas_ui/templates/405.html create mode 100644 ui/ecobidas_ui/templates/generate/device_info.html create mode 100644 ui/ecobidas_ui/templates/generate/index.html create mode 100644 ui/ecobidas_ui/templates/generate/institution.html create mode 100644 ui/ecobidas_ui/templates/generate/meeg/device_channel_count.tmp create mode 100644 ui/ecobidas_ui/templates/generate/meeg/device_channels.tmp create mode 100644 ui/ecobidas_ui/templates/generate/meeg/device_freq_config.tmp create mode 100644 ui/ecobidas_ui/templates/generate/meeg/dewar_positioning.tmp create mode 100644 ui/ecobidas_ui/templates/generate/meeg/eeg_channel_placement.tmp create mode 100644 ui/ecobidas_ui/templates/generate/meeg/eeg_report.tmp create mode 100644 ui/ecobidas_ui/templates/generate/meeg/head_coil_frequency.tmp create mode 100644 ui/ecobidas_ui/templates/generate/meeg/head_localisation.tmp create mode 100644 ui/ecobidas_ui/templates/generate/meeg/meg_report.tmp create mode 100644 ui/ecobidas_ui/templates/generate/meeg/recording_properties.tmp create mode 100644 ui/ecobidas_ui/templates/generate/mri/acquisition/info.html create mode 100644 ui/ecobidas_ui/templates/generate/mri/acquisition/inplane_spatial_encoding.html create mode 100644 ui/ecobidas_ui/templates/generate/mri/acquisition/rf_contrasts.html create mode 100644 ui/ecobidas_ui/templates/generate/mri/acquisition/scanner_hardware.html create mode 100644 ui/ecobidas_ui/templates/generate/mri/acquisition/sequence.html create mode 100644 ui/ecobidas_ui/templates/generate/mri/acquisition/slice_acceleration.html create mode 100644 ui/ecobidas_ui/templates/generate/mri/acquisition/timing_parameters.html create mode 100644 ui/ecobidas_ui/templates/generate/mri/preprocessing/brain-extraction.html create mode 100644 ui/ecobidas_ui/templates/generate/mri/preprocessing/coregistration.html create mode 100644 ui/ecobidas_ui/templates/generate/mri/preprocessing/intensity-norm.html create mode 100644 ui/ecobidas_ui/templates/generate/mri/preprocessing/operations-performed.html create mode 100644 ui/ecobidas_ui/templates/generate/mri/preprocessing/quality-control-reports.html create mode 100644 ui/ecobidas_ui/templates/generate/mri/preprocessing/segmentation.html create mode 100644 ui/ecobidas_ui/templates/generate/mri/preprocessing/slice-timing-correction.html create mode 100644 ui/ecobidas_ui/templates/generate/mri/preprocessing/smoothing.html create mode 100644 ui/ecobidas_ui/templates/generate/mri/preprocessing/software.html create mode 100644 ui/ecobidas_ui/templates/generate/mri/preprocessing/t1-stabilization.html create mode 100644 ui/ecobidas_ui/templates/generate/mri/preprocessing/volume-censoring.html create mode 100644 ui/ecobidas_ui/templates/generate/report.html create mode 100644 ui/ecobidas_ui/templates/generate/task_name.html diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9731853e..04f84a8c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -83,6 +83,10 @@ repos: hooks: - id: prettier types_or: [css, html, json] + exclude: | + (?x)^( + ui/ecobidas_ui/static/css/font-awesome.min.css + )$ # Check formatting HTML / Jinja # - repo: https://github.com/thibaudcolas/curlylint diff --git a/inputs/boilerplate/mri/preprocessing/brain-extraction.md b/inputs/boilerplate/mri/preprocessing/brain-extraction.md deleted file mode 100644 index ed67bc41..00000000 --- a/inputs/boilerplate/mri/preprocessing/brain-extraction.md +++ /dev/null @@ -1,7 +0,0 @@ -# Template text for skull stripping/brain extraction - -Brain extraction/Skull stripping was performed using `bet_method` -(`bet_software` version `bet_version`) with the following parameters: -`bet_parameters`. {if bet_manual_edit != ''} `bet_manual_edit`. else `` - -## Example diff --git a/inputs/boilerplate/mri/preprocessing/coregistration.md b/inputs/boilerplate/mri/preprocessing/coregistration.md deleted file mode 100644 index c8adf168..00000000 --- a/inputs/boilerplate/mri/preprocessing/coregistration.md +++ /dev/null @@ -1,8 +0,0 @@ -# Coregistration - -As part of the coregistration, the `func-anat_coreg__source_volume` scan was -aligned to the `func-anat_coreg_target_volume` scan using -`func-anat_coreg_method` in `func-anat_coreg_software` `func-anat_coreg_version` -(cost function: `func-anat_coreg_cost_function`, df: `func-anat_coreg_dof`) - -## Example diff --git a/inputs/boilerplate/mri/preprocessing/intensity-norm.md b/inputs/boilerplate/mri/preprocessing/intensity-norm.md deleted file mode 100644 index 9fa49751..00000000 --- a/inputs/boilerplate/mri/preprocessing/intensity-norm.md +++ /dev/null @@ -1,11 +0,0 @@ -# Normalization - -{if intensity_normalization} `intensity_normalization_choice` intensity -normalization was performed. - -{if structural_intensity_correction} T1 images were bias field corrected. - -{if functional_intensity_correction} Functional images were intensity corrected -to reduce interleaved acquisition artifacts. - -## Example diff --git a/inputs/boilerplate/mri/preprocessing/operations-performed.md b/inputs/boilerplate/mri/preprocessing/operations-performed.md deleted file mode 100644 index ca390c1e..00000000 --- a/inputs/boilerplate/mri/preprocessing/operations-performed.md +++ /dev/null @@ -1,5 +0,0 @@ -# Operations performed + order of operation - -The following preprocessing steps were performed: `order_of_operation`. - -## Example diff --git a/inputs/boilerplate/mri/preprocessing/quality-control-reports.md b/inputs/boilerplate/mri/preprocessing/quality-control-reports.md deleted file mode 100644 index ab86269c..00000000 --- a/inputs/boilerplate/mri/preprocessing/quality-control-reports.md +++ /dev/null @@ -1,6 +0,0 @@ -# Quality control reports - -The following measures were taken to control image quality: -`quality_control_reports`. - -## Example diff --git a/inputs/boilerplate/mri/preprocessing/segmentation.md b/inputs/boilerplate/mri/preprocessing/segmentation.md deleted file mode 100644 index 7fde938f..00000000 --- a/inputs/boilerplate/mri/preprocessing/segmentation.md +++ /dev/null @@ -1,7 +0,0 @@ -# Segmentation - -Structural images were segmented using `segmentation_software` -`segmentation_version` by `segmentation_method` with the following parameters: -`segmentation_parameters` - -## Example diff --git a/inputs/boilerplate/mri/preprocessing/slice-timing-correction.md b/inputs/boilerplate/mri/preprocessing/slice-timing-correction.md deleted file mode 100644 index 14b2b8ad..00000000 --- a/inputs/boilerplate/mri/preprocessing/slice-timing-correction.md +++ /dev/null @@ -1,8 +0,0 @@ -# Slice timing correction - -Slice timing correction was implemented in `stc_software` (`stc_version`) and -applied using `stc_method`. Individual slices were realigned with slice -`stc_reference` as a reference. As interpolation method, `stc_interpolation` -interpolation was used. - -## Example diff --git a/inputs/boilerplate/mri/preprocessing/smoothing.md b/inputs/boilerplate/mri/preprocessing/smoothing.md deleted file mode 100644 index 1e238dfe..00000000 --- a/inputs/boilerplate/mri/preprocessing/smoothing.md +++ /dev/null @@ -1,13 +0,0 @@ -# Smoothing - -`smoothing_target_space` were smoothed using `smoothing_software` -(`smoothing_version`) using a `smoothing_type` (FWHM = `smoothing_size` mm) with -a `filtering_approach`. - -## Example - -Native volumes were smoothed using SPM (SPM12 - r7487) using a gaussian (FWHM = -8 mm) fixed kernel. - -Template surfaces were smoothed using Freeesurfer (6.0) using a gaussian (FWHM = -8 mm) with iterative smoothing until the desired FWHM was reached. diff --git a/inputs/boilerplate/mri/preprocessing/software.md b/inputs/boilerplate/mri/preprocessing/software.md deleted file mode 100644 index b3b25cfe..00000000 --- a/inputs/boilerplate/mri/preprocessing/software.md +++ /dev/null @@ -1,6 +0,0 @@ -# Preprocessing software - -Raw fMRI data were preprocessed using `preprocessing_software` -`preprocessing_software_version`. - -## Example diff --git a/inputs/boilerplate/mri/preprocessing/t1-stabilization.md b/inputs/boilerplate/mri/preprocessing/t1-stabilization.md deleted file mode 100644 index 1418a877..00000000 --- a/inputs/boilerplate/mri/preprocessing/t1-stabilization.md +++ /dev/null @@ -1,6 +0,0 @@ -# T1 stabilization - -For each functional run, the first `t1_stabilization` volumes were removed to -discard unsteady signals. - -## Example diff --git a/inputs/boilerplate/mri/preprocessing/volume-censoring.md b/inputs/boilerplate/mri/preprocessing/volume-censoring.md deleted file mode 100644 index 5764dc10..00000000 --- a/inputs/boilerplate/mri/preprocessing/volume-censoring.md +++ /dev/null @@ -1,10 +0,0 @@ -#Template text for volume_censoring - -{if volume_censoring_used == 1} - -Volume censoring was applied using `volume_censoring_method` -(`volume_censoring_software` version `volume_censoring_version`) with the -following criteria `volume_censoring_criteria` {if interpolation == 'none'} and -`interpolation` interpolation. - -## Example diff --git a/ui/ecobidas_ui/app.py b/ui/ecobidas_ui/app.py index cb5ed344..c35040a8 100644 --- a/ui/ecobidas_ui/app.py +++ b/ui/ecobidas_ui/app.py @@ -2,7 +2,7 @@ import sys from pathlib import Path -from ecobidas_ui import auth, db, protocols, public +from ecobidas_ui import auth, db, generate, protocols, public from ecobidas_ui._version import version from ecobidas_ui.extensions import bootstrap, csrf_protect @@ -37,11 +37,6 @@ def export() -> str: flash("'Export' not implemented yet!", category="warning") return render_template("public/index.html") - @app.route("/generate") - def generate() -> str: - flash("'Generate' Not implemented yet!", category="warning") - return render_template("public/index.html") - return app @@ -59,6 +54,7 @@ def register_blueprints(app): app.register_blueprint(public.views.blueprint) app.register_blueprint(auth.views.blueprint) app.register_blueprint(protocols.views.blueprint) + app.register_blueprint(generate.views.blueprint) return None @@ -71,7 +67,7 @@ def render_error(error): error_code = getattr(error, "code", 500) return render_template(f"{error_code}.html"), error_code - for errcode in [401, 404, 500]: + for errcode in [401, 404, 405, 500]: app.errorhandler(errcode)(render_error) return None diff --git a/ui/ecobidas_ui/generate/__init__.py b/ui/ecobidas_ui/generate/__init__.py new file mode 100644 index 00000000..05af8588 --- /dev/null +++ b/ui/ecobidas_ui/generate/__init__.py @@ -0,0 +1,3 @@ +"""The public module, including the homepage and user auth.""" + +from . import views # noqa diff --git a/ui/ecobidas_ui/generate/views.py b/ui/ecobidas_ui/generate/views.py new file mode 100644 index 00000000..2682f3b6 --- /dev/null +++ b/ui/ecobidas_ui/generate/views.py @@ -0,0 +1,30 @@ +"""Public section, including homepage and signup.""" + +import json +from pathlib import Path + +from flask import Blueprint, current_app, render_template, send_from_directory +from markdownify import markdownify as md + +blueprint = Blueprint("generate", __name__, url_prefix="/generate") + + +def dummmy_data(): + with open( + "/home/remi/github/cobidas_chckls/inputs/bids_template/task-auditoryLocalizer_bold.json" + ) as f: + data = json.load(f) + return data + + +@blueprint.route("/", methods=["GET", "POST"]) +def generate(): + return render_template("generate/index.html", **dummmy_data()) + + +@blueprint.route("/download", methods=["GET"]) +def download(): + tmp = md(render_template("generate/report.html"), heading_style="ATX") + with open(Path(current_app.config["UPLOAD_FOLDER"]) / "report.md", "w") as f: + f.write(tmp) + return send_from_directory(current_app.config["UPLOAD_FOLDER"], "report.md") diff --git a/ui/ecobidas_ui/protocols/views.py b/ui/ecobidas_ui/protocols/views.py index 2692c184..098f363e 100644 --- a/ui/ecobidas_ui/protocols/views.py +++ b/ui/ecobidas_ui/protocols/views.py @@ -258,12 +258,16 @@ def generate_extra_forms(protocol_name, activity_name) -> tuple[FlaskForm | None upload_participants_form = None upload_acquisition_form = None - if protocol_name != "neurovault": + if protocol_name not in ["neurovault", "cobidas"]: return upload_participants_form, upload_acquisition_form - if activity_name == "participants": + if (protocol_name == "neurovault" and activity_name == "participants") or ( + protocol_name == "cobidas" and activity_name == "sample" + ): upload_participants_form = UploadParticipantsForm(prefix="upload-") - if activity_name == "mri_acquisition": + if (protocol_name == "neurovault" and activity_name == "mri_acquisition") or ( + protocol_name == "cobidas" and activity_name == "common_parameters" + ): upload_acquisition_form = UploadBoldJsonForm(prefix="mri_acquisition-") return upload_participants_form, upload_acquisition_form diff --git a/ui/ecobidas_ui/templates/405.html b/ui/ecobidas_ui/templates/405.html new file mode 100644 index 00000000..23529a41 --- /dev/null +++ b/ui/ecobidas_ui/templates/405.html @@ -0,0 +1,17 @@ +{% extends 'layout/base.html' %} + +{% block title %}405 Error -Method Not Allowed{% endblock %} + +{% block content %} +
+
+
+ +

The method is not allowed for the requested URL.

+

+ Want to go home instead? +

+
+
+
+{% endblock %} diff --git a/ui/ecobidas_ui/templates/generate/device_info.html b/ui/ecobidas_ui/templates/generate/device_info.html new file mode 100644 index 00000000..19426591 --- /dev/null +++ b/ui/ecobidas_ui/templates/generate/device_info.html @@ -0,0 +1,3 @@ +Recordings were acquired using the {{ManufacturersModelName}} system from +{{Manufacturer}}, with serial number {{DeviceSerialNumber}}. The software +version was {{SoftwareVersions}}. diff --git a/ui/ecobidas_ui/templates/generate/index.html b/ui/ecobidas_ui/templates/generate/index.html new file mode 100644 index 00000000..87ff341f --- /dev/null +++ b/ui/ecobidas_ui/templates/generate/index.html @@ -0,0 +1,22 @@ +{% extends 'layout/base.html' %} + +{% block title %} eCOBIDAS {% endblock %} + +{% block content %} +
+
+
+ + +

Report

+
{% include 'generate/report.html' %}
+
+
+
+{% endblock %} diff --git a/ui/ecobidas_ui/templates/generate/institution.html b/ui/ecobidas_ui/templates/generate/institution.html new file mode 100644 index 00000000..7a70e904 --- /dev/null +++ b/ui/ecobidas_ui/templates/generate/institution.html @@ -0,0 +1,2 @@ +The recordings were performed in the {{InstitutionName}}, +{{InstitutionalDepartmentName}}, {{InstitutionAddress}}. diff --git a/ui/ecobidas_ui/templates/generate/meeg/device_channel_count.tmp b/ui/ecobidas_ui/templates/generate/meeg/device_channel_count.tmp new file mode 100644 index 00000000..e51784cd --- /dev/null +++ b/ui/ecobidas_ui/templates/generate/meeg/device_channel_count.tmp @@ -0,0 +1 @@ +There were {{MEGChannelCount}} MEG channels, {{MEGREFChannelCount}} of which where MEG reference channels. diff --git a/ui/ecobidas_ui/templates/generate/meeg/device_channels.tmp b/ui/ecobidas_ui/templates/generate/meeg/device_channels.tmp new file mode 100644 index 00000000..69584869 --- /dev/null +++ b/ui/ecobidas_ui/templates/generate/meeg/device_channels.tmp @@ -0,0 +1,2 @@ +Data was collected with {{EEGChannelCount}} EEG channels, {{EOGChannelCount}} EOG channels, +{{ECGChannelCount}} ECG channels and {{EMGChannelCount}} EMG channels recorded simultaneously. diff --git a/ui/ecobidas_ui/templates/generate/meeg/device_freq_config.tmp b/ui/ecobidas_ui/templates/generate/meeg/device_freq_config.tmp new file mode 100644 index 00000000..83d3b108 --- /dev/null +++ b/ui/ecobidas_ui/templates/generate/meeg/device_freq_config.tmp @@ -0,0 +1 @@ +Power line and sampling frequencies were {{PowerLineFrequency}} Hz and {{SamplingFrequency}} Hz, respectively. diff --git a/ui/ecobidas_ui/templates/generate/meeg/dewar_positioning.tmp b/ui/ecobidas_ui/templates/generate/meeg/dewar_positioning.tmp new file mode 100644 index 00000000..2e8a62a2 --- /dev/null +++ b/ui/ecobidas_ui/templates/generate/meeg/dewar_positioning.tmp @@ -0,0 +1 @@ +The dewar was positioned {{DewarPosition}} during the scan. diff --git a/ui/ecobidas_ui/templates/generate/meeg/eeg_channel_placement.tmp b/ui/ecobidas_ui/templates/generate/meeg/eeg_channel_placement.tmp new file mode 100644 index 00000000..78d6b451 --- /dev/null +++ b/ui/ecobidas_ui/templates/generate/meeg/eeg_channel_placement.tmp @@ -0,0 +1 @@ +Channels were placed according to the {{EEGPlacementScheme}} with a {{EEGGround}}. The {{EEGReference}} were used as the reference. diff --git a/ui/ecobidas_ui/templates/generate/meeg/eeg_report.tmp b/ui/ecobidas_ui/templates/generate/meeg/eeg_report.tmp new file mode 100644 index 00000000..5ed7b7f9 --- /dev/null +++ b/ui/ecobidas_ui/templates/generate/meeg/eeg_report.tmp @@ -0,0 +1,13 @@ +{% include 'task_name.tmp' %} + +{% include 'institution.tmp' %} + +{% include 'device_info.tmp' %} + +{% include 'device_freq_config.tmp' %} + +{% include 'device_channels.tmp' %} + +{% include 'eeg_channel_placement.tmp' %} + +{% include 'recording_properties.tmp' %} diff --git a/ui/ecobidas_ui/templates/generate/meeg/head_coil_frequency.tmp b/ui/ecobidas_ui/templates/generate/meeg/head_coil_frequency.tmp new file mode 100644 index 00000000..b6aca2a2 --- /dev/null +++ b/ui/ecobidas_ui/templates/generate/meeg/head_coil_frequency.tmp @@ -0,0 +1 @@ +Head localisation coils used frequencies of {% for f in HeadCoilFrequency %}{{f}} Hz{% if loop.last -1 %} and {% elif not loop.last %}, {% endif %}{% endfor %}. diff --git a/ui/ecobidas_ui/templates/generate/meeg/head_localisation.tmp b/ui/ecobidas_ui/templates/generate/meeg/head_localisation.tmp new file mode 100644 index 00000000..81b6a7e5 --- /dev/null +++ b/ui/ecobidas_ui/templates/generate/meeg/head_localisation.tmp @@ -0,0 +1 @@ +Head localisation was continuous. diff --git a/ui/ecobidas_ui/templates/generate/meeg/meg_report.tmp b/ui/ecobidas_ui/templates/generate/meeg/meg_report.tmp new file mode 100644 index 00000000..62c6bd2e --- /dev/null +++ b/ui/ecobidas_ui/templates/generate/meeg/meg_report.tmp @@ -0,0 +1,21 @@ +{% include 'task_name.tmp' %} + +{% include 'institution.tmp' %} + +{% include 'device_info.tmp' %} + +{% include 'device_freq_config.tmp' %} + +{% include 'device_channel_count.tmp' %} + +{% include 'device_channels.tmp' %} + +{% include 'recording_properties.tmp' %} + +{% if ContinuousHeadLocalization %} +{% include 'head_localisation.tmp' %} +{% endif %} + +{% include 'dewar_positioning.tmp' %} + +{% include 'head_coil_frequency.tmp' %} diff --git a/ui/ecobidas_ui/templates/generate/meeg/recording_properties.tmp b/ui/ecobidas_ui/templates/generate/meeg/recording_properties.tmp new file mode 100644 index 00000000..ab1a98c9 --- /dev/null +++ b/ui/ecobidas_ui/templates/generate/meeg/recording_properties.tmp @@ -0,0 +1 @@ +The experiment was recorded during {{RecordingDuration}} seconds {{RecordingType}}. diff --git a/ui/ecobidas_ui/templates/generate/mri/acquisition/info.html b/ui/ecobidas_ui/templates/generate/mri/acquisition/info.html new file mode 100644 index 00000000..caff2b83 --- /dev/null +++ b/ui/ecobidas_ui/templates/generate/mri/acquisition/info.html @@ -0,0 +1,8 @@ +The anatomical MRI data were collected with following parameters. {% include +'generate/mri/acquisition/sequence.html' %} {% include +'generate/mri/acquisition/inplane_spatial_encoding.html' %} {% include +'generate/mri/acquisition/rf_contrasts.html' %} {% include +'generate/mri/acquisition/slice_acceleration.html' %} {% include +'generate/mri/acquisition/timing_parameters.html' %} ({{n_slices}} slices +acquired in XXXX order; field of view, FOV={{fov}}mm; matrix size={{ms}}; voxel +size={{vs}}mm). diff --git a/ui/ecobidas_ui/templates/generate/mri/acquisition/inplane_spatial_encoding.html b/ui/ecobidas_ui/templates/generate/mri/acquisition/inplane_spatial_encoding.html new file mode 100644 index 00000000..4ba10853 --- /dev/null +++ b/ui/ecobidas_ui/templates/generate/mri/acquisition/inplane_spatial_encoding.html @@ -0,0 +1,6 @@ +This data was acquired using {{NumberShots}} radio-frequency excitations, with a +phase encoding direction along {{PhaseEncodingDirection}}, with an effective +echo spacing {{EffectiveEchoSpacing}} seconds and total readout time of +{{TotalReadoutTime}}, using {{ParallelAcquisitionTechnique}} parallel imaging +with a factor of {{ParallelReductionFactorInPlane}}, a partial Fourrier of +{{PartialFourier}} in the {{PartialFourierDirection}} direction. diff --git a/ui/ecobidas_ui/templates/generate/mri/acquisition/rf_contrasts.html b/ui/ecobidas_ui/templates/generate/mri/acquisition/rf_contrasts.html new file mode 100644 index 00000000..3c4daf5d --- /dev/null +++ b/ui/ecobidas_ui/templates/generate/mri/acquisition/rf_contrasts.html @@ -0,0 +1 @@ +This data was acquired using a flip angle of {{FlipAngle}}. diff --git a/ui/ecobidas_ui/templates/generate/mri/acquisition/scanner_hardware.html b/ui/ecobidas_ui/templates/generate/mri/acquisition/scanner_hardware.html new file mode 100644 index 00000000..4ade7da0 --- /dev/null +++ b/ui/ecobidas_ui/templates/generate/mri/acquisition/scanner_hardware.html @@ -0,0 +1,10 @@ +MR data were acquired on {{StationName}} with software version: +{{SoftwareVersions}}. This MRI scanner is a {{MagneticFieldStrength}}-Tesla +{{ManufacturersModelName}} from {{Manufacturer}} with serial number +{{DeviceSerialNumber}}. A {{ReceiveCoilName}} receiver coil was used with the +following characteristics for the receiver coil ReceiveCoilActiveElements +{{ReceiveCoilActiveElements}}. A {{GradientSetType}} gradient coil was used. A +{{MRTransmitCoilSequence}} transmit coid was used. A {{MatrixCoilMode}} was used +to reduce the number of independent channels by combining in analog the signals +from multiple coil elements. The following coil combination method was used +{{CoilCombinationMethod}}. diff --git a/ui/ecobidas_ui/templates/generate/mri/acquisition/sequence.html b/ui/ecobidas_ui/templates/generate/mri/acquisition/sequence.html new file mode 100644 index 00000000..7063fd0c --- /dev/null +++ b/ui/ecobidas_ui/templates/generate/mri/acquisition/sequence.html @@ -0,0 +1,4 @@ +This data was acquired using a {{SequenceVariant}} variant of {{SequenceName}}, +a {{ScanningSequence}} {{PulseSequenceType}} with options {{ScanOptions}}. {% if +NonlinearGradientCorrection %} The image(s) were corrected for gradient +nonlinearities by this scanner sequence. {% endif %} {{PulseSequenceDetails}} diff --git a/ui/ecobidas_ui/templates/generate/mri/acquisition/slice_acceleration.html b/ui/ecobidas_ui/templates/generate/mri/acquisition/slice_acceleration.html new file mode 100644 index 00000000..e185be7d --- /dev/null +++ b/ui/ecobidas_ui/templates/generate/mri/acquisition/slice_acceleration.html @@ -0,0 +1,2 @@ +For this multiband acquisition, the multiband factor was +{{MultibandAccelerationFactor}}. diff --git a/ui/ecobidas_ui/templates/generate/mri/acquisition/timing_parameters.html b/ui/ecobidas_ui/templates/generate/mri/acquisition/timing_parameters.html new file mode 100644 index 00000000..01c9d3a3 --- /dev/null +++ b/ui/ecobidas_ui/templates/generate/mri/acquisition/timing_parameters.html @@ -0,0 +1,2 @@ +repetition time, TR={{tr}}ms; echo time, TE={{EchoTime}}ms; inversion time, +TE={{InversionTime}}ms; SliceTiming SliceEncodingDirection DwellTime diff --git a/ui/ecobidas_ui/templates/generate/mri/preprocessing/brain-extraction.html b/ui/ecobidas_ui/templates/generate/mri/preprocessing/brain-extraction.html new file mode 100644 index 00000000..8a037fd4 --- /dev/null +++ b/ui/ecobidas_ui/templates/generate/mri/preprocessing/brain-extraction.html @@ -0,0 +1,3 @@ +Brain extraction/Skull stripping was performed using {{ bet_method }} {{ +bet_software }} (version {{ bet_version}}) with the following parameters: {{ +bet_parameters }}. diff --git a/ui/ecobidas_ui/templates/generate/mri/preprocessing/coregistration.html b/ui/ecobidas_ui/templates/generate/mri/preprocessing/coregistration.html new file mode 100644 index 00000000..9e850cdf --- /dev/null +++ b/ui/ecobidas_ui/templates/generate/mri/preprocessing/coregistration.html @@ -0,0 +1,5 @@ +As part of the coregistration, the {{ func-anat_coreg__source_volume }} scan was +aligned to the {{ func-anat_coreg_target_volume }} scan using {{ +func-anat_coreg_method }} in {{ func-anat_coreg_software }} {{ +func-anat_coreg_version }} (cost function: {{ func-anat_coreg_cost_function }} +df: {{ func-anat_coreg_dof }}) diff --git a/ui/ecobidas_ui/templates/generate/mri/preprocessing/intensity-norm.html b/ui/ecobidas_ui/templates/generate/mri/preprocessing/intensity-norm.html new file mode 100644 index 00000000..837ad65b --- /dev/null +++ b/ui/ecobidas_ui/templates/generate/mri/preprocessing/intensity-norm.html @@ -0,0 +1,5 @@ +{% if intensity_normalization_choice %} {{ intensity_normalization_choice }} +intensity normalization was performed. {% endif %} {% if +structural_intensity_correction %} T1 images were bias field corrected. {% endif +%} {% if functional_intensity_correction %} Functional images were intensity +corrected to reduce interleaved acquisition artifacts. {% endif %} diff --git a/ui/ecobidas_ui/templates/generate/mri/preprocessing/operations-performed.html b/ui/ecobidas_ui/templates/generate/mri/preprocessing/operations-performed.html new file mode 100644 index 00000000..0e2e242e --- /dev/null +++ b/ui/ecobidas_ui/templates/generate/mri/preprocessing/operations-performed.html @@ -0,0 +1 @@ +The following preprocessing steps were performed: {{ order_of_operation }}. diff --git a/ui/ecobidas_ui/templates/generate/mri/preprocessing/quality-control-reports.html b/ui/ecobidas_ui/templates/generate/mri/preprocessing/quality-control-reports.html new file mode 100644 index 00000000..f6fcd47b --- /dev/null +++ b/ui/ecobidas_ui/templates/generate/mri/preprocessing/quality-control-reports.html @@ -0,0 +1,2 @@ +The following measures were taken to control image quality: {{ +quality_control_reports }}. diff --git a/ui/ecobidas_ui/templates/generate/mri/preprocessing/segmentation.html b/ui/ecobidas_ui/templates/generate/mri/preprocessing/segmentation.html new file mode 100644 index 00000000..cb4c214c --- /dev/null +++ b/ui/ecobidas_ui/templates/generate/mri/preprocessing/segmentation.html @@ -0,0 +1,3 @@ +# Segmentation Structural images were segmented using {{ segmentation_software` +`segmentation_version }} by {{ segmentation_method }} with the following +parameters: `segmentation_parameters` ## Example diff --git a/ui/ecobidas_ui/templates/generate/mri/preprocessing/slice-timing-correction.html b/ui/ecobidas_ui/templates/generate/mri/preprocessing/slice-timing-correction.html new file mode 100644 index 00000000..0ba3aa4f --- /dev/null +++ b/ui/ecobidas_ui/templates/generate/mri/preprocessing/slice-timing-correction.html @@ -0,0 +1,4 @@ +Slice timing correction was implemented in {{ stc_software }} ({{ stc_version +}}) and applied using {{ stc_method }}. Individual slices were realigned with +slice {{ stc_reference }} as a reference. As interpolation method, {{ +stc_interpolation }} interpolation was used. diff --git a/ui/ecobidas_ui/templates/generate/mri/preprocessing/smoothing.html b/ui/ecobidas_ui/templates/generate/mri/preprocessing/smoothing.html new file mode 100644 index 00000000..d36622d9 --- /dev/null +++ b/ui/ecobidas_ui/templates/generate/mri/preprocessing/smoothing.html @@ -0,0 +1,3 @@ +{{ smoothing_target_space }} were smoothed using {{ smoothing_software }} ({{ +smoothing_version }}) using a {{ smoothing_type }} (FWHM = {{ smoothing_size }} +mm) with a {{ filtering_approach }}. diff --git a/ui/ecobidas_ui/templates/generate/mri/preprocessing/software.html b/ui/ecobidas_ui/templates/generate/mri/preprocessing/software.html new file mode 100644 index 00000000..f5593ec2 --- /dev/null +++ b/ui/ecobidas_ui/templates/generate/mri/preprocessing/software.html @@ -0,0 +1 @@ +Raw fMRI data were preprocessed using {{ preprocessing_software }}. diff --git a/ui/ecobidas_ui/templates/generate/mri/preprocessing/t1-stabilization.html b/ui/ecobidas_ui/templates/generate/mri/preprocessing/t1-stabilization.html new file mode 100644 index 00000000..23f5d70e --- /dev/null +++ b/ui/ecobidas_ui/templates/generate/mri/preprocessing/t1-stabilization.html @@ -0,0 +1,2 @@ +For each functional run, the first {{ t1_stabilization }} volumes were removed +to discard unsteady signals. diff --git a/ui/ecobidas_ui/templates/generate/mri/preprocessing/volume-censoring.html b/ui/ecobidas_ui/templates/generate/mri/preprocessing/volume-censoring.html new file mode 100644 index 00000000..c5d373f4 --- /dev/null +++ b/ui/ecobidas_ui/templates/generate/mri/preprocessing/volume-censoring.html @@ -0,0 +1,5 @@ +{% if volume_censoring_used %} Volume censoring was applied using {{ +volume_censoring_method` ({{ volume_censoring_software }} version {{ +volume_censoring_version }}) with the following criteria {{ +volume_censoring_criteria }} {% if interpolation %} and `interpolation }} +interpolation {% endif %}. {% endif %} diff --git a/ui/ecobidas_ui/templates/generate/report.html b/ui/ecobidas_ui/templates/generate/report.html new file mode 100644 index 00000000..78c24b8d --- /dev/null +++ b/ui/ecobidas_ui/templates/generate/report.html @@ -0,0 +1,17 @@ +

Institution

+{% include 'generate/institution.html' %} + +

Acquisition

+ +

Scanner

+{% include 'generate/device_info.html' %} {% include +'generate/mri/acquisition/scanner_hardware.html' %} + +

Anatomical scans

+{% include 'generate/mri/acquisition/info.html' %} + +

Functional scans

+{% include 'generate/task_name.html' %} {% include +'generate/mri/acquisition/info.html' %} + +

Preprocessing

diff --git a/ui/ecobidas_ui/templates/generate/task_name.html b/ui/ecobidas_ui/templates/generate/task_name.html new file mode 100644 index 00000000..08c8ec38 --- /dev/null +++ b/ui/ecobidas_ui/templates/generate/task_name.html @@ -0,0 +1 @@ +The following data correspond to the {{TaskName}} task. diff --git a/ui/ecobidas_ui/templates/layout/base.html b/ui/ecobidas_ui/templates/layout/base.html index 239ba9bf..a35edb49 100644 --- a/ui/ecobidas_ui/templates/layout/base.html +++ b/ui/ecobidas_ui/templates/layout/base.html @@ -14,10 +14,10 @@ {{ bootstrap.load_css() }} {% assets "css" %} {% endassets %} - + > diff --git a/ui/ecobidas_ui/templates/side_nav.html b/ui/ecobidas_ui/templates/side_nav.html index 0e9519b2..310cb657 100644 --- a/ui/ecobidas_ui/templates/side_nav.html +++ b/ui/ecobidas_ui/templates/side_nav.html @@ -16,7 +16,7 @@ -
- -

Report

-
{% include 'generate/report.html' %}
-
-
-
-{% endblock %} diff --git a/ui/ecobidas_ui/templates/generate/institution.jinja b/ui/ecobidas_ui/templates/generate/institution.jinja deleted file mode 100644 index 746ad7eb..00000000 --- a/ui/ecobidas_ui/templates/generate/institution.jinja +++ /dev/null @@ -1,2 +0,0 @@ -The recordings were performed in the {{ InstitutionName }}, -{{ InstitutionalDepartmentName }}, {{ InstitutionAddress }}. diff --git a/ui/ecobidas_ui/templates/generate/meeg/device_channel_count.tmp b/ui/ecobidas_ui/templates/generate/meeg/device_channel_count.tmp deleted file mode 100644 index 8bbb120a..00000000 --- a/ui/ecobidas_ui/templates/generate/meeg/device_channel_count.tmp +++ /dev/null @@ -1 +0,0 @@ -There were {{ MEGChannelCount }} MEG channels, {{ MEGREFChannelCount }} of which where MEG reference channels. diff --git a/ui/ecobidas_ui/templates/generate/meeg/device_channels.tmp b/ui/ecobidas_ui/templates/generate/meeg/device_channels.tmp deleted file mode 100644 index 548b3821..00000000 --- a/ui/ecobidas_ui/templates/generate/meeg/device_channels.tmp +++ /dev/null @@ -1,2 +0,0 @@ -Data was collected with {{ EEGChannelCount }} EEG channels, {{ EOGChannelCount }} EOG channels, -{{ ECGChannelCount }} ECG channels and {{ EMGChannelCount }} EMG channels recorded simultaneously. diff --git a/ui/ecobidas_ui/templates/generate/meeg/device_freq_config.tmp b/ui/ecobidas_ui/templates/generate/meeg/device_freq_config.tmp deleted file mode 100644 index 2b9b85a2..00000000 --- a/ui/ecobidas_ui/templates/generate/meeg/device_freq_config.tmp +++ /dev/null @@ -1 +0,0 @@ -Power line and sampling frequencies were {{ PowerLineFrequency }} Hz and {{ SamplingFrequency }} Hz, respectively. diff --git a/ui/ecobidas_ui/templates/generate/meeg/dewar_positioning.tmp b/ui/ecobidas_ui/templates/generate/meeg/dewar_positioning.tmp deleted file mode 100644 index 2758a381..00000000 --- a/ui/ecobidas_ui/templates/generate/meeg/dewar_positioning.tmp +++ /dev/null @@ -1 +0,0 @@ -The dewar was positioned {{ DewarPosition }} during the scan. diff --git a/ui/ecobidas_ui/templates/generate/meeg/eeg_channel_placement.tmp b/ui/ecobidas_ui/templates/generate/meeg/eeg_channel_placement.tmp deleted file mode 100644 index d2dc2ffe..00000000 --- a/ui/ecobidas_ui/templates/generate/meeg/eeg_channel_placement.tmp +++ /dev/null @@ -1 +0,0 @@ -Channels were placed according to the {{ EEGPlacementScheme }} with a {{ EEGGround }}. The {{ EEGReference }} were used as the reference. diff --git a/ui/ecobidas_ui/templates/generate/meeg/eeg_report.tmp b/ui/ecobidas_ui/templates/generate/meeg/eeg_report.tmp deleted file mode 100644 index 5ed7b7f9..00000000 --- a/ui/ecobidas_ui/templates/generate/meeg/eeg_report.tmp +++ /dev/null @@ -1,13 +0,0 @@ -{% include 'task_name.tmp' %} - -{% include 'institution.tmp' %} - -{% include 'device_info.tmp' %} - -{% include 'device_freq_config.tmp' %} - -{% include 'device_channels.tmp' %} - -{% include 'eeg_channel_placement.tmp' %} - -{% include 'recording_properties.tmp' %} diff --git a/ui/ecobidas_ui/templates/generate/meeg/head_coil_frequency.tmp b/ui/ecobidas_ui/templates/generate/meeg/head_coil_frequency.tmp deleted file mode 100644 index baa5c911..00000000 --- a/ui/ecobidas_ui/templates/generate/meeg/head_coil_frequency.tmp +++ /dev/null @@ -1 +0,0 @@ -Head localisation coils used frequencies of {% for f in HeadCoilFrequency %}{{ f }} Hz{% if loop.last -1 %} and {% elif not loop.last %}, {% endif %}{% endfor %}. diff --git a/ui/ecobidas_ui/templates/generate/meeg/head_localisation.tmp b/ui/ecobidas_ui/templates/generate/meeg/head_localisation.tmp deleted file mode 100644 index 81b6a7e5..00000000 --- a/ui/ecobidas_ui/templates/generate/meeg/head_localisation.tmp +++ /dev/null @@ -1 +0,0 @@ -Head localisation was continuous. diff --git a/ui/ecobidas_ui/templates/generate/meeg/meg_report.tmp b/ui/ecobidas_ui/templates/generate/meeg/meg_report.tmp deleted file mode 100644 index 62c6bd2e..00000000 --- a/ui/ecobidas_ui/templates/generate/meeg/meg_report.tmp +++ /dev/null @@ -1,21 +0,0 @@ -{% include 'task_name.tmp' %} - -{% include 'institution.tmp' %} - -{% include 'device_info.tmp' %} - -{% include 'device_freq_config.tmp' %} - -{% include 'device_channel_count.tmp' %} - -{% include 'device_channels.tmp' %} - -{% include 'recording_properties.tmp' %} - -{% if ContinuousHeadLocalization %} -{% include 'head_localisation.tmp' %} -{% endif %} - -{% include 'dewar_positioning.tmp' %} - -{% include 'head_coil_frequency.tmp' %} diff --git a/ui/ecobidas_ui/templates/generate/meeg/recording_properties.tmp b/ui/ecobidas_ui/templates/generate/meeg/recording_properties.tmp deleted file mode 100644 index a64f8e23..00000000 --- a/ui/ecobidas_ui/templates/generate/meeg/recording_properties.tmp +++ /dev/null @@ -1 +0,0 @@ -The experiment was recorded during {{ RecordingDuration }} seconds {{ RecordingType }}. diff --git a/ui/ecobidas_ui/templates/generate/mri/acquisition/info.jinja b/ui/ecobidas_ui/templates/generate/mri/acquisition/info.jinja deleted file mode 100644 index 6c13be68..00000000 --- a/ui/ecobidas_ui/templates/generate/mri/acquisition/info.jinja +++ /dev/null @@ -1,13 +0,0 @@ -The anatomical MRI data were collected with following parameters. - -{% include 'generate/mri/acquisition/sequence.jinja' %} - -{% include 'generate/mri/acquisition/inplane_spatial_encoding.jinja' %} - -{% include 'generate/mri/acquisition/rf_contrasts.jinja' %} - -{% include 'generate/mri/acquisition/slice_acceleration.jinja' %} - -{% include 'generate/mri/acquisition/timing_parameters.jinja' %} - -({{ n_slices }} slices acquired in XXXX order; field of view, FOV={{ fov }}mm; matrix size={{ ms }}; voxel size={{ vs }}mm). diff --git a/ui/ecobidas_ui/templates/generate/mri/acquisition/inplane_spatial_encoding.jinja b/ui/ecobidas_ui/templates/generate/mri/acquisition/inplane_spatial_encoding.jinja deleted file mode 100644 index ac6068b6..00000000 --- a/ui/ecobidas_ui/templates/generate/mri/acquisition/inplane_spatial_encoding.jinja +++ /dev/null @@ -1,6 +0,0 @@ -This data was acquired using {{ NumberShots }} radio-frequency excitations, with a -phase encoding direction along {{ PhaseEncodingDirection }}, with an effective -echo spacing {{ EffectiveEchoSpacing }} seconds and total readout time of -{{ TotalReadoutTime }}, using {{ ParallelAcquisitionTechnique }} parallel imaging -with a factor of {{ ParallelReductionFactorInPlane }}, a partial Fourrier of -{{ PartialFourier }} in the {{ PartialFourierDirection }} direction. diff --git a/ui/ecobidas_ui/templates/generate/mri/acquisition/rf_contrasts.jinja b/ui/ecobidas_ui/templates/generate/mri/acquisition/rf_contrasts.jinja deleted file mode 100644 index 7a12e393..00000000 --- a/ui/ecobidas_ui/templates/generate/mri/acquisition/rf_contrasts.jinja +++ /dev/null @@ -1 +0,0 @@ -This data was acquired using a flip angle of {{ FlipAngle }}. diff --git a/ui/ecobidas_ui/templates/generate/mri/acquisition/scanner_hardware.jinja b/ui/ecobidas_ui/templates/generate/mri/acquisition/scanner_hardware.jinja deleted file mode 100644 index c9771e40..00000000 --- a/ui/ecobidas_ui/templates/generate/mri/acquisition/scanner_hardware.jinja +++ /dev/null @@ -1,10 +0,0 @@ -MR data were acquired on {{ StationName }} with software version: -{{ SoftwareVersions }}. This MRI scanner is a {{ MagneticFieldStrength }}-Tesla -{{ ManufacturersModelName }} from {{ Manufacturer }} with serial number -{{ DeviceSerialNumber }}. A {{ ReceiveCoilName }} receiver coil was used with the -following characteristics for the receiver coil ReceiveCoilActiveElements -{{ ReceiveCoilActiveElements }}. A {{ GradientSetType }} gradient coil was used. A -{{ MRTransmitCoilSequence }} transmit coid was used. A {{ MatrixCoilMode }} was used -to reduce the number of independent channels by combining in analog the signals -from multiple coil elements. The following coil combination method was used -{{ CoilCombinationMethod }}. diff --git a/ui/ecobidas_ui/templates/generate/mri/acquisition/sequence.jinja b/ui/ecobidas_ui/templates/generate/mri/acquisition/sequence.jinja deleted file mode 100644 index 82377e59..00000000 --- a/ui/ecobidas_ui/templates/generate/mri/acquisition/sequence.jinja +++ /dev/null @@ -1,7 +0,0 @@ -This data was acquired using a {{ SequenceVariant }} variant of {{ SequenceName }}, -a {{ ScanningSequence }} {{ PulseSequenceType }} with options {{ ScanOptions }}. -{# #} -{% if NonlinearGradientCorrection %} -The image(s) were corrected for gradient nonlinearities by this scanner sequence. -{% endif %} -{{ PulseSequenceDetails }} diff --git a/ui/ecobidas_ui/templates/generate/mri/acquisition/slice_acceleration.jinja b/ui/ecobidas_ui/templates/generate/mri/acquisition/slice_acceleration.jinja deleted file mode 100644 index 5bfc0674..00000000 --- a/ui/ecobidas_ui/templates/generate/mri/acquisition/slice_acceleration.jinja +++ /dev/null @@ -1 +0,0 @@ -For this multiband acquisition, the multiband factor was {{ MultibandAccelerationFactor }}. diff --git a/ui/ecobidas_ui/templates/generate/mri/acquisition/timing_parameters.jinja b/ui/ecobidas_ui/templates/generate/mri/acquisition/timing_parameters.jinja deleted file mode 100644 index 05cc3f12..00000000 --- a/ui/ecobidas_ui/templates/generate/mri/acquisition/timing_parameters.jinja +++ /dev/null @@ -1,2 +0,0 @@ -repetition time, TR={{ tr }}ms; echo time, TE={{ EchoTime }}ms; inversion time, -TE={{ InversionTime }}ms; SliceTiming SliceEncodingDirection DwellTime diff --git a/ui/ecobidas_ui/templates/generate/mri/preprocessing/brain-extraction.jinja b/ui/ecobidas_ui/templates/generate/mri/preprocessing/brain-extraction.jinja deleted file mode 100644 index c671bb04..00000000 --- a/ui/ecobidas_ui/templates/generate/mri/preprocessing/brain-extraction.jinja +++ /dev/null @@ -1,3 +0,0 @@ -Brain extraction/Skull stripping was performed using {{ bet_method }} -{{ bet_software }} (version {{ bet_version }}) with the following parameters: -{{ bet_parameters }}. diff --git a/ui/ecobidas_ui/templates/generate/mri/preprocessing/coregistration.jinja b/ui/ecobidas_ui/templates/generate/mri/preprocessing/coregistration.jinja deleted file mode 100644 index 8a8e7ed8..00000000 --- a/ui/ecobidas_ui/templates/generate/mri/preprocessing/coregistration.jinja +++ /dev/null @@ -1,4 +0,0 @@ -As part of the coregistration, the {{ func_anat_coreg_source_volume }} scan was -aligned to the {{ func_anat_coreg_target_volume }} scan using -{{ func_anat_coreg_method }} in {{ func_anat_coreg_software }} -{{ func_anat_coreg_version }} (cost function: {{ func_anat_coreg_cost_function }} df: {{ func_anat_coreg_dof }}) diff --git a/ui/ecobidas_ui/templates/generate/mri/preprocessing/intensity-norm.jinja b/ui/ecobidas_ui/templates/generate/mri/preprocessing/intensity-norm.jinja deleted file mode 100644 index 110061d2..00000000 --- a/ui/ecobidas_ui/templates/generate/mri/preprocessing/intensity-norm.jinja +++ /dev/null @@ -1,9 +0,0 @@ -{% if intensity_normalization_choice %} -{{ intensity_normalization_choice }} intensity normalization was performed. -{% endif %} -{% if structural_intensity_correction %} -T1 images were bias field corrected. -{% endif %} -{% if functional_intensity_correction %} -Functional images were intensity corrected to reduce interleaved acquisition artifacts. -{% endif %} diff --git a/ui/ecobidas_ui/templates/generate/mri/preprocessing/operations-performed.jinja b/ui/ecobidas_ui/templates/generate/mri/preprocessing/operations-performed.jinja deleted file mode 100644 index 0e2e242e..00000000 --- a/ui/ecobidas_ui/templates/generate/mri/preprocessing/operations-performed.jinja +++ /dev/null @@ -1 +0,0 @@ -The following preprocessing steps were performed: {{ order_of_operation }}. diff --git a/ui/ecobidas_ui/templates/generate/mri/preprocessing/preprocessing.jinja b/ui/ecobidas_ui/templates/generate/mri/preprocessing/preprocessing.jinja deleted file mode 100644 index 345b7574..00000000 --- a/ui/ecobidas_ui/templates/generate/mri/preprocessing/preprocessing.jinja +++ /dev/null @@ -1,19 +0,0 @@ -{% include 'generate/mri/preprocessing/operations-performed.jinja' %} - -{% include 'generate/mri/preprocessing/software.jinja' %} - -{% include 'generate/mri/preprocessing/intensity-norm.jinja' %} - -{% include 'generate/mri/preprocessing/brain-extraction.jinja' %} - -{% include 'generate/mri/preprocessing/segmentation.jinja' %} - -{% include 'generate/mri/preprocessing/t1-stabilization.jinja' %} - -{% include 'generate/mri/preprocessing/coregistration.jinja' %} - -{% include 'generate/mri/preprocessing/slice-timing-correction.jinja' %} - -{% include 'generate/mri/preprocessing/quality-control-reports.jinja' %} - -{% include 'generate/mri/preprocessing/smoothing.jinja' %} diff --git a/ui/ecobidas_ui/templates/generate/mri/preprocessing/quality-control-reports.jinja b/ui/ecobidas_ui/templates/generate/mri/preprocessing/quality-control-reports.jinja deleted file mode 100644 index 174181bc..00000000 --- a/ui/ecobidas_ui/templates/generate/mri/preprocessing/quality-control-reports.jinja +++ /dev/null @@ -1 +0,0 @@ -The following measures were taken to control image quality: {{ quality_control_reports }}. diff --git a/ui/ecobidas_ui/templates/generate/mri/preprocessing/segmentation.jinja b/ui/ecobidas_ui/templates/generate/mri/preprocessing/segmentation.jinja deleted file mode 100644 index b48d9e99..00000000 --- a/ui/ecobidas_ui/templates/generate/mri/preprocessing/segmentation.jinja +++ /dev/null @@ -1,3 +0,0 @@ -Structural images were segmented using {{ segmentation_software }} -{{ segmentation_version }} by {{ segmentation_method }} with the following -parameters: {{ segmentation_parameters }} diff --git a/ui/ecobidas_ui/templates/generate/mri/preprocessing/slice-timing-correction.jinja b/ui/ecobidas_ui/templates/generate/mri/preprocessing/slice-timing-correction.jinja deleted file mode 100644 index 2673f7fe..00000000 --- a/ui/ecobidas_ui/templates/generate/mri/preprocessing/slice-timing-correction.jinja +++ /dev/null @@ -1,3 +0,0 @@ -Slice timing correction was implemented in {{ stc_software }} ({{ stc_version }}) and applied using {{ stc_method }}. -Individual slices were realigned with slice {{ stc_reference }} as a reference. -As interpolation method, {{ stc_interpolation }} interpolation was used. diff --git a/ui/ecobidas_ui/templates/generate/mri/preprocessing/smoothing.jinja b/ui/ecobidas_ui/templates/generate/mri/preprocessing/smoothing.jinja deleted file mode 100644 index f44697e5..00000000 --- a/ui/ecobidas_ui/templates/generate/mri/preprocessing/smoothing.jinja +++ /dev/null @@ -1,3 +0,0 @@ -{{ smoothing_target_space }} were smoothed using {{ smoothing_software }} -({{ smoothing_version }}) using a {{ smoothing_type }} -(FWHM = {{ smoothing_size }} mm) with a {{ filtering_approach }}. diff --git a/ui/ecobidas_ui/templates/generate/mri/preprocessing/software.jinja b/ui/ecobidas_ui/templates/generate/mri/preprocessing/software.jinja deleted file mode 100644 index f5593ec2..00000000 --- a/ui/ecobidas_ui/templates/generate/mri/preprocessing/software.jinja +++ /dev/null @@ -1 +0,0 @@ -Raw fMRI data were preprocessed using {{ preprocessing_software }}. diff --git a/ui/ecobidas_ui/templates/generate/mri/preprocessing/t1-stabilization.jinja b/ui/ecobidas_ui/templates/generate/mri/preprocessing/t1-stabilization.jinja deleted file mode 100644 index 0df0d5b8..00000000 --- a/ui/ecobidas_ui/templates/generate/mri/preprocessing/t1-stabilization.jinja +++ /dev/null @@ -1 +0,0 @@ -For each functional run, the first {{ t1_stabilization }} volumes were removed to discard unsteady signals. diff --git a/ui/ecobidas_ui/templates/generate/mri/preprocessing/volume-censoring.jinja b/ui/ecobidas_ui/templates/generate/mri/preprocessing/volume-censoring.jinja deleted file mode 100644 index f4a8d643..00000000 --- a/ui/ecobidas_ui/templates/generate/mri/preprocessing/volume-censoring.jinja +++ /dev/null @@ -1,5 +0,0 @@ -{% if volume_censoring_used %} -Volume censoring was applied using {{ volume_censoring_method }} -({{ volume_censoring_software }} version {{ volume_censoring_version }}) -with the following criteria {{ volume_censoring_criteria }} {% if interpolation %} and {{ interpolation }} interpolation {% endif %}. -{% endif %} diff --git a/ui/ecobidas_ui/templates/generate/report.html b/ui/ecobidas_ui/templates/generate/report.html deleted file mode 100644 index d228e9f4..00000000 --- a/ui/ecobidas_ui/templates/generate/report.html +++ /dev/null @@ -1,22 +0,0 @@ -

Institution

-{% include 'generate/institution.jinja' %} - -

Acquisition

- -

Scanner

-{% include 'generate/device_info.jinja' %} - -{% include 'generate/mri/acquisition/scanner_hardware.jinja' %} - -

Anatomical scans

-{% include 'generate/mri/acquisition/info.jinja' %} - -

Functional scans

-{% include 'generate/task_name.jinja' %} - -{% include 'generate/mri/acquisition/info.jinja' %} - -

Preprocessing

-{% include 'generate/mri/preprocessing/preprocessing.jinja' %} - -

Analysis

diff --git a/ui/ecobidas_ui/templates/generate/task_name.jinja b/ui/ecobidas_ui/templates/generate/task_name.jinja deleted file mode 100644 index d160a961..00000000 --- a/ui/ecobidas_ui/templates/generate/task_name.jinja +++ /dev/null @@ -1 +0,0 @@ -The following data correspond to the {{ TaskName }} task. diff --git a/ui/ecobidas_ui/templates/layout/base.html b/ui/ecobidas_ui/templates/layout/base.html deleted file mode 100644 index a35edb49..00000000 --- a/ui/ecobidas_ui/templates/layout/base.html +++ /dev/null @@ -1,100 +0,0 @@ - - - - - - - {% block title %} {% endblock %} - - - - {{ bootstrap.load_css() }} {% assets "css" %} - - {% endassets %} - - - - - {% include "layout/svg.html" %} - -
-
-
- -
-
-
- - {% with messages = get_flashed_messages(with_categories=true) %} - - {% if messages %} - - {% for category, message in messages %} -
-
- -
-
- {% endfor %} - - {% endif %} - - {% endwith %} - -
- {% include "layout/nav.html" %} - -
-
- {% block content %} - - {% endblock %} -
-
- - - {{ bootstrap.load_js() }} -
- - - {% include "layout/footer.html" %} - diff --git a/ui/ecobidas_ui/templates/layout/footer.html b/ui/ecobidas_ui/templates/layout/footer.html deleted file mode 100644 index c1ba239a..00000000 --- a/ui/ecobidas_ui/templates/layout/footer.html +++ /dev/null @@ -1,26 +0,0 @@ -
-
-
-
-
eCobidas
-
UI version: {{ version }}
-
- - -
-
-
-
-
diff --git a/ui/ecobidas_ui/templates/layout/nav.html b/ui/ecobidas_ui/templates/layout/nav.html deleted file mode 100644 index ef4e2ad9..00000000 --- a/ui/ecobidas_ui/templates/layout/nav.html +++ /dev/null @@ -1,82 +0,0 @@ -
- -
diff --git a/ui/ecobidas_ui/templates/layout/svg.html b/ui/ecobidas_ui/templates/layout/svg.html deleted file mode 100644 index 655bc1d1..00000000 --- a/ui/ecobidas_ui/templates/layout/svg.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - diff --git a/ui/ecobidas_ui/templates/protocol.html b/ui/ecobidas_ui/templates/protocol.html deleted file mode 100644 index 0e02cabe..00000000 --- a/ui/ecobidas_ui/templates/protocol.html +++ /dev/null @@ -1,57 +0,0 @@ -{% extends 'layout/base.html' %} - -{% from 'bootstrap5/form.html' import render_form %} - -{% block title %} eCOBIDAS - {{ protocol_pref_label }} {% endblock %} - -{% block content %} -
-
-
-

- {{ protocol_pref_label }} -

- {% include "side_nav.html" %} -
- -
- {% if landing_page %} - - {{ protocol_preamble|safe }} - - {{ landing_page|safe }} {% else %} -

{{ activity_pref_label }}

- - {% if form %} -

- -
- -

- {% endif %} - - {{ activity_preamble|safe }} - - {% include "extra_forms.html" %} - - {% if form %} -
-
{{ render_form(form) }}
-
- {% endif %} - - {% endif %} -
-
-
-{% endblock %} diff --git a/ui/ecobidas_ui/templates/public/about.html b/ui/ecobidas_ui/templates/public/about.html deleted file mode 100644 index b581b65d..00000000 --- a/ui/ecobidas_ui/templates/public/about.html +++ /dev/null @@ -1,150 +0,0 @@ -{% extends 'layout/base.html' %} - -{% block title %} eCOBIDAS - About {% endblock %} - -{% block content %} -
-
-
-

Have any questions? Something is missing? Let us know.

- -

Why this project?

-

- Poor methods and results description hinders the reproducibility and the - replicability of research. It also makes it hard to compare new and old - results and generally increases inefficiency in the research process. - This project is built on the hope that improving methods and results - reporting could improve our research. -

-

- Follow the link if you want to know more about the - motivations behind this project. -

-

Background

-

- This checklist is a project to make a user friendly checklist out the - best practices - report - of the Committee on Best Practices in Data Analysis and Sharing (COBIDAS) of the - Organization for Human Brain Mapping. -

-

- This is very much of a work in progress but the next step is to expand - the list to cover all the items of the COBIDAS report for fMRI as well - as for the recent - extension to EEG and MEG. -

-

Want to help?

-

- We are currently working on trying to expand the number of items used in - the checklist. All of this work is done in google spreadsheets: the - spreadsheet for each section is accessible by clicking on the - Source - at the top of each page. -

-

Want to know more?

-

- Most of the information concerning this project can be found on this - github repository. -

-

- If you want to be kept posted about the progress of the project, you can - join our - google group -

-

- From more frequent updates and behind the scenes, come and join us on - the - cobidas_checklist channel on the brainhack - - - channel. - -

-

- There is also an OSF - project to centralize all the information and repos. -

-

- We have a - list - of short, middle, long term goals: if you are interested by any of those - get in touch. Many of them do not necessarily require super-advanced - technical skills (except maybe a certain love for working with - spreadsheet and wanting them to be super organized). -

-

Contributors

-

- The list of the people involved in this project can be found - here. -

-
-
-
-{% endblock %} diff --git a/ui/ecobidas_ui/templates/public/faq.html b/ui/ecobidas_ui/templates/public/faq.html deleted file mode 100644 index a004c667..00000000 --- a/ui/ecobidas_ui/templates/public/faq.html +++ /dev/null @@ -1,36 +0,0 @@ -{% extends "layout/base.html" %} {% block title %} eCOBIDAS - FAQ {% endblock %} -{% block content %} -
-
-
- {% set count = [0] %} {% for s in data['sections'] %} -

{{ s['name'] }}

- {% for item in s['questions'] %} {% set _ = count.append(count.pop()+1) %} -
-
-

- -

-
-
{{ item['a']|safe }}
-
-
-
- {% endfor %} {% endfor %} -
-
- {% endblock %} -
diff --git a/ui/ecobidas_ui/templates/public/index.html b/ui/ecobidas_ui/templates/public/index.html deleted file mode 100644 index 32c9b55a..00000000 --- a/ui/ecobidas_ui/templates/public/index.html +++ /dev/null @@ -1,23 +0,0 @@ -{% extends 'layout/base.html' %} - -{% block title %} eCOBIDAS {% endblock %} - -{% block content %} -
-
-
-

TBD

- -

- "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod - tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim - veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea - commodo consequat. Duis aute irure dolor in reprehenderit in voluptate - velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint - occaecat cupidatat non proident, sunt in culpa qui officia deserunt - mollit anim id est laborum." -

-
-
-
-{% endblock %} diff --git a/ui/ecobidas_ui/templates/side_nav.html b/ui/ecobidas_ui/templates/side_nav.html deleted file mode 100644 index 310cb657..00000000 --- a/ui/ecobidas_ui/templates/side_nav.html +++ /dev/null @@ -1,28 +0,0 @@ - diff --git a/ui/ecobidas_ui/utils.py b/ui/ecobidas_ui/utils.py deleted file mode 100644 index d527089b..00000000 --- a/ui/ecobidas_ui/utils.py +++ /dev/null @@ -1 +0,0 @@ -LANG: str = "en" diff --git a/ui/pyproject.toml b/ui/pyproject.toml deleted file mode 100644 index d5501fc0..00000000 --- a/ui/pyproject.toml +++ /dev/null @@ -1,90 +0,0 @@ -[build-system] -build-backend = "hatchling.build" -requires = ["hatchling", "hatch-vcs"] - -[project] -authors = [{name = "Remi Gau"}] -dependencies = [ - "flask", - "Flask-WTF", - "Flask-Assets", - "bootstrap-flask", - "pandas", - "rich", - "requests", - "Flask-Caching", - "Flask-DebugToolbar", - "environs", - "markdownify" -] -description = "UI for eCOBIDAS" -license = {text = "GPL 3.0"} -maintainers = [{name = "Remi Gau", email = "remi.gau2@mcgill.ca"}] -name = "ecobidas_ui" -readme = "README.md" -requires-python = ">=3.11" -# Version from setuptools_scm -# dynamic = ["version"] -version = "0.1.0" - -[project.optional-dependencies] -dev = [ - 'tox' -] -test = [ - "coverage", - "pytest>=6.0.0", - "pytest-cov" -] - -[tool.black] -line-length = 100 - -[tool.codespell] -# ignore-words-list = "" -skip = "./.git,*.svg,env," - -[tool.hatch.build.hooks.vcs] -version-file = "ecobidas_ui/_version.py" - -[tool.hatch.build.targets.wheel] -packages = ["ecobidas_ui"] - -[tool.hatch.version] -source = "vcs" - -[tool.isort] -combine_as_imports = true -line_length = 100 -profile = "black" -skip_gitignore = true - -[tool.mypy] -check_untyped_defs = true -disallow_any_generics = true -disallow_incomplete_defs = true -disallow_untyped_defs = true -enable_error_code = ["ignore-without-code", "redundant-expr"] # "truthy-bool" -no_implicit_optional = true -show_error_codes = true -# strict = true -warn_redundant_casts = true -warn_unreachable = true -warn_unused_ignores = true - -[[tool.mypy.overrides]] -ignore_missing_imports = true -module = [ - "rich" -] - -[[tool.mypy.overrides]] -ignore_errors = true -module = ['tests.*'] - -[tool.pytest.ini_options] -addopts = "-ra --strict-config --strict-markers --doctest-modules --showlocals -s -v" -doctest_optionflags = "NORMALIZE_WHITESPACE ELLIPSIS" -junit_family = "xunit2" -minversion = "6.0" -xfail_strict = true diff --git a/ui/requirements.txt b/ui/requirements.txt deleted file mode 100644 index 302b83bb..00000000 --- a/ui/requirements.txt +++ /dev/null @@ -1,67 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.11 -# by the following command: -# -# pip-compile --output-file=requirements.txt --strip-extras pyproject.toml -# -Flask-Assets -blinker==1.8.2 - # via flask -bootstrap-flask==2.4.0 - # via ecobidas_ui (pyproject.toml) -certifi==2024.2.2 - # via requests -charset-normalizer==3.3.2 - # via requests -click==8.1.7 - # via flask -flask==3.0.3 - # via - # bootstrap-flask - # ecobidas_ui (pyproject.toml) - # flask-wtf -flask-wtf==1.2.1 - # via ecobidas_ui (pyproject.toml) -idna==3.7 - # via requests -itsdangerous==2.2.0 - # via - # flask - # flask-wtf -jinja2==3.1.4 - # via flask -markdown-it-py==3.0.0 - # via rich -markupsafe==2.1.5 - # via - # jinja2 - # werkzeug - # wtforms -mdurl==0.1.2 - # via markdown-it-py -numpy==1.26.4 - # via pandas -pandas==2.2.2 - # via ecobidas_ui (pyproject.toml) -pygments==2.18.0 - # via rich -python-dateutil==2.9.0.post0 - # via pandas -pytz==2024.1 - # via pandas -requests==2.32.2 - # via ecobidas_ui (pyproject.toml) -rich==13.7.1 - # via ecobidas_ui (pyproject.toml) -six==1.16.0 - # via python-dateutil -tzdata==2024.1 - # via pandas -urllib3==2.2.1 - # via requests -werkzeug==3.0.3 - # via flask -wtforms==3.1.2 - # via - # bootstrap-flask - # flask-wtf diff --git a/ui/tests/__init__.py b/ui/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/ui/tests/conftest.py b/ui/tests/conftest.py deleted file mode 100644 index 44452705..00000000 --- a/ui/tests/conftest.py +++ /dev/null @@ -1,29 +0,0 @@ -import pytest -from ecobidas_ui.app import create_app - - -@pytest.fixture() -def app(): - app = create_app() - app.config.update( - { - "TESTING": True, - } - ) - - # other setup can go here - - yield app - - # clean up / reset resources here - - -@pytest.fixture() -def client(app): - return app.test_client() - - -@pytest.fixture -def app_context(app): - with app.app_context(): - yield diff --git a/ui/tests/protocols/conftest.py b/ui/tests/protocols/conftest.py deleted file mode 100644 index 2da42613..00000000 --- a/ui/tests/protocols/conftest.py +++ /dev/null @@ -1,60 +0,0 @@ -import pandas as pd -import pytest - - -@pytest.fixture -def participants_json(): - return { - "participant_id": {"Annotations": {"IsAbout": {"TermURL": "", "Label": ""}}}, - "age": { - "Annotations": { - "IsAbout": {"TermURL": "nb:Age", "Label": ""}, - "Transformation": {"TermURL": "nb:FromInt", "Label": "integer data"}, - "MissingValues": ["", "n/a", " "], - } - }, - } - - -@pytest.fixture -def participants_df(): - return pd.DataFrame( - { - "age": [ - 26, - 24, - 27, - 20, - 22, - 26, - 24, - 21, - 26, - 21, - 24, - 22, - 21, - 30, - 24, - 19, - ], - "sex": [ - "F", - "M", - "F", - "F", - "M,", - "F", - "M", - "M", - "M", - "F", - "F", - "F", - "F", - "F", - "F", - "M", - ], - } - ) diff --git a/ui/tests/protocols/test_forms.py b/ui/tests/protocols/test_forms.py deleted file mode 100644 index 1884ace7..00000000 --- a/ui/tests/protocols/test_forms.py +++ /dev/null @@ -1,12 +0,0 @@ -import pandas as pd -from ecobidas_ui.protocols.forms import validate_participants_json, validate_participants_tsv - - -def test_validate_participants_tsv(participants_df): - assert validate_participants_tsv(participants_df) - assert not validate_participants_tsv(pd.DataFrame()) - - -def test_validate_participants_json(participants_json): - assert validate_participants_json(participants_json) - assert not validate_participants_json({}) diff --git a/ui/tests/protocols/test_utils.py b/ui/tests/protocols/test_utils.py deleted file mode 100644 index 53736209..00000000 --- a/ui/tests/protocols/test_utils.py +++ /dev/null @@ -1,33 +0,0 @@ -import pytest -from ecobidas_ui.protocols.utils import ( - extract_values_participants, - get_nav_bar_content, - get_protocol, - prep_activity_page, - protocol_url, -) - - -def test_protocol_url(): - assert protocol_url("neurovault").suffix == ".jsonld" - assert protocol_url("neurovault").stem == "neurovault_schema" - - -def test_get_protocol(): - protocol_content = get_protocol("neurovault") - assert protocol_content["@id"] == "neurovault_schema.jsonld" - - -def test_get_nav_bar_content(): - nav_bar = get_nav_bar_content("neurovault", "Participants") - assert len(nav_bar) == 9 - assert nav_bar[2]["link"] == "#" - - -@pytest.mark.parametrize("activity_name", ["participants", "mri_acquisition"]) -def test_prep_activity_page(activity_name): - activities, activity, items = prep_activity_page("neurovault", activity_name) - - -def test_extract_values_participants(participants_df, participants_json): - assert extract_values_participants(participants_df, participants_json).subject_age_min == 19 diff --git a/ui/tests/test_app.py b/ui/tests/test_app.py deleted file mode 100644 index 7cc2db04..00000000 --- a/ui/tests/test_app.py +++ /dev/null @@ -1,9 +0,0 @@ -def test_request_example(client): - response = client.get("/") - assert b"eCOBIDAS" in response.data - response = client.get("/faq/") - assert b"FAQ" in response.data - response = client.get("/about/") - assert b"about" in response.data - response = client.get("/protocols/neurovault/mri_acquisition") - assert b"neurovault" in response.data diff --git a/ui/tmp/participants.json b/ui/tmp/participants.json deleted file mode 100644 index 7fe84dfb..00000000 --- a/ui/tmp/participants.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "sex": { - "LongName": "sex", - "Description": "String value indicating phenotypical sex.", - "TermURL": "http://purl.obolibrary.org/obo/PATO_0001894", - "Levels": { - "F": { - "Description": "Female", - "TermURL": "http://purl.obolibrary.org/obo/PATO_0000383" - }, - "M": { - "Description": "Male", - "TermURL": "http://purl.obolibrary.org/obo/PATO_0000384" - } - } - }, - "age": { - "LongName": "age", - "Units": "year", - "TermURL": "http://purl.obolibrary.org/obo/PATO_0000011" - } -} diff --git a/ui/tmp/participants.tsv b/ui/tmp/participants.tsv deleted file mode 100644 index 1bae496a..00000000 --- a/ui/tmp/participants.tsv +++ /dev/null @@ -1,35 +0,0 @@ -participant_id sex age -sub-01 F 29 -sub-02 M 21 -sub-03 M 18 -sub-04 F 27 -sub-05 M 24 -sub-06 M 18 -sub-07 M 19 -sub-08 F 21 -sub-09 M 18 -sub-10 F 20 -sub-11 F 26 -sub-12 F 19 -sub-13 F 23 -sub-14 F 25 -sub-15 F 22 -sub-16 M 22 -sub-17 F 18 -sub-18 F 21 -sub-19 M 21 -sub-20 F 18 -sub-21 M 18 -sub-22 M 19 -sub-23 F 20 -sub-24 M 21 -sub-25 M 18 -sub-26 F 24 -sub-27 M 25 -sub-28 M 20 -sub-29 M 20 -sub-30 F 21 -sub-31 M 41 -sub-32 F 25 -sub-33 M 23 -sub-34 F 29 diff --git a/ui/tox.ini b/ui/tox.ini deleted file mode 100644 index 4ff19c02..00000000 --- a/ui/tox.ini +++ /dev/null @@ -1,33 +0,0 @@ -; See https://tox.wiki/en -[tox] -requires = - tox>=4 -; run lint by default when just calling "tox" -env_list = lint - -; ENVIRONMENTS -; ------------ -[style] -description = common environment for style checkers (rely on pre-commit hooks) -skip_install = true -deps = - pre-commit - -; COMMANDS -; -------- -[testenv:lint] -description = install pre-commit hooks and run all linters and formatters -skip_install = true -deps = - {[style]deps} -commands = - pre-commit install - pre-commit run --all-files --show-diff-on-failure {posargs:} - -[testenv:update_dependencies] -description = update requirements.txt -skip_install = true -deps = - pip-tools -commands = - pip-compile --strip-extras -o requirements.txt pyproject.toml {posargs:} From 4fc27199280f0abf9237c8f7c6cbe740c3cde922 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Tue, 28 May 2024 15:43:55 +0200 Subject: [PATCH 27/31] update precommit --- .pre-commit-config.yaml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0403e4f6..9731853e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -83,10 +83,6 @@ repos: hooks: - id: prettier types_or: [css, html, json] - # exclude: | - # (?x)^( - # ui/ecobidas_ui/static/css/font-awesome.min.css - # )$ # Check formatting HTML / Jinja # - repo: https://github.com/thibaudcolas/curlylint From 018423361e1481b8d649a319b04b7fa19132a106 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Tue, 28 May 2024 15:56:07 +0200 Subject: [PATCH 28/31] update all schemas --- cobidas_schema | 2 +- ecobidas/inputs/meeg/acquisition.tsv | 2 +- ecobidas/inputs/neurovault/neurovault.tsv | 176 ++++++++++---------- ecobidas/inputs/reexecution/reexecution.tsv | 2 +- mkdocs.yml | 6 +- 5 files changed, 94 insertions(+), 94 deletions(-) diff --git a/cobidas_schema b/cobidas_schema index c1621e78..a6753816 160000 --- a/cobidas_schema +++ b/cobidas_schema @@ -1 +1 @@ -Subproject commit c1621e7839c730963cdc735efa35ed9520b4df2a +Subproject commit a6753816ac6960e357e657378c882bb2593e3a28 diff --git a/ecobidas/inputs/meeg/acquisition.tsv b/ecobidas/inputs/meeg/acquisition.tsv index b47146cb..9a576796 100644 --- a/ecobidas/inputs/meeg/acquisition.tsv +++ b/ecobidas/inputs/meeg/acquisition.tsv @@ -20,7 +20,7 @@ Acquisition Data acquisition parameters Low- and high-pass filter characteristic Acquisition Data acquisition parameters Sampling frequency sampling_frequency sampling_frequency 21 1 1 Does the paper specify the sampling frequency? Acquisition Data acquisition parameters Continuous versus epoched acquisition? continuous_versus_epoched_acquisition? continuous_versus_epoched_acquisition 22 1 1 Does the paper specify whether continuous versus epoched acquisition was used? Acquisition Data acquisition parameters For EEG/EOG/ECG/EMG/skin conductance: report reference and ground electrode positions reference_and_ground_electrode_positions reference_and_ground_electrode_positions 23 1 1 (EEG/EOG/ECG/EMG/skin conductance) Does the paper report reference and ground electrode positions? -Acquisition Sensor position digitization EEG/EOG: manufacterer and model of the device used other_devices_for_meg other_devices_for_meg 25 1 1 (EEG/EOG) Does the paper specify the manufacterer and model of the device used for EEG/EOG - ECG?, All electrodes? +Acquisition Sensor position digitization EEG/EOG: manufacturer and model of the device used other_devices_for_meg other_devices_for_meg 25 1 1 (EEG/EOG) Does the paper specify the manufacturer and model of the device used for EEG/EOG - ECG?, All electrodes? Acquisition Sensor position digitization MEG: monitoring of head position relative to the sensor array monitoring_of_head_position monitoring_of_head_position 26 1 1 (MEG) Does the paper describe how head position relative to the sensor array was monitored? Acquisition Sensor position digitization MEG: use of head movement detection coils use_of_head_movement_detection_coils use_of_head_movement_detection_coils 27 1 1 (MEG) Does the paper specify the use of head movement detection coils? Acquisition Sensor position digitization MEG: placement of coils placement_of_coils placement_of_coils 28 1 1 (MEG) Does the paper specify the placement of coils? diff --git a/ecobidas/inputs/neurovault/neurovault.tsv b/ecobidas/inputs/neurovault/neurovault.tsv index c9a9c56c..2540a968 100644 --- a/ecobidas/inputs/neurovault/neurovault.tsv +++ b/ecobidas/inputs/neurovault/neurovault.tsv @@ -1,88 +1,88 @@ -activity_pref_label activity_order item_order question unit details field_type choices item item_pref_label visibility item_description include mandatory preamble bids_status bids_file bids_key bids_key_for_unit UUID -Experimental design 1 1 Type of design select blocked | event_related | hybrid block/event type_of_design type of design 1 type of design 1 1 Describe your experimental design #NAME? -Experimental design 1 2 Number of imaging runs acquired integer 0 number of imaging runs 1 number of imaging runs 1 2 #NAME? -Experimental design 1 3 Number of blocks, trials or experimental units per imaging run integer 0 number of experimental units 1 number of experimental units 1 2 #NAME? -Experimental design 1 4 Length of each imaging run seconds float 0 length of runs 1 length of runs 1 2 #NAME? -Experimental design 1 5 For blocked designs, length of blocks seconds float 0 length of blocks type_of_design in [0, 2] length of blocks 1 2 #NAME? -Experimental design 1 6 Length of individual trials seconds float 0 length of trials 1 length of trials 1 2 #NAME? -Experimental design 1 7 Was the design optimized for efficiency? radio preset:boolean optimization 1 optimization 1 2 #NAME? -Experimental design 1 8 What method was used for optimization? textarea optimization method optimization == 1 optimization method 1 3 #NAME? -Participants 2 1 Number of subjects entering into the analysis integer 0 number of subjects 1 number of subjects 1 1 Describe your participant sample #NAME? -Participants 2 2 Mean age of subjects float 0 subject age mean 1 subject age mean 1 1 #NAME? -Participants 2 3 Minimum age of subjects float 0 subject age min 1 subject age min 1 2 #NAME? -Participants 2 4 Maximum age of subjects float 0 subject age max 1 subject age max 1 2 #NAME? -Participants 2 5 Handedness of subjects radio right | left | both handedness 1 handedness 1 2 #NAME? -Participants 2 6 The proportion of subjects who were male float 0 | 1 proportion male subjects 1 proportion male subjects 1 2 #NAME? -Participants 2 7 Additional inclusion/exclusion criteria, if any. Including specific sampling strategies that limit inclusion to a specific group, such as laboratory members. textarea inclusion exclusion criteria 1 inclusion exclusion criteria 1 3 #NAME? -Participants 2 8 Number of subjects scanned but rejected from analysis integer 0 number of rejected subjects 1 number of rejected subjects 1 2 #NAME? -Participants 2 9 Was this study a comparison between subject groups? radio preset:boolean group comparison 1 group comparison 1 1 #NAME? -Participants 2 10 A description of the groups being compared textarea group description group_comparison == 1 group description 1 2 #NAME? -MRI acquisition 3 1 Manufacturer of MRI scanner select Siemens | Philips | General Electric | other Manufacturer scanner make 1 scanner make 1 1 Describe your acquisition parameters #NAME? -MRI acquisition 3 2 Model of MRI scanner textarea ManufacturersModelName scanner model 1 scanner model 1 1 #NAME? -MRI acquisition 3 3 Field strength of MRI scanner Tesla float 0 MagneticFieldStrength field strength 1 field strength 1 1 #NAME? -MRI acquisition 3 4 Description of pulse sequence used for fMRI select Gradient echo | Spin echo | Mutliband gradient echo | MPRAGE | MP2RAGE | FLASH PulseSequenceType pulse sequence 1 pulse sequence 1 1 #NAME? -MRI acquisition 3 5 Description of parallel imaging method and parameters textarea parallel imaging 1 parallel imaging 1 3 #NAME? -MRI acquisition 3 6 Imaging field of view Millimeters float field of view 1 field of view 1 2 #NAME? -MRI acquisition 3 7 Matrix size for MRI acquisition integer matrix size 1 matrix size 1 2 #NAME? -MRI acquisition 3 8 Distance between slices (includes skip or distance factor). Millimeters float 0 slice thickness 1 slice thickness 1 1 #NAME? -MRI acquisition 3 9 The size of the skipped area between slices. Millimeters float 0 skip factor 1 skip factor 1 2 #NAME? -MRI acquisition 3 10 The orientation of slices radio axial | sagittal | frontal acquisition orientation 1 acquisition orientation 1 2 #NAME? -MRI acquisition 3 11 Order of acquisition of slices select ascending | descending | interleaved SliceTiming order of acquisition 1 order of acquisition 1 3 #NAME? -MRI acquisition 3 12 Repetition time (TR) Milliseconds float 0 RepetitionTime repetition time 1 repetition time 1 1 #NAME? -MRI acquisition 3 13 Echo time (TE) Milliseconds float 0 EchoTime echo time 1 echo time 1 1 #NAME? -MRI acquisition 3 14 Flip angle Degrees float 0 FlipAngle flip angle 1 flip angle 1 2 #NAME? -Preprocessing 4 1 If a single software package was used for all analyses, specify that here select preset:mri_softwares SoftwareName software package 1 software package 1 1 Describe your preprocessing #NAME? -Preprocessing 4 2 Version of software package used textarea SoftwareVersion software version 1 software version 1 1 #NAME? -Preprocessing 4 3 Specify order of preprocessing operations textarea order of preprocessing operations 1 order of preprocessing operations 1 2 #NAME? -Preprocessing 4 4 Describe quality control measures textarea quality control 1 quality control 1 3 #NAME? -Preprocessing 4 5 Was B0 distortion correction used? radio preset:boolean used b0 unwarping 1 used b0 unwarping 1 2 #NAME? -Preprocessing 4 6 Specify software used for distortion correction if different from the main package select preset:mri_softwares b0 unwarping software used_b0_unwarping == 1 b0 unwarping software 1 3 #NAME? -Preprocessing 4 7 Was slice timing correction used? radio preset:boolean used slice timing correction 1 used slice timing correction 1 1 #NAME? -Preprocessing 4 8 Specify software used for slice timing correction if different from the main package select preset:mri_softwares slice timing correction software used_slice_timing_correction == 1 slice timing correction software 1 3 #NAME? -Preprocessing 4 9 Was motion correction used? radio preset:boolean used motion correction 1 used motion correction 1 1 #NAME? -Preprocessing 4 10 Specify software used for motion correction if different from the main package select preset:mri_softwares motion correction software used_motion_correction == 1 motion correction software 1 3 #NAME? -Preprocessing 4 11 Reference scan used for motion correction textarea motion correction reference used_motion_correction == 1 motion correction reference 1 3 #NAME? -Preprocessing 4 12 Similarity metric used for motion correction select preset:cost_functions motion correction metric used_motion_correction == 1 motion correction metric 1 3 #NAME? -Preprocessing 4 13 Interpolation method used for motion correction select preset:interpolations motion correction interpolation used_motion_correction == 1 motion correction interpolation 1 3 #NAME? -Preprocessing 4 14 Was motion-susceptibility correction used? radio preset:boolean used motion susceptibiity correction 1 used motion susceptibiity correction 1 3 #NAME? -Intersubject registration 5 1 Were subjects registered to a common stereotactic space? radio preset:boolean used intersubject registration 1 used intersubject registration 1 1 Describe your spatial normalization #NAME? -Intersubject registration 5 2 Specify software used for intersubject registration if different from main package select preset:mri_softwares intersubject registration software used_intersubject_registration == 1 intersubject registration software 1 2 #NAME? -Intersubject registration 5 3 Was linear or nonlinear registration used? select linear | non-linear intersubject transformation type used_intersubject_registration == 1 intersubject transformation type 1 1 #NAME? -Intersubject registration 5 4 If nonlinear registration was used, describe transform method textarea nonlinear transform type used_intersubject_registration == 1 and nonlinear_transform_type == 1 nonlinear transform type 1 2 #NAME? -Intersubject registration 5 5 Similarity metric used for intersubject registration textarea transform similarity metric used_intersubject_registration == 1 transform similarity metric 1 3 #NAME? -Intersubject registration 5 6 Interpolation method used for intersubject registration select preset:interpolations interpolation method used_intersubject_registration == 1 interpolation method 1 2 #NAME? -Intersubject registration 5 7 What type of image was used to determine the transformation to the atlas? textarea object image type used_intersubject_registration == 1 object image type 1 1 #NAME? -Intersubject registration 5 8 Were the functional images coregistered to the subject's structural image? radio preset:boolean functional coregistered to structural 1 functional coregistered to structural 1 2 #NAME? -Intersubject registration 5 9 Method used to coregister functional to structural images textarea functional coregistration method functional_coregistered_to_structural == 1 functional coregistration method 1 3 #NAME? -Intersubject registration 5 10 Name of coordinate space for registration target select MNI | Talairach | MNI2Tal | other coordinate space 1 coordinate space 1 1 #NAME? -Intersubject registration 5 11 Name of target template image textarea target template image 1 target template image 1 2 #NAME? -Intersubject registration 5 12 Voxel size of target template Millimeters float 0 target resolution 1 target resolution 1 1 #NAME? -Intersubject registration 5 13 Was spatial smoothing applied? radio preset:boolean used smoothing 1 used smoothing 1 1 #NAME? -Intersubject registration 5 14 Describe the type of smoothing applied textarea smoothing type used_smoothing == 1 smoothing type 1 1 #NAME? -Intersubject registration 5 15 The full-width at half-maximum of the smoothing kernel Millimeters float 0 smoothing fwhm used_smoothing == 1 smoothing fwhm 1 1 #NAME? -Intersubject registration 5 16 Voxel size in mm of the resampled, atlas-space images float 0 resampled voxel size 1 resampled voxel size 1 1 #NAME? -Individual subject modeling 6 1 Type of group model used radio Regression | other intrasubject model type 1 intrasubject model type 1 1 Describe your model specification at the subejct level #NAME? -Individual subject modeling 6 2 Estimation method used for model select ordinary least squares | generalized least squares | other intrasubject estimation type 1 intrasubject estimation type 1 1 #NAME? -Individual subject modeling 6 3 Software used for intrasubject modeling if different from overall package select preset:mri_softwares intrasubject modeling software 1 intrasubject modeling software 1 2 #NAME? -Individual subject modeling 6 4 Nature of HRF model select spm HRF | glover HRF | double gamma | Fourrier set | Finite Impulse Response | FLOBS | other hemodynamic response function 1 hemodynamic response function 1 2 #NAME? -Individual subject modeling 6 5 Were temporal derivatives included? radio preset:boolean used temporal derivatives 1 used temporal derivatives 1 2 #NAME? -Individual subject modeling 6 6 Were dispersion derivatives included? radio preset:boolean used dispersion derivatives 1 used dispersion derivatives 1 3 #NAME? -Individual subject modeling 6 7 Were motion regressors included? radio preset:boolean used motion regressors 1 used motion regressors 1 2 #NAME? -Individual subject modeling 6 8 Was a reaction time regressor included? radio preset:boolean used reaction time regressor 1 used reaction time regressor 1 2 #NAME? -Individual subject modeling 6 9 Were any regressors specifically orthogonalized with respect to others? radio preset:boolean used orthogonalization 1 used orthogonalization 1 1 #NAME? -Individual subject modeling 6 10 If orthogonalization was used, describe here textarea orthogonalization description used_orthogonalization == 1 orthogonalization description 1 2 #NAME? -Individual subject modeling 6 11 Was high pass filtering applied? radio preset:boolean used high pass filter 1 used high pass filter 1 1 #NAME? -Individual subject modeling 6 12 Describe method used for high pass filtering textarea high pass filter method used_high_pass_filter == 1 high pass filter method 1 2 #NAME? -Individual subject modeling 6 13 What autocorrelation model was used ? select SPM: global approximate AR(1) | SPM: FAST | FSL: locally regularized autocorrelation function | AFNI: ARMA | none | other autocorrelation model 1 autocorrelation model 1 2 #NAME? -Individual subject modeling 6 14 Exactly what terms are subtracted from what? textarea contrast definition 1 contrast definition 1 1 #NAME? -Individual subject modeling 6 15 Link to Cognitive Atlas definition of this contrast Define these in terms of task or stimulus conditions (e.g., 'one-back task with objects versus zero-back task with objects') instead of underlying psychological concepts (e.g., 'working memory'). textarea contrast definition cogatlas 1 contrast definition cogatlas 1 3 #NAME? -Group modeling 7 1 Type of group model used select Regression group model type 1 group model type 1 1 Describe the group level analysis #NAME? -Group modeling 7 2 Estimation method used for model select ordinary least squares | generalized least squares group estimation type 1 group estimation type 1 1 #NAME? -Group modeling 7 3 Software used for group modeling if different from overall package select preset:mri_softwares group modeling software 1 group modeling software 1 2 #NAME? -Group modeling 7 4 Type of inference for group model select random effect | mixed effect | fixed effect group inference type 1 group inference type 1 1 #NAME? -Group modeling 7 5 If more than 2-levels, describe the levels and assumptions of the model. For example, are variances assumed equal between groups. textarea group model multilevel 1 group model multilevel 1 3 #NAME? -Group modeling 7 6 Was this a repeated measures design at the group level? radio preset:boolean group repeated measures 1 group repeated measures 1 1 #NAME? -Group modeling 7 7 If multiple measurements per subject, list method to account for within subject correlation, exact assumptions made about correlation/variance textarea group repeated measures method group_repeated_measures == 1 group repeated measures method 1 3 #NAME? -Group inference 8 1 Type of statistic that is the basis of the inference select Z | T | F | X2 | PostProb | Non-parametric Permutations | Monte Carlo Permutations group statistic type 1 group statistic type 1 2 Describe your statistical inference #NAME? -Group inference 8 2 Parameters of the null distribution of the test statisic. Typically degrees of freedom (should be clear from the test statistic what these are). float group statistic parameters 1 group statistic parameters 1 1 #NAME? -Group inference 8 3 Noise smoothness for statistical inference This is the estimated smoothness used with Random Field Theory or a simulation-based inference method. float 0 group smoothness fwhm 1 group smoothness fwhm 1 1 #NAME? +activity_pref_label activity_order item_order question unit details field_type choices item item_pref_label visibility validation item_description include mandatory preamble bids_status bids_file bids_key bids_key_for_unit UUID +Experimental design 1 1 Type of design select blocked | event_related | hybrid block/event type_of_design type of design 1 type of design 1 1 Describe your experimental design #NAME? +Experimental design 1 2 Number of imaging runs acquired integer 0 number of imaging runs 1 number of imaging runs 1 2 #NAME? +Experimental design 1 3 Number of blocks, trials or experimental units per imaging run integer 0 number of experimental units 1 number of experimental units 1 2 #NAME? +Experimental design 1 4 Length of each imaging run seconds float 0 length of runs 1 length of runs 1 2 #NAME? +Experimental design 1 5 For blocked designs, length of blocks seconds float 0 length of blocks type_of_design in [0, 2] length of blocks 1 2 #NAME? +Experimental design 1 6 Length of individual trials seconds float 0 length of trials 1 length of trials 1 2 #NAME? +Experimental design 1 7 Was the design optimized for efficiency? radio preset:boolean optimization 1 optimization 1 2 #NAME? +Experimental design 1 8 What method was used for optimization? textarea optimization method optimization == 1 optimization method 1 3 #NAME? +Participants 2 1 Number of subjects entering into the analysis integer 0 number of subjects 1 number of subjects 1 1 Describe your participant sample #NAME? +Participants 2 2 Mean age of subjects float 0 | 120 subject_age_mean subject age mean 1 subject age mean 1 1 #NAME? +Participants 2 3 Minimum age of subjects float 0 | 120 subject_age_min subject age min 1 subject_age_min < subject_age_mean subject age min 1 2 #NAME? +Participants 2 4 Maximum age of subjects float 0 | 120 subject_age_max subject age max 1 subject_age_max > subject_age_mean subject age max 1 2 #NAME? +Participants 2 5 Handedness of subjects radio right | left | both handedness 1 handedness 1 2 #NAME? +Participants 2 6 The proportion of subjects who were male float 0 | 1 proportion male subjects 1 proportion male subjects 1 2 #NAME? +Participants 2 7 Additional inclusion/exclusion criteria, if any. Including specific sampling strategies that limit inclusion to a specific group, such as laboratory members. textarea inclusion exclusion criteria 1 inclusion exclusion criteria 1 3 #NAME? +Participants 2 8 Number of subjects scanned but rejected from analysis integer 0 number of rejected subjects 1 number of rejected subjects 1 2 #NAME? +Participants 2 9 Was this study a comparison between subject groups? radio preset:boolean group comparison 1 group comparison 1 1 #NAME? +Participants 2 10 A description of the groups being compared textarea group description group_comparison == 1 group description 1 2 #NAME? +MRI acquisition 3 1 Manufacturer of MRI scanner select Siemens | Philips | General Electric | other Manufacturer scanner make 1 scanner make 1 1 Describe your acquisition parameters #NAME? +MRI acquisition 3 2 Model of MRI scanner textarea ManufacturersModelName scanner model 1 scanner model 1 1 #NAME? +MRI acquisition 3 3 Field strength of MRI scanner Tesla float 0 | 20 MagneticFieldStrength field strength 1 field strength 1 1 #NAME? +MRI acquisition 3 4 Description of pulse sequence used for fMRI select Gradient echo | Spin echo | Mutliband gradient echo | MPRAGE | MP2RAGE | FLASH | other PulseSequenceType pulse sequence 1 pulse sequence 1 1 #NAME? +MRI acquisition 3 5 Description of parallel imaging method and parameters textarea parallel imaging 1 parallel imaging 1 3 #NAME? +MRI acquisition 3 6 Imaging field of view Millimeters float field of view 1 field of view 1 2 #NAME? +MRI acquisition 3 7 Matrix size for MRI acquisition integer matrix size 1 matrix size 1 2 #NAME? +MRI acquisition 3 8 Distance between slices (includes skip or distance factor). Millimeters float 0 slice thickness 1 slice thickness 1 1 #NAME? +MRI acquisition 3 9 The size of the skipped area between slices. Millimeters float 0 skip factor 1 skip factor 1 2 #NAME? +MRI acquisition 3 10 The orientation of slices radio axial | sagittal | frontal acquisition orientation 1 acquisition orientation 1 2 #NAME? +MRI acquisition 3 11 Order of acquisition of slices select ascending | descending | interleaved SliceTiming order of acquisition 1 order of acquisition 1 3 #NAME? +MRI acquisition 3 12 Repetition time (TR) Milliseconds float 0 RepetitionTime repetition time 1 repetition time 1 1 #NAME? +MRI acquisition 3 13 Echo time (TE) Milliseconds float 0 EchoTime echo time 1 echo time 1 1 #NAME? +MRI acquisition 3 14 Flip angle Degrees float 0 FlipAngle flip angle 1 flip angle 1 2 #NAME? +Preprocessing 4 1 If a single software package was used for all analyses, specify that here select preset:mri_softwares SoftwareName software package 1 software package 1 1 Describe your preprocessing #NAME? +Preprocessing 4 2 Version of software package used textarea SoftwareVersion software version 1 software version 1 1 #NAME? +Preprocessing 4 3 Specify order of preprocessing operations textarea order of preprocessing operations 1 order of preprocessing operations 1 2 #NAME? +Preprocessing 4 4 Describe quality control measures textarea quality control 1 quality control 1 3 #NAME? +Preprocessing 4 5 Was B0 distortion correction used? radio preset:boolean used b0 unwarping 1 used b0 unwarping 1 2 #NAME? +Preprocessing 4 6 Specify software used for distortion correction if different from the main package select preset:mri_softwares b0 unwarping software used_b0_unwarping == 1 b0 unwarping software 1 3 #NAME? +Preprocessing 4 7 Was slice timing correction used? radio preset:boolean used slice timing correction 1 used slice timing correction 1 1 #NAME? +Preprocessing 4 8 Specify software used for slice timing correction if different from the main package select preset:mri_softwares slice timing correction software used_slice_timing_correction == 1 slice timing correction software 1 3 #NAME? +Preprocessing 4 9 Was motion correction used? radio preset:boolean used motion correction 1 used motion correction 1 1 #NAME? +Preprocessing 4 10 Specify software used for motion correction if different from the main package select preset:mri_softwares motion correction software used_motion_correction == 1 motion correction software 1 3 #NAME? +Preprocessing 4 11 Reference scan used for motion correction textarea motion correction reference used_motion_correction == 1 motion correction reference 1 3 #NAME? +Preprocessing 4 12 Similarity metric used for motion correction select preset:cost_functions motion correction metric used_motion_correction == 1 motion correction metric 1 3 #NAME? +Preprocessing 4 13 Interpolation method used for motion correction select preset:interpolations motion correction interpolation used_motion_correction == 1 motion correction interpolation 1 3 #NAME? +Preprocessing 4 14 Was motion-susceptibility correction used? radio preset:boolean used motion susceptibiity correction 1 used motion susceptibiity correction 1 3 #NAME? +Intersubject registration 5 1 Were subjects registered to a common stereotactic space? radio preset:boolean used intersubject registration 1 used intersubject registration 1 1 Describe your spatial normalization #NAME? +Intersubject registration 5 2 Specify software used for intersubject registration if different from main package select preset:mri_softwares intersubject registration software used_intersubject_registration == 1 intersubject registration software 1 2 #NAME? +Intersubject registration 5 3 Was linear or nonlinear registration used? select linear | non-linear intersubject transformation type used_intersubject_registration == 1 intersubject transformation type 1 1 #NAME? +Intersubject registration 5 4 If nonlinear registration was used, describe transform method textarea nonlinear transform type used_intersubject_registration == 1 and nonlinear_transform_type == 1 nonlinear transform type 1 2 #NAME? +Intersubject registration 5 5 Similarity metric used for intersubject registration textarea transform similarity metric used_intersubject_registration == 1 transform similarity metric 1 3 #NAME? +Intersubject registration 5 6 Interpolation method used for intersubject registration select preset:interpolations interpolation method used_intersubject_registration == 1 interpolation method 1 2 #NAME? +Intersubject registration 5 7 What type of image was used to determine the transformation to the atlas? textarea object image type used_intersubject_registration == 1 object image type 1 1 #NAME? +Intersubject registration 5 8 Were the functional images coregistered to the subject's structural image? radio preset:boolean functional coregistered to structural 1 functional coregistered to structural 1 2 #NAME? +Intersubject registration 5 9 Method used to coregister functional to structural images textarea functional coregistration method functional_coregistered_to_structural == 1 functional coregistration method 1 3 #NAME? +Intersubject registration 5 10 Name of coordinate space for registration target select MNI | Talairach | MNI2Tal | other coordinate space 1 coordinate space 1 1 #NAME? +Intersubject registration 5 11 Name of target template image textarea target template image 1 target template image 1 2 #NAME? +Intersubject registration 5 12 Voxel size of target template Millimeters float 0 target resolution 1 target resolution 1 1 #NAME? +Intersubject registration 5 13 Was spatial smoothing applied? radio preset:boolean used smoothing 1 used smoothing 1 1 #NAME? +Intersubject registration 5 14 Describe the type of smoothing applied textarea smoothing type used_smoothing == 1 smoothing type 1 1 #NAME? +Intersubject registration 5 15 The full-width at half-maximum of the smoothing kernel Millimeters float 0 smoothing fwhm used_smoothing == 1 smoothing fwhm 1 1 #NAME? +Intersubject registration 5 16 Voxel size in mm of the resampled, atlas-space images float 0 resampled voxel size 1 resampled voxel size 1 1 #NAME? +Individual subject modeling 6 1 Type of group model used radio Regression | other intrasubject model type 1 intrasubject model type 1 1 Describe your model specification at the subejct level #NAME? +Individual subject modeling 6 2 Estimation method used for model select ordinary least squares | generalized least squares | other intrasubject estimation type 1 intrasubject estimation type 1 1 #NAME? +Individual subject modeling 6 3 Software used for intrasubject modeling if different from overall package select preset:mri_softwares intrasubject modeling software 1 intrasubject modeling software 1 2 #NAME? +Individual subject modeling 6 4 Nature of HRF model select spm HRF | glover HRF | double gamma | Fourrier set | Finite Impulse Response | FLOBS | other hemodynamic response function 1 hemodynamic response function 1 2 #NAME? +Individual subject modeling 6 5 Were temporal derivatives included? radio preset:boolean used temporal derivatives 1 used temporal derivatives 1 2 #NAME? +Individual subject modeling 6 6 Were dispersion derivatives included? radio preset:boolean used dispersion derivatives 1 used dispersion derivatives 1 3 #NAME? +Individual subject modeling 6 7 Were motion regressors included? radio preset:boolean used motion regressors 1 used motion regressors 1 2 #NAME? +Individual subject modeling 6 8 Was a reaction time regressor included? radio preset:boolean used reaction time regressor 1 used reaction time regressor 1 2 #NAME? +Individual subject modeling 6 9 Were any regressors specifically orthogonalized with respect to others? radio preset:boolean used orthogonalization 1 used orthogonalization 1 1 #NAME? +Individual subject modeling 6 10 If orthogonalization was used, describe here textarea orthogonalization description used_orthogonalization == 1 orthogonalization description 1 2 #NAME? +Individual subject modeling 6 11 Was high pass filtering applied? radio preset:boolean used high pass filter 1 used high pass filter 1 1 #NAME? +Individual subject modeling 6 12 Describe method used for high pass filtering textarea high pass filter method used_high_pass_filter == 1 high pass filter method 1 2 #NAME? +Individual subject modeling 6 13 What autocorrelation model was used ? select SPM: global approximate AR(1) | SPM: FAST | FSL: locally regularized autocorrelation function | AFNI: ARMA | none | other autocorrelation model 1 autocorrelation model 1 2 #NAME? +Individual subject modeling 6 14 Exactly what terms are subtracted from what? textarea contrast definition 1 contrast definition 1 1 #NAME? +Individual subject modeling 6 15 Link to Cognitive Atlas definition of this contrast Define these in terms of task or stimulus conditions (for example 'one-back task with objects versus zero-back task with objects') instead of underlying psychological concepts (for example 'working memory'). textarea contrast definition cogatlas 1 contrast definition cogatlas 1 3 #NAME? +Group modeling 7 1 Type of group model used select Regression group model type 1 group model type 1 1 Describe the group level analysis #NAME? +Group modeling 7 2 Estimation method used for model select ordinary least squares | generalized least squares | other group estimation type 1 group estimation type 1 1 #NAME? +Group modeling 7 3 Software used for group modeling if different from overall package select preset:mri_softwares group modeling software 1 group modeling software 1 2 #NAME? +Group modeling 7 4 Type of inference for group model select random effect | mixed effect | fixed effect group inference type 1 group inference type 1 1 #NAME? +Group modeling 7 5 If more than 2-levels, describe the levels and assumptions of the model. For example, are variances assumed equal between groups. textarea group model multilevel 1 group model multilevel 1 3 #NAME? +Group modeling 7 6 Was this a repeated measures design at the group level? radio preset:boolean group repeated measures 1 group repeated measures 1 1 #NAME? +Group modeling 7 7 If multiple measurements per subject, list method to account for within subject correlation, exact assumptions made about correlation/variance textarea group repeated measures method group_repeated_measures == 1 group repeated measures method 1 3 #NAME? +Group inference 8 1 Type of statistic that is the basis of the inference select Z | T | F | X2 | PostProb | Non-parametric Permutations | Monte Carlo Permutations | other group statistic type 1 group statistic type 1 2 Describe your statistical inference #NAME? +Group inference 8 2 Parameters of the null distribution of the test statisic. Typically degrees of freedom (should be clear from the test statistic what these are). float group statistic parameters 1 group statistic parameters 1 1 #NAME? +Group inference 8 3 Noise smoothness for statistical inference This is the estimated smoothness used with Random Field Theory or a simulation-based inference method. float 0 group smoothness fwhm 1 group smoothness fwhm 1 1 #NAME? diff --git a/ecobidas/inputs/reexecution/reexecution.tsv b/ecobidas/inputs/reexecution/reexecution.tsv index 56c6a8da..05adfd49 100644 --- a/ecobidas/inputs/reexecution/reexecution.tsv +++ b/ecobidas/inputs/reexecution/reexecution.tsv @@ -20,7 +20,7 @@ include activity_pref_label activity_order item_order item item_pref_label item_ 1 analysis 3 6 preprocessing_parameters_specified preprocessing parameters specified preprocessing parameters specified 1 1 Are the detailed processing parameters specified? radio yes | some details provided | no 1 analysis 3 7 analysis_reexecutable analysis reexecutable analysis reexecutable 1 1 Do you think a reasonably skilled image analyst could re-execute this analysis (including getting the specified versions of the tools and operating system indicated)? radio yes | approximately | no | I am not sure 1 statistics 4 1 statistical_tools_specified statistical tools specified statistical tools specified 1 1 Are the statistical tools / packages specified? radio preset:boolean -1 statistics 4 2 statitical_tools_and_versions statitical tools and versions statitical tools and versions 1 statistical_tools_specified == 1 List the tools and versions indicated (i.e. Stata 5.0). If more than one tool used, use a new line for each tool. textarea +1 statistics 4 2 statistical_tools_and_versions statistical tools and versions statistical tools and versions 1 statistical_tools_specified == 1 List the tools and versions indicated (i.e. Stata 5.0). If more than one tool used, use a new line for each tool. textarea 1 statistics 4 3 statistics_OS_specified statistics OS specified statistics OS specified 1 1 Is the operating system used for the statistical tool(s) specified? radio preset:boolean 1 statistics 4 4 statistics_OS_class statistics OS class statistics OS class 0 statistics_OS_specified == 1 Which class of operating system was indicated for the statistical analysis? radio preset:operating_systems 1 statistics 4 5 statistics_OS_details statistics OS details statistics OS details 0 statistics_OS_specified == 1 Describe the operating system details (i.e. specific version) provided (i.e. MacOS 10.12.6). textarea diff --git a/mkdocs.yml b/mkdocs.yml index 4ae36e18..b1357869 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -93,14 +93,14 @@ markdown_extensions: - md_in_html - pymdownx.details - pymdownx.emoji: - emoji_generator: !%21python/name:material.extensions.emoji.to_svg - emoji_index: !%21python/name:material.extensions.emoji.twemoji + emoji_generator: !!python/name:material.extensions.emoji.to_svg + emoji_index: !!python/name:material.extensions.emoji.twemoji - pymdownx.snippets - pymdownx.superfences: custom_fences: - name: mermaid class: mermaid - format: !%21python/name:pymdownx.superfences.fence_code_format + format: !!python/name:pymdownx.superfences.fence_code_format - tables - toc: anchorlink: true From 312e831d61f8edab38a7f88250bfa401c26cb180 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Tue, 28 May 2024 16:01:15 +0200 Subject: [PATCH 29/31] update precommit --- .pre-commit-config.yaml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 607d7d6c..f4162e95 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -84,12 +84,6 @@ repos: - id: prettier types_or: [css, html, json] -# Check formatting HTML / Jinja -# - repo: https://github.com/thibaudcolas/curlylint - # rev: v0.13.1 - # hooks: - # - id: curlylint - # Check that Python code complies with PEP8 guidelines # flake8 uses pydocstyle to check docstrings: https://flake8.pycqa.org/en/latest/ # flake8-docstrings: https://pypi.org/project/flake8-docstrings/ From 0041650af4298af9b3e6dd71f865554ee1a1e8f4 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Tue, 28 May 2024 16:11:27 +0200 Subject: [PATCH 30/31] drop reproschema-ui --- .gitmodules | 4 ---- reproschema-ui | 1 - 2 files changed, 5 deletions(-) delete mode 160000 reproschema-ui diff --git a/.gitmodules b/.gitmodules index 319563bd..105e508b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -9,7 +9,3 @@ [submodule "reproschema-py"] path = reproschema-py url = https://github.com/Remi-Gau/reproschema-py.git -[submodule "reproschema-ui"] - path = reproschema-ui - url = https://github.com/Remi-Gau/reproschema-ui.git - datalad-url = https://github.com/Remi-Gau/reproschema-ui.git diff --git a/reproschema-ui b/reproschema-ui deleted file mode 160000 index eb11cd6c..00000000 --- a/reproschema-ui +++ /dev/null @@ -1 +0,0 @@ -Subproject commit eb11cd6ce4ad250e4bf053cfe2932b466190ac73 From e279d5dec0fd340e9018c0a755c20b8c8441f6df Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Tue, 28 May 2024 16:15:09 +0200 Subject: [PATCH 31/31] fix tests --- tests/test_item.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_item.py b/tests/test_item.py index acc7c78b..86d6500e 100644 --- a/tests/test_item.py +++ b/tests/test_item.py @@ -39,7 +39,7 @@ def test_preset(): @pytest.mark.parametrize( - "input, expected", + "input_str, expected", [ ("_i[t]em-n:a m!e", "_item-na_me"), # alphanumeric with _ and - only ("item name", "item_name"), @@ -164,7 +164,7 @@ def test_get_item_info_with_only_name(): @pytest.mark.parametrize( - "input, expected", + "input_value, expected", [ (float("nan"), True), ("1", True),