Skip to content

Commit

Permalink
Update readme and changelog
Browse files Browse the repository at this point in the history
  • Loading branch information
erikogabrielsson committed Feb 12, 2024
1 parent ec6b546 commit eed01fa
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 28 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Support for opening files using [fsspec](https://filesystem-spec.readthedocs.io/).

## [0.18.3] - 2024-01-22

### Fixed
Expand Down
41 changes: 24 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,23 +63,30 @@ Please note that this is an early release and the API is not frozen yet. Functio

```python
from wsidicom import WsiDicom
slide = WsiDicom.open(path_to_folder)
slide = WsiDicom.open("path_to_folder")
```

***Load a WSI dataset from remote url.***

```python
from wsidicom import WsiDicom
slide = WsiDicom.open("s3://bucket/key", file_options={"s3": "anon": True})
```

***Or load a WSI dataset from opened streams.***

```python
from wsidicom import WsiDicom

slide = WsiDicom.open([file_stream_1, file_stream_2, ... ])
slide = WsiDicom.open_streams([file_stream_1, file_stream_2, ... ])
```

***Or load a WSI dataset from a DICOMDIR.***

```python
from wsidicom import WsiDicom

slide = WsiDicom.open_dicomdir(path_to_dicom_dir)
slide = WsiDicom.open_dicomdir("path_to_dicom_dir")
```

***Or load a WSI dataset from DICOMWeb.***
Expand Down Expand Up @@ -107,8 +114,8 @@ Alternatively, if you have already created an instance of
`WsiDicomWebClient` like so:

```python
dw_client = DICOMwebClient(url)
client = WsiDicomWebClient(dw_client)
dicomweb_client = DICOMwebClient("url")
client = WsiDicomWebClient(dicomweb_client)
```

Then proceed to call `WsiDicom.open_web()` with this as in the first example.
Expand All @@ -117,7 +124,7 @@ Then proceed to call `WsiDicom.open_web()` with this as in the first example.

```python
from wsidicom import WsiDicom
with WsiDicom.open(path_to_folder) as slide:
with WsiDicom.open("path_to_folder") as slide:
...
```

Expand Down Expand Up @@ -194,7 +201,7 @@ The WsiDicom API is similar to OpenSlide, but with some important differences:
Conversion between OpenSlide `location` and `level` parameters to WsiDicom can be performed:

```python
with WsiDicom.open(test_wsi) as wsi:
with WsiDicom.open("path_to_folder") as wsi:
level = wsi.levels[openslide_level_index]
x = openslide_x // 2**(level.level)
y = openslide_y // 2**(level.level)
Expand All @@ -206,7 +213,7 @@ with WsiDicom.open(test_wsi) as wsi:
WsiDicom parses the DICOM metadata in the opened image into easy-to-use dataclasses, see `wsidicom\metadata`.

```python
with WsiDicom.open(path_to_folder) as wsi:
with WsiDicom.open("path_to_folder") as wsi:
metadata = wsi.metadata
```

Expand All @@ -227,7 +234,7 @@ with the [VL Whole Slide Microscopy Image CIOD](https://dicom.innolitics.com/cio
Note that not all DICOM attributes are represented in the defined metadata model. Instead the full ´pydicom´ Datasets can be accessed per level, for example:

```python
with WsiDicom.open(path_to_folder) as wsi:
with WsiDicom.open("path_to_folder") as wsi:
wsi.levels.base_level.datasets[0]
```

Expand Down Expand Up @@ -294,7 +301,7 @@ The metadata can be exported to json:
```python
from wsidicom.metadata.schema.json import WsiMetadataJsonSchema

with WsiDicom.open(path_to_folder) as wsi:
with WsiDicom.open("path_to_folder") as wsi:
metadata = wsi.metadata

schema = WsiMetadataJsonSchema()
Expand All @@ -319,8 +326,8 @@ An opened WsiDicom instance can be saved to a new path using the save()-method.
By default frames are copied as-is, i.e. without re-compression.

```python
with WsiDicom.open(path_to_folder) as slide:
slide.save(path_to_output)
with WsiDicom.open("path_to_folder") as slide:
slide.save("path_to_output")
```

The output folder must already exists. Be careful to specify a unique folder folder to avoid mixing files from different images.
Expand All @@ -330,8 +337,8 @@ Optionally frames can be transcoded, either by a encoder setting or an encoder:
```python
from wsidicom.codec import JpegSettings

with WsiDicom.open(path_to_folder) as slide:
slide.save(path_to_output, transcoding=JpegSettings())
with WsiDicom.open("path_to_folder") as slide:
slide.save("path_to_output", transcoding=JpegSettings())
```

## Settings
Expand Down Expand Up @@ -363,7 +370,7 @@ Codes that are defined in the 222-draft can be created using the create(source,

```python
from wsidicom import WsiDicom
slide = WsiDicom.open(path_to_folder)
slide = WsiDicom.open("path_to_folder")
```

***Create a point annotation at x=10.0, y=20.0 mm.***
Expand Down Expand Up @@ -414,7 +421,7 @@ annotations.save('path_to_dicom_dir/annotation.dcm')
***Reopen the slide and access the annotation instance.***

```python
slide = WsiDicom.open(path_to_folder)
slide = WsiDicom.open("path_to_folder")
annotations = slide.annotations
```

Expand Down Expand Up @@ -465,7 +472,7 @@ Labels and overviews are structured similarly to levels, but with somewhat diffe
A Source is used to create WsiInstances, either from files (*WsiDicomFileSource*) or DICOMWeb (*WsiDicomWebSource*), and can be used to to Initiate a *WsiDicom* object. A source is easiest created with the open() and open_web() helper functions, e.g.:

```python
slide = WsiDicom.open(path_to_folder)
slide = WsiDicom.open("path_to_folder")
```

## Code structure
Expand Down
4 changes: 2 additions & 2 deletions wsidicom/file/wsidicom_file_target.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def __init__(
"""
self._output_path = UPath(output_path)
self._offset_table = offset_table
self._filepaths: List[Path] = []
self._filepaths: List[UPath] = []
self._opened_files: List[WsiDicomReader] = []
self._file_options = file_options
super().__init__(
Expand All @@ -112,7 +112,7 @@ def __init__(
)

@property
def filepaths(self) -> List[Path]:
def filepaths(self) -> List[UPath]:
"""Return filepaths for created files."""
return self._filepaths

Expand Down
23 changes: 14 additions & 9 deletions wsidicom/wsidicom.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ def open(
----------
path: Union[str, Path, UPath, Iterable[Union[str, Path, UPath]]]
Files to open. Can be a path for a single file, a list of paths for multiple
files, or a path to a folder containing files.
files, or a path to a folder containing files. Path can be local or an URL
supported by fsspec.
file_options: Optional[Dict[str, Any]] = None
Optional options for when opening files.
Expand All @@ -116,7 +117,8 @@ def open_dicomdir(
Parameters
----------
path: UPath
Path to DICOMDIR file or directory with a DICOMDIR file.
Path to DICOMDIR file or directory with a DICOMDIR file. Path can be local
or an URL supported by fsspec.
file_options: Optional[Dict[str, Any]] = None
Optional options for when opening files.
Expand Down Expand Up @@ -215,7 +217,7 @@ def save(
label: Optional[Union[Image, Union[str, Path, UPath]]] = None,
transcoding: Optional[Union[EncoderSettings, Encoder]] = None,
file_options: Optional[Dict[str, Any]] = None,
) -> List[Path]:
) -> List[UPath]:
"""
Save wsi as DICOM-files in path. Instances for the same pyramid
level will be combined when possible to one file (e.g. not split
Expand All @@ -227,7 +229,7 @@ def save(
----------
output_path: Union[str, Path, UPath]
Output folder to write files to. Should preferably be an dedicated folder
for the wsi.
for the wsi. Path can be local or an URL supported by fsspec.
uid_generator: Callable[..., UID] = pydicom.uid.generate_uid
Function that can generate unique identifiers.
workers: Optional[int] = None
Expand Down Expand Up @@ -262,7 +264,7 @@ def save(
Returns
-------
List[Path]
List[UPath]
List of paths of created files.
"""
if workers is None:
Expand Down Expand Up @@ -318,8 +320,9 @@ def is_ready_for_viewing(
Parameters
----------
path: Union[str, Path, UPath, Iterable[Union[str, Path, UPath]]]
Files to open. Can be a path or stream for a single file, a list of paths or
streams for multiple files, or a path to a folder containing files.
Files to open. Can be a path for a single file, a list of paths for multiple
files, or a path to a folder containing files. Path can be local or an URL
supported by fsspec.
file_options: Optional[Dict[str, Any]] = None
Optional options for when opening files.
Expand All @@ -341,8 +344,10 @@ def is_supported(
Parameters
----------
path: Union[str, Iterable[str], Path, Iterable[Path]]
Path to files to test.
path: Union[str, Path, UPath, Iterable[Union[str, Path, UPath]]]
Path to files to test. Path can be local or an URL supported by fsspec.
file_options: Optional[Dict[str, Any]] = None
Optional options for when opening files.
Returns
True if files in path have one level that can be read with WsiDicom.
Expand Down

0 comments on commit eed01fa

Please sign in to comment.