Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
0ab3a0f
BLD/STY: Set up cli for command line interface
May 30, 2020
3a24650
BLD: Added slide information feature
May 31, 2020
3477f52
BLD: Add multiproc decorator for toolbox
Jun 1, 2020
6921300
STY: Run black for style formatting
Jun 1, 2020
c67d8b0
DOC: Add Docstring to multiproc.py
Jun 1, 2020
6a6845e
BUG: Update requirements_dev.txt to fix bugs with Travis
Jun 1, 2020
f7b0c0c
BUG: Update requirements_dev.txt to fix bugs opencv-python with Travis
Jun 1, 2020
7381339
BUG: Travis error fix setuptools
Jun 1, 2020
eb4a990
BUG: Travis error fix setuptools
Jun 1, 2020
f06b659
BUG: Fix Travis error History.rst
Jun 1, 2020
1ba8c42
BUG: Fix Travis libopenslide.so.0: error
Jun 1, 2020
02747bb
BUG: Update test_tiatoolbox.py to fix pytest errors
Jun 1, 2020
5f63b4a
BUG: FIX travis error for python3.8
Jun 2, 2020
34b9bd6
BUG: FIX travis error for python3.8
Jun 2, 2020
6f3ffaa
BUG: Fix Travis python 3.8 issue
Jun 2, 2020
68d2177
BUG: Fix Travis python 3.8 issue
Jun 2, 2020
6811a98
BUG: Fix Travis python 3.8 issue
Jun 2, 2020
ab43935
BUG: Roll back multiprocessing changes for python 3.8
Jun 2, 2020
045ef83
BUG: Fix Travis error for multiprocessing
Jun 2, 2020
a24e4a5
BUG: Fix Multiprocessing bug for python 3.8
Jun 2, 2020
e837fb7
BUG: Fix Multiprocessing bug for python 3.8
Jun 2, 2020
1285e6b
Merge branch 'develop' into feature-slide-info
shaneahmed Jun 2, 2020
abfa632
DOC: Update docstring test_tiatoolbox.py
Jun 2, 2020
eabf091
DOC: Update README
Jun 3, 2020
ee19869
DOC: Update README.rst
shaneahmed Jun 3, 2020
5b1c768
DEV: Add conda requirements file
Jun 3, 2020
3b78fc1
TST: Add test for version information
Jun 3, 2020
a70831d
DEP: Remove tiatoolbox_Structure.jpg
Jun 4, 2020
82cf63c
DOC: Update to README.rst according to address PR comments
Jun 4, 2020
60e7d69
DEV: Update travis yml for openslide tools
Jun 4, 2020
08ab342
DOC: Update cli docstring
Jun 4, 2020
573fa08
BUG: Reverting back to python3-openslide for travis
Jun 4, 2020
f547d2d
BUG: Reverting back to python3-openslide for travis
Jun 4, 2020
b0ff26e
DEV: Update wsireader
Jun 4, 2020
3d9f6e4
TST: Modify tests to using setup/teardown functions
Jun 4, 2020
2ed615e
STY: Update the style using black
Jun 4, 2020
2661de6
DEV: Update travis yml for openslide tools
Jun 5, 2020
e180dd6
DOC: Update instructions for pip
Jun 15, 2020
0847184
STY: Format import on one line
Jun 15, 2020
a2e2a81
MAINT: Rename misc_utils.py to misc.py
Jun 15, 2020
66dac0f
DOC: Update docstring to add file type
Jun 15, 2020
b49ec89
DOC: Update docstring to add file type
Jun 15, 2020
e80e860
DOC: Update README.rst to include TIA logo
Jun 15, 2020
b9b6dd5
DOC: Update misc.py docstring to ammend Returns
Jun 15, 2020
ff3073b
DEP: output only dictionary from slide_info
Jun 15, 2020
ad355c4
STY: Run black on python code
Jun 15, 2020
d7ea162
MAINT: Update multiproc to raise error instead of print
Jun 15, 2020
dc5d144
DOC: Update slide_info docstring
Jun 15, 2020
d3af79a
DOC: Update save_yaml doc in misc.py
Jun 15, 2020
322286c
DOC: Update docstring for sphinx
Jun 16, 2020
8849f62
STY: Update style using black
Jun 16, 2020
3970513
DOC: Update usage.rst to reformat html and pdf
Jun 17, 2020
8b11fc8
DOC: Update docstring with space to make it consistent
Jun 17, 2020
9cbb54b
MAINT: Update location of logo
Jun 17, 2020
3fbd942
DOC: Update docstring to fix One-line docstring error
Jun 17, 2020
90b7140
DOC: Update docstring to fix Doc line too long error
Jun 17, 2020
84187a8
MAINT: Modify if statement to remove unnecessary else error
Jun 17, 2020
00b0c28
MAINT: Modify if statement to remove unnecessary else error
Jun 17, 2020
8a459f0
MAINT: Fix spaces after ,
Jun 17, 2020
5dfa112
DOC: Fix docstring line too long
Jun 17, 2020
bd45034
DOC: Fix docstring line too long
Jun 17, 2020
bc81b2b
DOC: Fix whitespace before comma
Jun 17, 2020
72f2b5d
STY: Update black styling
Jun 17, 2020
2726d98
MAINT: Use `is` instead of `==` for test
Jun 17, 2020
7e8dcf4
MAINT: Unused arguments should start with _
Jun 17, 2020
4614f7f
TST: Update test_tiatoolbox.py for slide_info
Jun 17, 2020
eff04cf
MAINT: Remove __exit__ to fix errors with Deepsource
Jun 17, 2020
8fc06d6
Merge branch 'develop' into feature-slide-info
shaneahmed Jun 18, 2020
8398bb4
DOC: Update docstrings
Jun 18, 2020
8af253a
BUG: Fix .travis.yml indentation
Jun 18, 2020
1d99de1
BUG: Fix .travis.yml openslide-tools
Jun 18, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ python:
- 3.6

