GithubHelp home page GithubHelp logo

neurostuff / neurostore Goto Github PK

View Code? Open in Web Editor NEW
8.0 8.0 5.0 54.62 MB

The NeuroStore/Neurosynth application

Home Page: https://compose.neurosynth.org

Python 22.42% Dockerfile 0.28% Mako 0.09% Shell 0.33% HTML 0.27% TypeScript 69.86% CSS 0.12% JavaScript 6.63%

neurostore's People

Contributors

adelavega avatar dependabot[bot] avatar jdkent avatar nicoalee avatar tyarkoni avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

jdkent tsalo

neurostore's Issues

Linking Neurosynth and NeuroVault datasets

Per today's call, DOIs are the best target for linking coordinates from Neurosynth and collections from NeuroVault, but this hasn't been implemented yet. Would it be feasible to link them automatically?

can't locate revision identified by "hash"

I am having some issues with keeping the database in a good state (I think) when I run:
python manage.py db migrate`

and I get output that looks like this:

INFO  [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO  [alembic.runtime.migration] Will assume transactional DDL.
Traceback (most recent call last):
  File "/usr/local/lib/python3.8/site-packages/alembic/script/base.py", line 162, in _catch_revision_errors
    yield
  File "/usr/local/lib/python3.8/site-packages/alembic/script/base.py", line 227, in get_revisions
    return self.revision_map.get_revisions(id_)
  File "/usr/local/lib/python3.8/site-packages/alembic/script/revision.py", line 319, in get_revisions
    return sum([self.get_revisions(id_elem) for id_elem in id_], ())
  File "/usr/local/lib/python3.8/site-packages/alembic/script/revision.py", line 319, in <listcomp>
    return sum([self.get_revisions(id_elem) for id_elem in id_], ())
  File "/usr/local/lib/python3.8/site-packages/alembic/script/revision.py", line 322, in get_revisions
    return tuple(
  File "/usr/local/lib/python3.8/site-packages/alembic/script/revision.py", line 323, in <genexpr>
    self._revision_for_ident(rev_id, branch_label)
  File "/usr/local/lib/python3.8/site-packages/alembic/script/revision.py", line 386, in _revision_for_ident
    raise ResolutionError(
alembic.script.revision.ResolutionError: No such revision or branch 'e6192a6cd3b4'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "manage.py", line 50, in <module>
    manager.run()
  File "/usr/local/lib/python3.8/site-packages/flask_script/__init__.py", line 417, in run
    result = self.handle(argv[0], argv[1:])
  File "/usr/local/lib/python3.8/site-packages/flask_script/__init__.py", line 386, in handle
    res = handle(*args, **config)
  File "/usr/local/lib/python3.8/site-packages/flask_script/commands.py", line 216, in __call__
    return self.run(*args, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/flask_migrate/__init__.py", line 180, in migrate
    command.revision(config, message, autogenerate=True, sql=sql,
  File "/usr/local/lib/python3.8/site-packages/alembic/command.py", line 214, in revision
    script_directory.run_env()
  File "/usr/local/lib/python3.8/site-packages/alembic/script/base.py", line 489, in run_env
    util.load_python_file(self.dir, "env.py")
  File "/usr/local/lib/python3.8/site-packages/alembic/util/pyfiles.py", line 98, in load_python_file
    module = load_module_py(module_id, path)
  File "/usr/local/lib/python3.8/site-packages/alembic/util/compat.py", line 184, in load_module_py
    spec.loader.exec_module(module)
  File "<frozen importlib._bootstrap_external>", line 783, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "/migrations/migrations/env.py", line 87, in <module>
    run_migrations_online()
  File "/migrations/migrations/env.py", line 80, in run_migrations_online
    context.run_migrations()
  File "<string>", line 8, in run_migrations
  File "/usr/local/lib/python3.8/site-packages/alembic/runtime/environment.py", line 846, in run_migrations
    self.get_context().run_migrations(**kw)
  File "/usr/local/lib/python3.8/site-packages/alembic/runtime/migration.py", line 509, in run_migrations
    for step in self._migrations_fn(heads, self):
  File "/usr/local/lib/python3.8/site-packages/alembic/command.py", line 190, in retrieve_migrations
    revision_context.run_autogenerate(rev, context)
  File "/usr/local/lib/python3.8/site-packages/alembic/autogenerate/api.py", line 442, in run_autogenerate
    self._run_environment(rev, migration_context, True)
  File "/usr/local/lib/python3.8/site-packages/alembic/autogenerate/api.py", line 453, in _run_environment
    if set(self.script_directory.get_revisions(rev)) != set(
  File "/usr/local/lib/python3.8/site-packages/alembic/script/base.py", line 227, in get_revisions
    return self.revision_map.get_revisions(id_)
  File "/usr/local/lib/python3.8/contextlib.py", line 131, in __exit__
    self.gen.throw(type, value, traceback)
  File "/usr/local/lib/python3.8/site-packages/alembic/script/base.py", line 194, in _catch_revision_errors
    compat.raise_from_cause(util.CommandError(resolution))
  File "/usr/local/lib/python3.8/site-packages/alembic/util/compat.py", line 308, in raise_from_cause
    reraise(type(exception), exception, tb=exc_tb, cause=exc_value)
  File "/usr/local/lib/python3.8/site-packages/alembic/util/compat.py", line 301, in reraise
    raise value.with_traceback(tb)
  File "/usr/local/lib/python3.8/site-packages/alembic/script/base.py", line 162, in _catch_revision_errors
    yield
  File "/usr/local/lib/python3.8/site-packages/alembic/script/base.py", line 227, in get_revisions
    return self.revision_map.get_revisions(id_)
  File "/usr/local/lib/python3.8/site-packages/alembic/script/revision.py", line 319, in get_revisions
    return sum([self.get_revisions(id_elem) for id_elem in id_], ())
  File "/usr/local/lib/python3.8/site-packages/alembic/script/revision.py", line 319, in <listcomp>
    return sum([self.get_revisions(id_elem) for id_elem in id_], ())
  File "/usr/local/lib/python3.8/site-packages/alembic/script/revision.py", line 322, in get_revisions
    return tuple(
  File "/usr/local/lib/python3.8/site-packages/alembic/script/revision.py", line 323, in <genexpr>
    self._revision_for_ident(rev_id, branch_label)
  File "/usr/local/lib/python3.8/site-packages/alembic/script/revision.py", line 386, in _revision_for_ident
    raise ResolutionError(
alembic.util.exc.CommandError: Can't locate revision identified by 'e6192a6cd3b4'

and the only surefire way I have been able to resolve the issue is by [removing the volume](docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d) and starting over from:
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d

Is there a better way I should be trying to correct for these kinds of errors?

keep track of provenance of search terms

When a user searches for studies to include in a dataset, there should be some way to track what those search terms were and what results were included from those search terms.

provenance of analysis creation process

from meeting with @62442katieb , one suggestion was to allow the tracking of the search process that led to the inclusion/exclusion of specific studies.

often, reviewers want to know what the inclusion/exclusion criteria was for a meta-analysis.

this is low priority for now but an idea for the future.

Automatically generate client typescript library from openapi spec

https://github.com/OpenAPITools/openapi-generator

We can generate a client library for the site from the speciifcation so we don't have to roll our own. I tested using typescript-fetch on the specification in the submodule commit and its almost there. Errors generated were:

Errors:
-attribute components.schemas.analysis.items is missing
-attribute components.schemas.study.items is missing

Can generate the library using the --skip-validate-spec. Haven't tested importing and using the generated code yet.

@jdkent @nicoalee What do y'all think?

add total unique count

total_count would indicate all clones as well as parent study, calculate the unique count as well.

Add Login

allow people to login so they can edit studies and have the studies be linked to them.

conceptual issues:

  • how should we link across different platforms?
    • if someone ran several analyses in neuroscout and wants to run a meta-analysis using neurosynth, and needs to curate the analyses listed on neurovault into neurostore.
    • 4 potential accounts that need to be linked.
      • neuroscout
      • neurosynth
      • neurovault
      • neurostore

implementation issues:

Relationship between Dataset and MetaAnalysis?

The MetaAnalysis database currently does not appear to reference the Dataset database, but in my mind I think MetaAnalysis should have an explicit relationship with the Dataset database, since the meta-analysis will perform operations on a dataset object. I'm probably missing something in my thought process.

class MetaAnalysis(BaseMixin, db.Model):
__tablename__ = "metaanalyses"
name = db.Column(db.Text)
desc = db.Column(db.Text)
estimator = db.Column(db.Text)
estimator_options = db.Column(db.JSON)
variable_names = db.Column(db.JSON)
variable_descs = db.Column(db.JSON)
data = db.Column(db.JSON)
user_id = db.Column(db.Text, db.ForeignKey("users.id"), primary_key=True)
user = relationship("User", backref=backref("metaanalyses"))
images = association_proxy("metanalysis_images", "image")
points = association_proxy("metanalysis_points", "point")
image_weights = association_proxy("metanalysis_images", "weight")
point_weights = association_proxy("metanalysis_points", "weight")

Should data in MetaAnalysis have the same content as nimads_data in Dataset?

class Dataset(BaseMixin, db.Model):
__tablename__ = "datasets"
name = db.Column(db.String)
description = db.Column(db.String)
publication = db.Column(db.String)
doi = db.Column(db.String)
pmid = db.Column(db.String)
public = db.Column(db.Boolean, default=True)
nimads_data = db.Column(db.JSON)
user_id = db.Column(db.Text, db.ForeignKey("users.id"))
user = relationship("User", backref=backref("datasets"))

If nimads_data already contains the studies/analyses/points/images necessary for the meta-analysis, does this section contain redundant information?

images = association_proxy("metanalysis_images", "image") 
points = association_proxy("metanalysis_points", "point") 
image_weights = association_proxy("metanalysis_images", "weight") 
point_weights = association_proxy("metanalysis_points", "weight") 

Alternative to flask-restful

Looks like we're using flask-restful for setting up API routes.

The project is pretty dead, and doesn't actually create any swagger-docs.

In fact, the author of the project even suggests alternative, as he himself uses other projects: flask-restful/flask-restful#883

I say we abandon ship now, and get on something maintained, before we get in too deep. Even just using Flasks regular MethodView would work.

Organization of neurostore/neurosynth APIs

How should the API endpoints on neurostore/neurosynth be organized?

  • Option1:

    • neurostuff.org/store/api/v1
    • neurostuff.org/synth/api/v1
    • neurostuff.org/auth
    • Pros:
      • Keeps all applications under same domain, so JWTs authenticate under the same domain
      • Keeps the APIs (and documentation separate
      • Domain name is general purpose
    • Cons:
      • No branding recognition
  • Option2:

    • neurosynth.org/store/api/v1
    • neurosynth.org/synth/api/v1
    • neurosynth.org/auth
    • Pros:
      • Keeps all applications under same domain, so JWTs authenticate under the same domain
      • Keeps the APIs separate
      • Domain name leverages branding from neurosynth
    • Cons:
      • People may not recognize neurostore as being general purpose
  • Option 3:

    • neurostore.org/api/v1
    • neurosynth.org/api/v1
    • Pros:
      • Most modular design/separation of services
    • Cons:
      • Cross domain authentication is hard
  • Option 4

    • neurostuff.org/store/api/v1
    • neurostuff.org/auth/api/v1
    • neurosynth.org/api/v1

    Under this division, Store and Synth would keep separate User tables with joint identities.
    Users would got to /auth and get JWT which store and auth can both authenticate.
    We can look into making /auth a proper authentication service.

    • Pros:
      • Let's neurostore be a separate service from neurosynth branding, and allows for a generic authentication service
    • Cons:
      • Potential CORS issues (can hide this from user though)

rename services in docker-compose

change nginx to neurostore_nginx
change pgsql to neurostore_pgsql

This prevents conflicts between all services running concurrently with nginx-proxy.

Tag table

one could tag analyses with certain terms to make them more easily searchable, could also be useful for collections like all the studies automatically ingested with neurosynth to be tagged with neurosynth.

Enable travis

Since this is private repo, we'd have to pay, so we won't see it for now, but the yml file is ready.

Add argument validation

I'm looking into using webargs (based on Marshmallow) for validation, with a way that works with the current abstraction hierarchy.

cannot see application running from localhost

I followed up to:

docker-compose build
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d

in initializing backend, but when I visited http://localhost/ I got "webpage not found":
not_found

and when I specified the 8000 port specifically, I was told the connection is refused.
connection_refused

I'm trying to use wsl2 on windows so something there may be the source of my issues, but I wanted to confirm you can access a webpage on your machine before I go down the wsl2-windows rabbit hole.

Docker version 19.03.12, build 48a66213fe

Move to Python 3.8

In Docker and (later) travis. No need to worry about other users since it's mostly just us.

How to Authenticate

Use only SSO from various providers Flask-Dance

To communicate between services we have a few options:

  • If everything is public, but unlisted, can just access without auth
  • Cache credentials and use that to access protected routes
  • Have a common secret and secret routes for between service authentication (preferred for now)

For now, let's commit to not having a neurostuff OAuth

What would a valid Dataset endpoint look like?

would a dataset endpoint essentially be a list of studies like in /api/studies, but for a specific subset?
What would a simple example of NIMADS data look like?

Something like

{
    "name": "my dataset",
    "description": "my collection of studies about ice cream",
    "publication": null,
    "doi": null,
    "pmid": null,
    "nimads_data": {
        "dataset": [
            {
    "analysis": [
    {
      "condition": [],
      "created_at": "2021-04-13T04:26:25.223113+00:00",
      "description": null,
      "id": "http://neurostore.org/api/analyses/5xqi2gdvTQbK",
      "image": [],
      "name": "20356",
      "point": [
        {
          "analysis": "http://neurostore.org/api/analyses/5xqi2gdvTQbK",
          "coordinates": [
            63.0,
            65.0,
            1.0
          ],
          "created_at": "2021-04-13T04:26:25.223113+00:00",
          "id": "http://neurostore.org/api/points/SwFJeP9xTQnS",
          "image": null,
          "kind": "unknown",
          "label_id": null,
          "space": "UNKNOWN",
          "value": []
        }
      ],
      "study": "http://neurostore.org/api/studies/3vnm4gctCpAH",
      "weight": []
    }
  ],
  "description": null,
  "doi": "10.1016/S0926-6410(97)00020-7",
  "id": "http://neurostore.org/api/studies/3vnm4gctCpAH",
  "metadata": null,
  "name": "Functional magnetic resonance imaging of category-specific cortical activation: evidence for semantic maps.",
  "pmid": null,
  "publication": null
}
        ],
    }, 
    "user_id": 123,
    "user": "james"
}

questions:

  • should the data under nimads_data be in JSON-LD form?
    • If we are not using JSON-LD yet, would looking at a study with api/studies/<some-study>?nested=true be a good approximation for now?
  • Are the doi, pmid and other identifying keys are assuming the dataset exists in some published form?
  • would it be appropriate to interpret a dataset as a subset of the entries in /api/studies?

authentication/login discussion

related to #32

IMG_20210518_152743
To make an analysis reproducible, you need information about the statistical model, the (MRI) data, and the software used to execute the model on the data, this information is kept in a bundle (represented in json) which is proposed to be kept on neurostore as additional information attached to a particular analysis... TODO additional explanation

IMG_20210518_152734

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.