GithubHelp home page GithubHelp logo

kitwaremedical / slicerehrsandbox Goto Github PK

View Code? Open in Web Editor NEW
0.0 12.0 3.0 385 KB

Slicer extension for reading EHR data from a FHIR server and a DICOMweb server.

License: Apache License 2.0

CMake 7.15% Python 92.85%
3d-slicer-extension lungair kitware

slicerehrsandbox's Introduction

SlicerEHRSandbox

UNDER DEVELOPMENT

Slicer extension for reading EHR data from a FHIR server and DICOM data from a DICOMweb server.

Tutorial

  1. SlicerEHRSandbox requires a FHIR server and a DICOMweb server. If you are missing either, go to the FHIR Server section for a missing FHIR server and the DICOMweb Server section for a missing DICOMweb server.
  2. Place the url of your FHIR server into the FHIR Server textbox and (if available) place the url of your DICOMweb server into the DICOMweb server textbox. It is important to note the url should end with hapi-fhir-jpaserver.
  3. Press the Connect and Load Patients button.
  4. The Patient Browser list will be populated with all patients in the FHIR server. Double click a patient to load observations and DICOM studies.
  5. The Patient Information table (left table) will populate with patient information from the FHIR server. The Observation Browser and DICOM Browser will populate with associated observation types and DICOM studies respectively.
  6. Double click an obervation type. The Patient Observations table (right table) will populate with all observations of the selected type.
  7. Double click a DICOM series. The Patient DICOM slice viewer will display the DICOM image after it is downloaded from the server.

FHIR Server

If you have data without a FHIR server, it is still possible to use the extension. Using lungair-fhir-server, it is possible to create a Docker container containing a FHIR server. Consult the README on how to convert your data into a FHIR server. Once the FHIR server has been created, you can use SlicerEHRSandbox as normal.

DICOMweb Server

If you have DICOM data without a DICOMweb server, it is possible to create a DICOMweb server using Slicer using the following steps.

  1. Open another instance of Slicer.
  2. Go to the Add DICOM Data module.
  3. Press the Import DICOM Data button and select the directory with all DICOM files.
  4. Go to the Web Server module.
  5. Ensure the DICOMweb API box is checked in the Advanced tab.
  6. Press the Start Server button.
  7. Press the Open static pages in external browser button. This will give you url the web server is hosted at.
  8. Add /dicom to the end of the url for the DICOM endpoint. This will be the url to put in the DICOMweb server textbox.

Please note that the Patient ID value in Slicer's DICOM database needs to be the same ID value in the first identifier value inside the the FHIR server. More information about identifier can be found here. If the values do not match up:

  1. Load the affected patient's series into Slicer.
  2. Delete the same patients from the DICOM database.
  3. Right click each series and select Export to DICOM....
  4. Change the PatientID value to match the value in FHIR.
  5. Press the Export button.
  6. Repeat for all series.

You can the continue from step 4 in the first set of DICOMweb server instructions.

Screenshots

SlicerEHRSandbox in use

License

This software is licensed under the terms of the Apache Licence Version 2.0.

The license file was added at revision 1dea689 on 2022-11-17, but you may consider that the license applies to all prior revisions as well.

slicerehrsandbox's People

Contributors

jcfr avatar stephencrowell avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

slicerehrsandbox's Issues

make tables not editable

The patient and observation tables are currently editable in the UI. It doesn't affect the actual data; it's just that the table nodes provide editable cells. We can just lock the tables; e.g. see here

rename UI elements

image

In the above "Inputs" should be something like "Networking Information" or "Connection Info" etc.

and "Apply" should probably be "Load patients"

add correct description material throughout extension and repo