before_install:
- sudo apt-get -y install python3-openslide
- sudo apt-get -y install openslide-tools

# Command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors
install: pip install -U tox-travis
Expand Down
13 changes: 11 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
.. raw:: html

<p align="center">
<img width="450" height="200" src=docs/tialab_logo.png>
<img width="450" height="200" src=https://warwick.ac.uk/fac/sci/dcs/research/tia/models/tialab_logo.png>
</p>

===========
Expand All @@ -22,6 +22,15 @@ Getting Started
First, install OpenSlide `here <https://openslide.org/download/>`__. Then, create and
activate the conda environment:

pip
----

::

pip install -r requirements_dev.txt

conda
-----
::

conda env create --name tiatoolbox --file requirements.conda.yml
Expand All @@ -42,6 +51,6 @@ tiatoolbox --help

optional arguments:
-h, --help show this help message and exit
--version show program's version number and exit
--version show program`s version number and exit
--verbose VERBOSE

2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@

# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ["sphinx.ext.autodoc", "sphinx.ext.viewcode"]
extensions = ["sphinx.ext.autodoc", "sphinx.ext.viewcode", "sphinx.ext.napoleon"]

# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]
Expand Down
2 changes: 1 addition & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Welcome to TIA Toolbox's documentation!
======================================
=======================================

.. toctree::
:maxdepth: 2
Expand Down
44 changes: 44 additions & 0 deletions docs/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,47 @@ Usage
To use TIA Toolbox in a project::

import tiatoolbox


----------
Dataloader
----------
.. automodule:: tiatoolbox.dataloader

^^^^^^^^^^^^^^^^^^^^
dataloader.wsireader
^^^^^^^^^^^^^^^^^^^^

.. automodule:: tiatoolbox.dataloader.wsireader
:members: WSIReader
:special-members: __init__

^^^^^^^^^^^^^^^^^^^^^
dataloader.slide_info
^^^^^^^^^^^^^^^^^^^^^

.. automodule:: tiatoolbox.dataloader.slide_info
:members: slide_info

----------
Decorators
----------
.. automodule:: tiatoolbox.decorators

^^^^^^^^^^^^^^^^^^^^
decorators.multiproc
^^^^^^^^^^^^^^^^^^^^
.. automodule:: tiatoolbox.decorators.multiproc
:members: TIAMultiProcess
:special-members: __init__, __call__

------
Utils
------
.. automodule:: tiatoolbox.utils

^^^^^^^^^^
utils.misc
^^^^^^^^^^
.. automodule:: tiatoolbox.utils.misc
:members: save_yaml, split_path_name_ext, grab_files_from_dir
11 changes: 6 additions & 5 deletions tests/test_tiatoolbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import pytest

from tiatoolbox.dataloader.slide_info import slide_info
from tiatoolbox.utils import misc_utils as misc
from tiatoolbox import utils
from tiatoolbox import cli
from tiatoolbox import __version__

Expand Down Expand Up @@ -62,13 +62,14 @@ def test_slide_info(response_ndpi, response_svs):
"""
pytest for slide_info as a python function
"""
# from bs4 import BeautifulSoup
# assert 'GitHub' in BeautifulSoup(response.content).title.string
file_types = ("*.ndpi", "*.svs", "*.mrxs")
files_all = misc.grab_files_from_dir(
files_all = utils.misc.grab_files_from_dir(
input_path=str(pathlib.Path(r".")), file_types=file_types,
)
_ = slide_info(input_path=files_all, workers=2, mode="save")
slide_params = slide_info(input_path=files_all, workers=2, mode="save")

for slide_param in slide_params:
utils.misc.save_yaml(slide_param, slide_param["file_name"] + ".yaml")


def test_command_line_help_interface():
Expand Down
3 changes: 3 additions & 0 deletions tiatoolbox/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@
__author__ = """TIA Lab"""
__email__ = "[email protected]"
__version__ = "0.1.1"

if __name__ == "__main__":
pass
4 changes: 2 additions & 2 deletions tiatoolbox/cli.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Console script for tiatoolbox."""
from tiatoolbox import __version__
from tiatoolbox import dataloader
from tiatoolbox.utils import misc_utils as misc
from tiatoolbox import utils
import sys
import click
import os
Expand Down Expand Up @@ -52,7 +52,7 @@ def slide_info(wsi_input, output_dir, file_types, mode, workers=None):
"""
file_types = tuple(file_types.split(", "))
if os.path.isdir(wsi_input):
files_all = misc.grab_files_from_dir(
files_all = utils.misc.grab_files_from_dir(
input_path=wsi_input, file_types=file_types
)
elif os.path.isfile(wsi_input):
Expand Down
7 changes: 5 additions & 2 deletions tiatoolbox/dataloader/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
from tiatoolbox.dataloader import slide_info
from tiatoolbox.dataloader import wsireader
"""
Package to read whole slide images
"""

from tiatoolbox.dataloader import slide_info, wsireader
40 changes: 18 additions & 22 deletions tiatoolbox/dataloader/slide_info.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
This file contains code to output or save slide information using python multiprocessing
Get Slide Meta Data information
"""
from tiatoolbox.dataloader import wsireader
from tiatoolbox.decorators.multiproc import TIAMultiProcess
Expand All @@ -8,43 +8,39 @@


@TIAMultiProcess(iter_on="input_path")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a style preference here. Having a capitalised decorator like this just looks wrong. They are usually defined in a decorators.py file then imported in __innit__.py e.g. @pytest.fixture, @np.vectorize, @click.command or imported then used e.g.:

from numba import jit

@jit(nopython=True)
def do_something_useful():
    pass

or a function of a class e.g. in flask apps:

from flask import Flask
app = Flask(__name__)


@app.route('/')
def hello_world():
    return 'Hello, World!'

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Class name shouldn't it be PascalCase?

def slide_info(input_path, output_dir=None, mode="show"):
def slide_info(input_path, output_dir=None):
"""
slide_info()
Single file run to output or save WSI meta data. Multiprocessing uses this function to run slide_info in parallel
Args:
input_path: Path to whole slide image
output_dir: Path to output directory to save the output
mode: "show" to display meta information only or "save" to save the meta information

Returns:
displays or saves WSI meta information

Examples:
>>> from tiatoolbox.dataloader.slide_info import slide_info
>>> from tiatoolbox import utils
>>> file_types = ("*.ndpi", "*.svs", "*.mrxs")
>>> files_all = utils.misc.grab_files_from_dir(input_path, file_types=file_types)
>>> slide_params = slide_info(input_path=files_all, workers=2)
>>> for slide_param in slide_params:
>>> utils.misc.save_yaml(slide_param, slide_param["file_name"] + ".yaml")
>>> print(type(slide_param))

"""

input_dir, file_name = os.path.split(input_path)

if output_dir is None:
output_dir = os.path.join(input_dir, "..", "meta")

if mode is None:
mode = "show"

if not os.path.isdir(output_dir) and mode == "save":
os.makedirs(output_dir, exist_ok=True)

print(file_name, flush=True)
_, file_type = os.path.splitext(file_name)

if file_type == ".svs" or file_type == ".ndpi" or file_type == ".mrxs":
wsi_reader = wsireader.WSIReader(
input_dir=input_dir, file_name=file_name, output_dir=output_dir
)
if mode == "show":
info = wsi_reader.slide_info(save_mode=False)
print(info)
return info
else:
wsi_reader.slide_info(
output_dir=output_dir, output_name=file_name + ".yaml"
)
return os.path.join(output_dir, file_name + ".yaml")
info = wsi_reader.slide_info()
return info
else:
print("File type not supported")
return None
58 changes: 33 additions & 25 deletions tiatoolbox/dataloader/wsireader.py
Original file line number Diff line number Diff line change
@@ -1,33 +1,50 @@
"""
WSIReader for WSI reading or extracting metadata information from WSIs

"""
import pathlib
import numpy as np
import yaml
from PIL import Image

import openslide


class WSIReader:
"""
WSI Reader class to read WSI images

Attributes:
input_dir (pathlib.Path): input path to WSI directory
file_name (str): file name of the WSI
output_dir (pathlib.Path): output directory to save the output
openslide_obj (:obj:`openslide.OpenSlide`)
tile_objective_value (int): objective value at which tile is generated
tile_read_size (int): [tile width, tile height]
objective_power (int): objective value at which whole slide image is scanned
level_count (int): The number of pyramid levels in the slide
level_dimensions = A list of `(width, height)` tuples, one for each level of the slide
level_downsamples = A list of down sample factors for each level of the slide

"""

def __init__(
self,
input_dir=pathlib.Path.cwd(),
input_dir=".",
file_name=None,
output_dir=pathlib.Path(pathlib.Path.cwd(), "output"),
output_dir="./output",
tile_objective_value=20,
tile_read_size_w=5000,
tile_read_size_h=5000,
):
"""
WSI Reader class to read WSI images
Args:
input_dir: input path to WSI directory
file_name: file name of the WSI
output_dir: output directory to save the output, default=os.getcwd()/output
tile_objective_value: objective value at which tile is generated, default=20
tile_read_size_w: tile width, default=5000
tile_read_size_h: tile height, default=5000
input_dir (str, pathlib.Path): input path to WSI directory
file_name (str): file name of the WSI
output_dir (str, pathlib.Path): output directory to save the output, default=os.getcwd()/output
tile_objective_value (int): objective value at which tile is generated, default=20
tile_read_size_w (int): tile width, default=5000
tile_read_size_h (int): tile height, default=5000

"""

self.input_dir = pathlib.Path(input_dir)
Expand All @@ -50,23 +67,16 @@ def __init__(
def __exit__(self):
self.openslide_obj.close()

def slide_info(self, save_mode=True, output_dir=None, output_name=None):
def slide_info(self):
"""
WSI meta data reader
Args:
save_mode: save meta information as yaml file
output_dir: output directory to save the meta information
output_name: output file name

Returns:
displays or saves WSI meta information
param (dict): dictionary containing meta information

"""
input_dir = self.input_dir
if output_dir is None:
self.output_dir = output_dir
if output_name is None:
output_name = "param.yaml"
if self.objective_power == 0:
self.objective_power = np.int(
self.openslide_obj.properties[openslide.PROPERTY_NAME_OBJECTIVE_POWER]
Expand All @@ -80,10 +90,10 @@ def slide_info(self, save_mode=True, output_dir=None, output_name=None):
level_count = self.level_count
level_dimensions = self.level_dimensions
level_downsamples = self.level_downsamples
file_name = self.file_name

param = {
"input_dir": input_dir,
"output_dir": output_dir,
"objective_power": objective_power,
"slide_dimension": slide_dimension,
"rescale": rescale,
Expand All @@ -93,9 +103,7 @@ def slide_info(self, save_mode=True, output_dir=None, output_name=None):
"level_count": level_count,
"level_dimensions": level_dimensions,
"level_downsamples": level_downsamples,
"file_name": file_name,
}
if save_mode:
with open(pathlib.Path(output_dir, output_name), "w") as yaml_file:
yaml.dump(param, yaml_file)
else:
return param

return param
2 changes: 1 addition & 1 deletion tiatoolbox/decorators/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""
Decorators init file
Package defines decorators for the toolbox
"""
from tiatoolbox.decorators import multiproc
Loading