Skip to content

Commit

Permalink
Merge pull request #2 from ylemarechal/docs/improvements
Browse files Browse the repository at this point in the history
Find resources with complex filters or filter on many resource levels
  • Loading branch information
gacou54 authored Sep 5, 2023
2 parents f1723e0 + 53fc41e commit f0c30f8
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 100 deletions.
2 changes: 1 addition & 1 deletion docs/api/filtering.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
::: pyorthanc.filtering
::: pyorthanc._filtering
:docstring:
:members:
2 changes: 1 addition & 1 deletion docs/api/find.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
::: pyorthanc.find
::: pyorthanc._find
:docstring:
:members:
2 changes: 1 addition & 1 deletion docs/api/resources/resource.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
::: pyorthanc.resources.Resource
::: pyorthanc._resources.Resource
:docstring:
:members:
54 changes: 44 additions & 10 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,56 @@
<!-- ================================================= -->

# PyOrthanc
**PyOrthanc** is a python client for the Orthanc REST API, which fully wraps all the methods of the REST API.
Additionally, it provides many utility functions to interact with an Orthanc instance.

Python library that wraps the Orthanc REST API and facilitates the manipulation of data with several cool utilities.
What for ?

The aim of the PyOrthanc module is to easy use the Orthanc Dicom server API.
---
Install PyOrthanc
```bash
pip install pyorthanc
```
---
Then use the client:
```python
import pyorthanc

It has access to the full available Orthanc API and get the useful return without dealing with http requests.
client = pyorthanc.Orthanc('https://demo.orthanc-server.com')
patient_ids = client.get_patients()
```
Interact with connected modalities

It also allows you to find specifics series/studies/patients according to complex filters
```python
import pyorthanc

modality = pyorthanc.Modality(client, 'MY_MODALITY')
assert modality.echo()

# C-Find on modality
response = modality.query({'Level': 'Study', 'Query': {'PatientID': '*'}})

# C-Move to target modality
modality.move(response['ID'], {'TargetAet': 'target_modality'})
```
Find patients
```python
patients = pyorthanc.find_patients(client, {'PatientID': '*P001'})
for patient in patients:
patient.labels
patient.is_stable
patient.name
...
for study in patient.studies:
study.labels
study.date
...
for series in study.series:
...
for instance in series.instances:
pydicom_ds = instance.get_pydicom()
```