Currently we are still using all the default extension metadata and we have a placeholder project name; we should

  • Name the extension; the name should be SlicerSomething. Maybe SlicerEHRSandbox or something like that.
  • Rename the repo accordingly (SlicerSomething) and give it the tags "lungair" and "3d-slicer-extension"
  • Put in the extension and module metadata a brief description, reference to the contributors (stephen, ebrahim, andinet) and acknowledgement of the grant (NIH award R42HL145669).
  • Create an icon for the extension and for the module
  • Choose the correct category for this extension (currently it's the default "Examples")
  • [ ] Package the application, creating a tagged commit and release object No need to actually do this yet, but I created #19 to track ensuring that we are able to create a package when we are ready to make a release.
  • Put some more info in the readme about how to install and use the extension. We should probably link up to lungair-fhir-server and perhaps rename that repo accordingly
  • Move this repo to KitwareMedical and give it the tag "kitware"

name/create/destroy/reuse mrml nodes appropriately

after loading the patient info from the server a bunch of times and querying a bunch of different observations, the data module shows table nodes all over the place:

image

we should destroy or re-use table nodes appropriately (e.g. when patient info is re-loaded from the sever, we should not create a new PatientInfo_TableNode without destroying the old one)

We should name the observation table nodes more informatively, perhaps sometimes allowing ourselves to re-use existing observation table nodes rather than reloading data.

built package does not contain layout

Probably a similar issue to #19 -- the following was encountered when installing from a built package:

Traceback (most recent call last):
  File "/home/ebrahim/Downloads/Slicer-5.1.0-2022-07-17-linux-amd64/NA-MIC/Extensions-31083/SlicerEHRReader/lib/Slicer-5.1/qt-scripted-modules/FHIRReader.py", line 192, in setup
    with open(self.resourcePath('fhir-layout.xml')) as fh:
FileNotFoundError: [Errno 2] No such file or directory: '/home/ebrahim/Downloads/Slicer-5.1.0-2022-07-17-linux-amd64/NA-MIC/Extensions-31083/SlicerEHRReader/lib/Slicer-5.1/qt-scripted-modules/Resources/fhir-layout.xml'

Change Icons

Change icons to text saying "Slicer EHR Sandbox" and a simple fire logo.

Add LICENSE

@stephencrowell

It is great to see all the work you have done so far 💯

That said the project seems to be missing a license file. 😱

No worry, I suggest you follow these few steps:

  • 1️⃣ Choose a license. We suggest you use a permissive license that includes patent and contribution clauses. This will help protect developers and ensure the code remains freely available. We suggest you the Apache 2.0. Read here to learn more about licenses.

  • 2️⃣ Add the the license file to your project. This guide may be helpful.

  • 3️⃣ Add a section like the following at the end of your project's README.md file:

    ⚠️ Make sure to update the abcdefghi and YYYY-MM-DD placeholders respectively with the short commit SHA and the commit date corresponding to step 2 above

    ## License
    
    This software is licensed under the terms of the [Apache Licence Version 2.0](LICENSE).
    
    The license file was added at revision [abcdefghi](https://github.com/Slicer/slicer_download/commit/abcdefghi) on YYYY-MM-DD, but you may consider that the license applies to all prior revisions as well.
    

Background

Without a license file, interpreting the licensing terms becomes complex. In a nutshell, code hosted on GitHub without a license is likely made available through section D. 5. License Grant to Other Users of the GitHub terms of service.

Reading issue github/choosealicense.com#196 (No license" does not allow commercial or private use) is also informative.

Links

Description Link
Which open source license is appropriate for my project? https://opensource.guide/legal/#which-open-source-license-is-appropriate-for-my-project
Adding a license to a repository https://docs.github.com/en/communities/setting-up-your-project-for-healthy-contributions/adding-a-license-to-a-repository
All About Open Source Licenses https://fossa.com/blog/what-do-open-source-licenses-even-mean/
Choose an open source license https://choosealicense.com/
No License https://choosealicense.com/no-permission/

Disclaimers

I am not a lawyer. As such, my suggestions can not serve as legal advice.


This comment was adapted from my GitHub saved replies, it is licensed under a Creative Commons Attribution 4.0 International License and you are welcome to reuse it. Creative Commons License

patient/obs widgets don't interact well with the rest of slicer

Currently (and this is referring to display-patient-and-observation branch) if we switch to the FHIRReader module then the current layout is replaced by the layout that shows the patient/obs widgets. If I then want to use the slice views then I can do that by changing the layout, e.g. View -> Layout -> Four-Up. Once I do that there seems to be no way to get the patient/obs widgets back, not even by switching out of and back into the FHIRReader module. There are really two issues here:

  1. (Broken behavior) If we switch into FHIRReader module then change the layout manually, then there's seems to be no way to recover the FHIRReader module's initial layout.
  2. (Inconvenient behavior) If we switch into FHIRReader module then our layout is replaced, but switching out of FHIRReader module doesn't revert the layout to what we had before. That's a bit annoying. Not sure how to deal with it.
    a. I wonder if we can switch to something more like how the DICOM browser works, where it just lets you toggle between viewing a dicom data display widget versus the usual underlying layout on the right side.
    b. Probably this is not the first time someone deals with this so it's worth looking into other solutions before complicating things too much.

Re-organize and cleanup extension files

Remove __pycache__ directory

Directories like FHIRReader/FHIRReader/__pycache__ should not be part of the project.

Add CMakeLists.txt and module directory at the top-level

To follow established convention for Slicer extensions, consider having the CMakeLists.txt and module directory available in the top-level directory.

Instead of the following structure:

FHIRReader
FHIRReader/CMakeLists.txt
FHIRReader/FHIRReader
FHIRReader/FHIRReader/CMakeLists.txt
FHIRReader/FHIRReader/FHIRReader.py
FHIRReader/FHIRReader/Resources
FHIRReader/FHIRReader/Resources/Icons
FHIRReader/FHIRReader/Resources/Icons/FHIRReader.png
FHIRReader/FHIRReader/Resources/UI
FHIRReader/FHIRReader/Resources/UI/FHIRReader.ui
FHIRReader/FHIRReader/Testing
FHIRReader/FHIRReader/Testing/CMakeLists.txt
FHIRReader/FHIRReader/Testing/Python
FHIRReader/FHIRReader/Testing/Python/CMakeLists.txt
FHIRReader/FHIRReader.png
README.md

I suggest to re-organize files to have the following:

CMakeLists.txt
FHIRReader
FHIRReader/CMakeLists.txt
FHIRReader/FHIRReader.py
FHIRReader/Resources
FHIRReader/Resources/Icons
FHIRReader/Resources/Icons/FHIRReader.png
FHIRReader/Resources/UI
FHIRReader/Resources/UI/FHIRReader.ui
FHIRReader/Testing
FHIRReader/Testing/CMakeLists.txt
FHIRReader/Testing/Python
FHIRReader/Testing/Python/CMakeLists.txt
FHIRReader.png
README.md

Examples:

initial layout is not remembered

This is related to #4

If I switch into the FHIRReader module, change the layout manually, and then switch out of the module, then the layout behavior is correct from there on out. i.e. switching into FHIRReader change the layout to show patient info, and switching out reverts the layout properly.

However that correct behavior is not there initially.

  • Launch Slicer
  • Switch into and then out of the FHIRReader module
  • We see that after switching out, the patient info widgets are still there and the layout has not been reverted to the initial slicer layout

Add busy cursor

During times when the extension is reading data from FHIR server or installing python dependencies, make use of busy cursor as show here.

Handle python dependency installation

Currently (and this is referring to the display-patient-and-observation branch) when I add the module to Slicer, the module fails to load with the following error:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/home/ebrahim/Downloads/Slicer-5.1.0-2022-07-17-linux-amd64/lib/Python/lib/python3.9/imp.py", line 169, in load_source
    module = _exec(spec, sys.modules[name])
  File "<frozen importlib._bootstrap>", line 613, in _exec
  File "<frozen importlib._bootstrap_external>", line 850, in exec_module
  File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
  File "/home/ebrahim/fhir-slicer-extension/FHIRReader/FHIRReader/FHIRReader.py", line 11, in <module>
    from fhirclient import client
ModuleNotFoundError: No module named 'fhirclient'

Not surprising-- I haven't installed fhirclient. This will go away when I install it.

But we need to include installing the dependency in a more elegant way and not require the user to fiddle with the python console.

I don't know if this is the best way, but here is an example of what I did in the lungair module:

add layout in "setup" rather than "enter"

I had a thought while working on #9 yesterday. Should we be initialing the layout every time we enter? If we save the layout ID for the extension, can't we just set the layout to ID and then only initialize once? #9 has an issue where whenever we switch between different modules we create new TableNodes and I was wondering if this could be part of the reason.

Originally posted by @stephencrowell in #4 (comment)

search feature for patients list

When the list of patients becomes large it makes sense to interact with it by lookup rather than scrolling.
Patients could be searched by name.

It may be good to also have the search feature for observation types, so the patient search feature could be designed with that generalization in mind.

GitHub UI: Reduce noise

To remove the "noise" associated with the project, I suggest disabling the following unused features if it still applies:

Go to General settings and disable the Wiki, Projects and Discussions tabs If empty or unused, hide Releases and Packages section on the right side
GitHub: Projects & Wiki tabs GitHub: Release & Packages sections

Rational

It is just to simplify things.

For example, if user support is provided via a forum then it is better to turn off Discussions here, so that there is no need to monitor two user support sites, but only one.

If Releases and Packages are not used, so it is cleaner to hide them (to indicate that it is not the way how we manage releases and packages).

Projects feature is rarely used in general and this repository does not use it either. If the user clicks on Projects then an empty page is s displayed. It is better to not display the heading at all, to save the extra two clicks for users exploring the project.

Wiki on Github is meant to be a lighter weight tool for documentation. The issue is that it is too limited, for example contributors either can make changes directly (without pull request) or they cannot make changes at all. It also lead to write redundant content, since Github quite nicely renders markdown pages in the main repository. For small projects it is simpler and more consistent to keep all documentation in markdown files in the main repository.

Co-authored by @lassoan


This comment was adapted from my GitHub saved replies, it is licensed under a Creative Commons Attribution 4.0 International License and you were welcome to reuse it. Creative Commons License

improve dicom loading to not have to write to disk

Currently when we read an image from DICOMWeb, we have a roundabout process to turn that into a mrml node:

  • write the image to disk using pydicom
  • read the image from disk into a mrml node using DICOMLib

Can we find a way to avoid writing to disk? i.e. can we take each dicom series in memory and turn it directly into a vtkMRMLScalarVolumeNode?

remember previously used URL

Remember the previously used FHIR and DICOMWeb URLs and populate the text field with them the first time the module is entered.

We could also look into suggesting from a list of previously used URLs while the user types, if Qt makes that easy to do.

ensure that creating a package works

Regarding the creation of a release object, I have asked a question here: https://discourse.slicer.org/t/how-to-release-an-extension/26289

Here is what worked for me to create a tar.gz package out of the extension:

mkdir
cd build
cmake .. -DSlicer_DIR=/home/ebrahim/Slicer-SuperBuild/Slicer-build -DCMAKE_BUILD_TYPE:STRING=Release
make package

I was able to install it using the "Install from file" button in Slicer's extension manager.
However upon launch I got

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/home/ebrahim/Downloads/Slicer-5.1.0-2022-07-17-linux-amd64/lib/Python/lib/python3.9/imp.py", line 169, in load_source
    module = _exec(spec, sys.modules[name])
  File "<frozen importlib._bootstrap>", line 613, in _exec
  File "<frozen importlib._bootstrap_external>", line 850, in exec_module
  File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
  File "/home/ebrahim/Downloads/Slicer-5.1.0-2022-07-17-linux-amd64/NA-MIC/Extensions-31083/SlicerEHRReader/lib/Slicer-5.1/qt-scripted-modules/FHIRReader.py", line 11, in <module>
    from Utils import BusyCursor
ModuleNotFoundError: No module named 'Utils'

Looking at the copied extension files

$ ls /home/ebrahim/Downloads/Slicer-5.1.0-2022-07-17-linux-amd64/NA-MIC/Extensions-31083/SlicerEHRReader/lib/Slicer-5.1/qt-scripted-modules/

FHIRReader.py  __pycache__  Resources

we see that the `Utils' didn't get copied over.

There might be a cmake line you have to add somewhere to get this to work.

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.