## [First steps](tutorial/quickstart.md#first-steps)
### [Requirements](tutorial/quickstart.md#requirements)
### [Installation](tutorial/quickstart.md#installation)
### [Getting started](tutorial/quickstart.md#getting-started)
* [Import pyorthanc library](tutorial/quickstart.md#import-pyorthanc-library)
* [Connect to Orthanc](tutorial/quickstart.md#connect-to-orthanc)
Expand All @@ -25,14 +62,11 @@ It also allows you to find specifics series/studies/patients according to comple
* [Query (C-Find) and Retrieve (C-Move) from remote modality:](tutorial/quickstart.md#query-c-find-and-retrieve-c-move-from-remote-modality)
### [Full basic examples](tutorial/quickstart.md#full-basic-examples)
* [Access instance informations](tutorial/quickstart.md#access-instance-informations)
### [Some useful commands](tutorial/quickstart.md#some-useful-commands)
* [Docker commands](tutorial/quickstart.md#docker-commands)
### [Advanced examples](tutorial/advanced.md)
* [Transfer data from a PACS to a Orthanc server](tutorial/advanced.md#transfer-data-from-a-pacs-to-a-orthanc-server)
### [Releases](releases/releases.md)
* [Lastest release : 1.12.1](releases/releases.md#lastest-release-1121)
* [Release 1.11.5](releases/releases.md#release-1115)
## [Contribute](contributing.md#contribute)
## [Contacts](contacts.md#contacts)
* [Maintainers Team](contacts.md#maintainers-team)
* [Useful links](contacts.md#useful-links)
Expand Down
175 changes: 88 additions & 87 deletions docs/tutorial/quickstart.md
Original file line number Diff line number Diff line change
@@ -1,140 +1,141 @@
# First steps

## Requirements

- [x] Python3.8

## Installation

```bash
python3 -m venv .venv
source .venv/bin/activate
pip install pyorthanc
```
## Getting started
### Import pyorthanc library
```python
import pyorthanc
```

### Connect to Orthanc
Here are some quick how to examples to use pyorthanc
```python
from pyorthanc import Orthanc

orthanc = Orthanc(url='http://localhost:8042/',
username='username',
password='password')
orthanc = Orthanc(url='http://localhost:8042/', username='orthanc', password='orthanc')
```

### Upload DICOM files to Orthanc:

```python
from pyorthanc import Orthanc

orthanc = Orthanc(url='http://localhost:8042/',
username='username',
password='password')

with open('A_DICOM_INSTANCE_PATH.dcm', 'rb') as file:
orthanc.post_instances(file.read())
orthanc.post_instances(file.read())
```
### Getting list of connected remote modalities:
```python
from pyorthanc import Orthanc
modalities = orthanc.get_modalities()
```
### Query (C-Find) and Retrieve (C-Move) from remote modality:

orthanc = Orthanc(url='http://localhost:8042/',
username='username',
password='password')
```python
from pyorthanc import Modality

orthanc.get_modalities()
```
modality = Modality(orthanc, 'modality')

# C-Echo
assert modality.echo() # Test the connection

### Find and download patients according to criteria:
# Query (C-Find) on modality
data = {'Level': 'Study', 'Query': {'PatientID': '*'}}
query_response = modality.query(data=data)

```python
from pyorthanc import Orthanc, find_patients, retrieve_and_write_patients
# Inspect the answer
answer = modality.get_query_answers()[query_response['ID']]
print(answer)

orthanc = Orthanc(url='https://demo.orthanc-server.com', username='', password='')
# Retrieve (C-Move) results of query on a target modality (AET)
modality.move(query_response['ID'], {'TargetAet': 'target_modality'})
```

### Find and download patients according to criteria:
```python
from pyorthanc import find_patients, retrieve_and_write_patients

patients = find_patients(
client=orthanc,
query={'PatientName': 'COMUNIX'} # Optional: filter with pyorthanc.Series object
query={'PatientName': '*Gabriel'}, # Filter on PatientName
labels=['a-label'] # Filter on patients with the 'a-label'
)
retrieve_and_write_patients(patients, '.')
```

### Query (C-Find) and Retrieve (C-Move) from remote modality:

Write the patients DICOM files locally
```python
from pyorthanc import RemoteModality, Orthanc

orthanc = Orthanc('http://localhost:8042', 'username', 'password')
retrieve_and_write_patients(patients, './patients_path')
```
Or manipulates the Patient object
```python
patient = patients[0]

modality = RemoteModality(orthanc, 'modality')
patient.name
patient.is_stable
patient.last_update

# Query (C-Find) on modality
data = {'Level': 'Study', 'Query': {'PatientID': '*'}}
query_response = modality.query(data=data)
patient.labels
patient.remove_label('a-label')
patient.add_label('a-new-label')
...
```

answer = modality.get_query_answers()[query_response['ID']]
print(answer)
It is also possible to query the other resource levels
```python
from pyorthanc import find_studies, find_series, find_instances

# Retrieve (C-Move) results of query on a target modality (AET)
modality.move(query_response['ID'], {'TargetAet': 'target_modality'})
studies = find_studies(client=orthanc, query={...}, labels=[...])
series = find_series(client=orthanc, query={...}, labels=[...])
instances = find_instances(client=orthanc, query={...}, labels=[...])
```

#### Anonymize patient:
#### Anonymize patient
Resources (`Patient`, `Study`, `Series`, `Instance`) can be easily __anonymized__.
```python
from pyorthanc import Orthanc, Patient
import pyorthanc

orthanc = Orthanc('http://localhost:8042', 'username', 'password')
orthanc_patient_id = client.get_patients()[0]
patient = pyorthanc.Patient(orthanc_patient_id, client)
```
Waiting for the anonymization process (this may raise a TimeOutError)
```python
new_patient = patient.anonymize()
new_patient_with_given_patient_id = patient.anonymize(
keep=['PatientName'],
replace={'PatientID': 'TheNewPatientID'},
force=True # Needed when changing PatientID/StudyInstanceUID/SeriesInstanceUID/SOPInstanceUID
)
```
For long-running job (i.e. large patient) or to submit many anonymization jobs at the same time, use
```python
job = patient.anonymize_as_job()
job.state # You can follow the job state

job.wait_until_completion() # Or just wait on its completion
new_patient = pyorthanc.Patient(job.content['ID'], client)
```

patient_identifier = orthanc.get_patients()[0]
#### Find resources with complex filters or filter on many resource levels
The `pyorthanc.find()` function allow to find resources with filters on many levels,
or with complex filter. Each filter function takes an object that correspond to the resource level
and should return a boolean value.

anonymized_patient = Patient(patient_identifier, orthanc).anonymize(
keep=['PatientName'], # You can keep/remove/replace the DICOM tags you want
replace={'PatientID': 'TheNewPatientID'},
remove=['ReferringPhysicianName'],
force=True # Needed when changing PatientID/StudyInstanceUID/SeriesInstanceUID/SOPInstanceUID
Note that when using the `find()` function, the state of the resources `Patient/Study/Series/Instance`
are locked.
```python
from datetime import datetime
from pyorthanc import find

patients = find(
orthanc,
patient_filter=lambda patient: patient.last_update > datetime(year=2023, month=10, day=1),
study_filter=lambda study: 'thorax' in study.description.lower(),
series_filter=lambda series: series.modality == 'CT'
)
# Or directly with
orthanc.post_patients_id_anonymize(patient_identifier)

# result is: (you can retrieve DICOM file from ID)
# {'ID': 'dd41f2f1-24838e1e-f01746fc-9715072f-189eb0a2',
# 'Path': '/patients/dd41f2f1-24838e1e-f01746fc-9715072f-189eb0a2',
# 'PatientID': 'dd41f2f1-24838e1e-f01746fc-9715072f-189eb0a2',
# 'Type': 'Patient'}
```
__Note__ that this function may take a while to run since each resource level is filtered.
Using `find()` on large Orthanc server is not recommended.


## Full basic examples

Be sure that Orthanc is running. The default URL (if running locally) is `http://localhost:8042`.

Here is a list of examples to helps you getting started with pyorthanc
Here is a list of examples to helps you getting started with pyorthanc.

### Access instance informations
### Access instance information

[Get instance informations](https://github.com/ylemarechal/pyorthanc-examples/tree/main/basic/access_informations)

## Some useful commands

### Docker commands
Start Orthanc
```bash
docker compose up -d
```
Stop Orthanc
```bash
docker compose stop
```
Restart Orthanc
```bash
docker compose restart
```
Delete Orthanc container
```bash
docker compose down
```

0 comments on commit f0c30f8

Please sign in to comment.