dsa-helpers 0.3__tar.gz → 0.3.dev0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. {dsa_helpers-0.3 → dsa_helpers-0.3.dev0}/.gitignore +1 -3
  2. {dsa_helpers-0.3/dsa_helpers.egg-info → dsa_helpers-0.3.dev0}/PKG-INFO +6 -12
  3. {dsa_helpers-0.3 → dsa_helpers-0.3.dev0}/dsa_helpers/__init__.py +2 -3
  4. dsa_helpers-0.3.dev0/dsa_helpers/girder_utils.py +116 -0
  5. {dsa_helpers-0.3 → dsa_helpers-0.3.dev0}/dsa_helpers/login.py +1 -3
  6. {dsa_helpers-0.3 → dsa_helpers-0.3.dev0/dsa_helpers.egg-info}/PKG-INFO +6 -12
  7. dsa_helpers-0.3.dev0/dsa_helpers.egg-info/SOURCES.txt +16 -0
  8. dsa_helpers-0.3.dev0/dsa_helpers.egg-info/requires.txt +5 -0
  9. {dsa_helpers-0.3 → dsa_helpers-0.3.dev0}/pyproject.toml +6 -12
  10. dsa_helpers-0.3.dev0/requirements.txt +5 -0
  11. dsa_helpers-0.3/app.py +0 -14
  12. dsa_helpers-0.3/dsa_helpers/dash/__init__.py +0 -1
  13. dsa_helpers-0.3/dsa_helpers/dash/header.py +0 -141
  14. dsa_helpers-0.3/dsa_helpers/dash/header_callbacks.py +0 -98
  15. dsa_helpers-0.3/dsa_helpers/girder_utils.py +0 -321
  16. dsa_helpers-0.3/dsa_helpers/ml/__init__.py +0 -2
  17. dsa_helpers-0.3/dsa_helpers/ml/object_detection/__init__.py +0 -5
  18. dsa_helpers-0.3/dsa_helpers/ml/object_detection/get_pearce_roi_images.py +0 -136
  19. dsa_helpers-0.3/dsa_helpers/ml/object_detection/tile_image.py +0 -137
  20. dsa_helpers-0.3/dsa_helpers/ml/object_detection/utils.py +0 -104
  21. dsa_helpers-0.3/dsa_helpers/mongo_utils.py +0 -147
  22. dsa_helpers-0.3/dsa_helpers.egg-info/SOURCES.txt +0 -28
  23. dsa_helpers-0.3/dsa_helpers.egg-info/requires.txt +0 -11
  24. dsa_helpers-0.3/readthedocs.yaml +0 -27
  25. dsa_helpers-0.3/requirements.txt +0 -11
  26. dsa_helpers-0.3/test.ipynb +0 -268
  27. {dsa_helpers-0.3 → dsa_helpers-0.3.dev0}/LICENSE +0 -0
  28. {dsa_helpers-0.3 → dsa_helpers-0.3.dev0}/README.md +0 -0
  29. {dsa_helpers-0.3 → dsa_helpers-0.3.dev0}/dsa_helpers/image_utils.py +0 -0
  30. {dsa_helpers-0.3 → dsa_helpers-0.3.dev0}/dsa_helpers/imread.py +0 -0
  31. {dsa_helpers-0.3 → dsa_helpers-0.3.dev0}/dsa_helpers/imwrite.py +0 -0
  32. {dsa_helpers-0.3 → dsa_helpers-0.3.dev0}/dsa_helpers.egg-info/dependency_links.txt +0 -0
  33. {dsa_helpers-0.3 → dsa_helpers-0.3.dev0}/dsa_helpers.egg-info/top_level.txt +0 -0
  34. {dsa_helpers-0.3 → dsa_helpers-0.3.dev0}/setup.cfg +0 -0
@@ -5,6 +5,4 @@ pyenv/
5
5
  # Do not push the version file.
6
6
  dsa_utils/_version.py
7
7
 
8
- *.pyc
9
- *.egg-info
10
- dist/
8
+ *.pyc
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dsa_helpers
3
- Version: 0.3
3
+ Version: 0.3.dev0
4
4
  Summary: Utility functions for working with the DSA girder client.
5
5
  Author-email: "Juan C. Vizcarra" <jvizcar@emory.edu>
6
6
  Maintainer-email: "Juan C. Vizcarra" <jvizcar@emory.edu>
@@ -11,17 +11,11 @@ Classifier: License :: OSI Approved :: MIT License
11
11
  Requires-Python: >=3.9
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE
14
- Requires-Dist: girder-client
15
- Requires-Dist: numpy
16
- Requires-Dist: setuptools
17
- Requires-Dist: opencv-python
18
- Requires-Dist: pandas
19
- Requires-Dist: pymongo
20
- Requires-Dist: pillow
21
- Requires-Dist: dash
22
- Requires-Dist: dash_bootstrap_components
23
- Requires-Dist: shapely
24
- Requires-Dist: geopandas
14
+ Requires-Dist: girder-client==3.2.3
15
+ Requires-Dist: numpy==2.0.0
16
+ Requires-Dist: setuptools==71.0.3
17
+ Requires-Dist: opencv-python==4.10.0.84
18
+ Requires-Dist: pandas==2.2.2
25
19
 
26
20
  # Digital Slide Archive (DSA) Helpers
27
21
  Digital Slide Archive Python utility library.
@@ -1,8 +1,7 @@
1
1
  # Shadow imports.
2
+ from .login import login
2
3
  from .imread import imread
3
4
  from .imwrite import imwrite
4
5
 
5
6
  # Modules that should be available.
6
- # from . import girder_utils, image_utils, dash
7
-
8
- __all__ = ["girder_utils", "image_utils", "dash"]
7
+ from . import girder_utils, image_utils
@@ -0,0 +1,116 @@
1
+ # Functions using the girder client.
2
+ from girder_client import GirderClient
3
+ import pickle
4
+ import numpy as np
5
+
6
+
7
+ def get_item_large_image_metadata(gc: GirderClient, item_id: str) -> dict:
8
+ """Get large image metadata for an item.
9
+
10
+ Args:
11
+ gc (girder_client.GirderClient): The authenticated girder client.
12
+ item_id (str): The item id.
13
+
14
+ Returns:
15
+ dict: The metadata of the large image item.
16
+
17
+ """
18
+ return gc.get(f"item/{item_id}/tiles")
19
+
20
+
21
+ def get_thumbnail(
22
+ gc: GirderClient,
23
+ item_id: str,
24
+ mag: float | None = None,
25
+ width: int | None = None,
26
+ height: int | None = None,
27
+ fill: int | tuple = (255, 255, 255),
28
+ ) -> np.ndarray:
29
+ """Get the thumbnail image by a specific magnification or shape. If mag is
30
+ not None, then width and height are ignored. Fill is only used when both
31
+ width and height are provided, to return the thumbnail at the exact shape.
32
+ DSA convention will fill the height of the image, centering the image and
33
+ filling the top and bottom of the image equally.
34
+
35
+ Args:
36
+ gc (girder_client.GirderClient): The authenticated girder client.
37
+ item_id (str): The item id.
38
+ mag (float, optional): The magnification. Defaults to None.
39
+ width (int, optional): The width of the thumbnail. Defaults to None.
40
+ height (int, optional): The height of the thumbnail. Defaults to None.
41
+ fill (int | tuple, optional): The fill color. Defaults to (255, 255, 255).
42
+
43
+ Returns:
44
+ np.ndarray: The thumbnail image.
45
+
46
+ """
47
+ get_url = f"item/{item_id}/tiles/"
48
+
49
+ if mag is not None:
50
+ get_url += f"region?magnification={mag}&encoding=pickle"
51
+ else:
52
+ # Instead use width and height.
53
+ params = ["encoding=pickle"]
54
+
55
+ if width is not None and height is not None:
56
+ if isinstance(fill, (tuple, list)):
57
+ if len(fill) == 3:
58
+ fill = f"rgb({fill[0]},{fill[1]},{fill[2]})"
59
+ elif len(fill) == 4:
60
+ fill = f"rgba({fill[0]},{fill[1]},{fill[2]},{fill[3]})"
61
+
62
+ params.extend([f"width={width}", f"height={height}", f"fill={fill}"])
63
+ elif width is not None:
64
+ params.append(f"width={width}")
65
+ elif height is not None:
66
+ params.append(f"height={height}")
67
+
68
+ get_url += "thumbnail?" + "&".join(params)
69
+
70
+ response = gc.get(get_url, jsonResp=False)
71
+
72
+ return pickle.loads(response.content)
73
+
74
+
75
+ def get_region(
76
+ gc: GirderClient,
77
+ item_id: str,
78
+ left: int,
79
+ top: int,
80
+ width: int,
81
+ height: int,
82
+ mag: float | None = None,
83
+ ) -> np.ndarray:
84
+ """Get a region of the image for an item. Note that the output image might
85
+ not be in the shape (width, height) if left + width or top + height exceeds
86
+ the image size. The output image will be the maximum size possible.
87
+
88
+ Args:
89
+ gc (girder_client.GirderClient): The authenticated girder client.
90
+ item_id (str): The item id.
91
+ left (int): The left coordinate.
92
+ top (int): The top coordinate.
93
+ width (int): The width of the region.
94
+ height (int): The height of the region.
95
+ mag (float, optional): The magnification. Defaults to None which returns
96
+ the image at scan magnification. Using a mag lower than the scan
97
+ magnification will result in an ouptut image smaller than the
98
+ width and height. Similarly, using a mag higher than the scan
99
+ magnification will result in an output image larger than the width
100
+ and height.
101
+
102
+ Returns:
103
+ np.ndarray: The region of the image.
104
+
105
+ """
106
+ get_url = (
107
+ f"item/{item_id}/tiles/region?left={left}&top={top}&regionWidth="
108
+ f"{width}&regionHeight={height}&encoding=pickle"
109
+ )
110
+
111
+ if mag is not None:
112
+ get_url += f"&magnification={mag}"
113
+
114
+ response = gc.get(get_url, jsonResp=False)
115
+
116
+ return pickle.loads(response.content)
@@ -24,9 +24,7 @@ def login(
24
24
  gc = GirderClient(apiUrl=api_url)
25
25
 
26
26
  if api_key is None:
27
- if login_or_email is None:
28
- _ = gc.authenticate(interactive=True)
29
- elif password is None:
27
+ if password is None:
30
28
  _ = gc.authenticate(username=login_or_email, interactive=True)
31
29
  else:
32
30
  _ = gc.authenticate(username=login_or_email, password=password)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dsa_helpers
3
- Version: 0.3
3
+ Version: 0.3.dev0
4
4
  Summary: Utility functions for working with the DSA girder client.
5
5
  Author-email: "Juan C. Vizcarra" <jvizcar@emory.edu>
6
6
  Maintainer-email: "Juan C. Vizcarra" <jvizcar@emory.edu>
@@ -11,17 +11,11 @@ Classifier: License :: OSI Approved :: MIT License
11
11
  Requires-Python: >=3.9
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE
14
- Requires-Dist: girder-client
15
- Requires-Dist: numpy
16
- Requires-Dist: setuptools
17
- Requires-Dist: opencv-python
18
- Requires-Dist: pandas
19
- Requires-Dist: pymongo
20
- Requires-Dist: pillow
21
- Requires-Dist: dash
22
- Requires-Dist: dash_bootstrap_components
23
- Requires-Dist: shapely
24
- Requires-Dist: geopandas
14
+ Requires-Dist: girder-client==3.2.3
15
+ Requires-Dist: numpy==2.0.0
16
+ Requires-Dist: setuptools==71.0.3
17
+ Requires-Dist: opencv-python==4.10.0.84
18
+ Requires-Dist: pandas==2.2.2
25
19
 
26
20
  # Digital Slide Archive (DSA) Helpers
27
21
  Digital Slide Archive Python utility library.
@@ -0,0 +1,16 @@
1
+ .gitignore
2
+ LICENSE
3
+ README.md
4
+ pyproject.toml
5
+ requirements.txt
6
+ dsa_helpers/__init__.py
7
+ dsa_helpers/girder_utils.py
8
+ dsa_helpers/image_utils.py
9
+ dsa_helpers/imread.py
10
+ dsa_helpers/imwrite.py
11
+ dsa_helpers/login.py
12
+ dsa_helpers.egg-info/PKG-INFO
13
+ dsa_helpers.egg-info/SOURCES.txt
14
+ dsa_helpers.egg-info/dependency_links.txt
15
+ dsa_helpers.egg-info/requires.txt
16
+ dsa_helpers.egg-info/top_level.txt
@@ -0,0 +1,5 @@
1
+ girder-client==3.2.3
2
+ numpy==2.0.0
3
+ setuptools==71.0.3
4
+ opencv-python==4.10.0.84
5
+ pandas==2.2.2
@@ -4,17 +4,11 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  dependencies = [
7
- 'girder-client',
8
- 'numpy',
9
- 'setuptools',
10
- 'opencv-python',
11
- 'pandas',
12
- 'pymongo',
13
- 'pillow',
14
- 'dash',
15
- 'dash_bootstrap_components',
16
- 'shapely',
17
- 'geopandas'
7
+ 'girder-client==3.2.3',
8
+ 'numpy==2.0.0',
9
+ 'setuptools==71.0.3',
10
+ 'opencv-python==4.10.0.84',
11
+ 'pandas==2.2.2'
18
12
  ]
19
13
  name = "dsa_helpers"
20
14
  authors = [
@@ -31,7 +25,7 @@ classifiers = [
31
25
  "License :: OSI Approved :: MIT License",
32
26
  ]
33
27
  keywords = ["dsa", "girder", "girder_client"]
34
- version = "v0.3"
28
+ version = "v0.3dev"
35
29
 
36
30
  [project.urls]
37
31
  Repository = "https://github.com/Gutman-Lab/dsa-python-utils"
@@ -0,0 +1,5 @@
1
+ setuptools==71.0.3
2
+ girder-client==3.2.3
3
+ numpy==2.0.0
4
+ opencv-python==4.10.0.84
5
+ pandas==2.2.2
dsa_helpers-0.3/app.py DELETED
@@ -1,14 +0,0 @@
1
- # A test application.
2
- from dash import Dash, html
3
- import dash_bootstrap_components as dbc
4
- from dsa_helpers.dash.header import get_header
5
- import os
6
-
7
- os.environ["DSA_API_URL"] = "https://megabrain.neurology.emory.edu/api/v1"
8
-
9
- app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
10
-
11
- app.layout = html.Div([get_header("Test")])
12
-
13
- if __name__ == "__main__":
14
- app.run_server(debug=True)
@@ -1 +0,0 @@
1
- from . import header
@@ -1,141 +0,0 @@
1
- from dash import html, dcc
2
- import dash_bootstrap_components as dbc
3
- from . import header_callbacks
4
-
5
-
6
- def get_header(title: str = "App", config: dict | None = None) -> html.Div:
7
- """Get the Dash html component that contains the header of the application
8
- with login capabilities.
9
-
10
- Args:
11
- title (str): The title of the application.
12
- config (dict): The configuration of the component.
13
-
14
- backgroundColor
15
- titleColor
16
- fontColor
17
-
18
- Returns:
19
- html.Div: The header component.
20
-
21
- """
22
- login_modal = dbc.Modal(
23
- [
24
- dbc.ModalHeader("Log in"),
25
- dbc.ModalBody(
26
- [
27
- html.Div(
28
- "Login or email", style={"margin": 5, "fontWeight": "bold"}
29
- ),
30
- dbc.Input(
31
- id="login",
32
- type="text",
33
- placeholder="Enter login",
34
- style={"margin": 5},
35
- ),
36
- html.Div(
37
- "Password",
38
- style={"margin": 5, "marginTop": 15, "fontWeight": "bold"},
39
- ),
40
- dbc.Input(
41
- id="password",
42
- type="password",
43
- placeholder="Enter password",
44
- style={"margin": 5},
45
- ),
46
- html.Div(
47
- "Login failed.",
48
- hidden=True,
49
- id="login-failed",
50
- style={"color": "red", "fontWeight": "bold", "margin": 10},
51
- ),
52
- ],
53
- ),
54
- dbc.ModalFooter(
55
- dbc.Row(
56
- [
57
- dbc.Col(
58
- dbc.Button(
59
- "Close",
60
- id="close-login-modal",
61
- className="me-1",
62
- color="light",
63
- )
64
- ),
65
- dbc.Col(
66
- dbc.Button(
67
- "Login",
68
- id="log-in-btn",
69
- className="me-1",
70
- color="primary",
71
- )
72
- ),
73
- ],
74
- )
75
- ),
76
- ],
77
- is_open=False,
78
- id="login-modal",
79
- )
80
-
81
- logout_modal = dbc.Modal(
82
- [
83
- dbc.ModalFooter(
84
- [
85
- dbc.Button(
86
- "Log out",
87
- id="logout-btn",
88
- color="danger",
89
- className="me-1",
90
- ),
91
- ]
92
- )
93
- ],
94
- is_open=False,
95
- id="logout-modal",
96
- )
97
-
98
- if config is None:
99
- config = {}
100
-
101
- return html.Div(
102
- [
103
- dbc.Row(
104
- [
105
- dbc.Col(
106
- html.H1(
107
- title,
108
- style={
109
- "fontWeight": "bold",
110
- "color": config.get("titleColor", "#d9d9d6"),
111
- "marginLeft": 5,
112
- },
113
- ),
114
- width="auto",
115
- ),
116
- dbc.Col(
117
- dbc.Button(
118
- "Log in",
119
- id="login-btn",
120
- color=config.get("backgroundColor", "#012169"),
121
- style={
122
- "color": config.get("fontColor", "#f2a900"),
123
- "fontSize": "1.2rem",
124
- },
125
- className="me-1",
126
- ),
127
- width="auto",
128
- ),
129
- ],
130
- justify="between",
131
- align="center",
132
- ),
133
- login_modal,
134
- logout_modal,
135
- dcc.Store(id="user-store", storage_type="local", data={}),
136
- ],
137
- style={
138
- "backgroundColor": config.get("backgroundColor", "#012169"),
139
- "padding": 5,
140
- },
141
- )
@@ -1,98 +0,0 @@
1
- # Callbacks for the header component.
2
- from dash import callback, Output, Input, State, no_update
3
- from girder_client import GirderClient
4
- from os import getenv
5
-
6
-
7
- @callback(Output("login-btn", "children"), Input("user-store", "data"))
8
- def check_user_store(data):
9
- # Check if the user store has user info or if no one is logged in.
10
- return data["user"] if len(data) else "Log in"
11
-
12
-
13
- @callback(
14
- [
15
- Output("login-modal", "is_open", allow_duplicate=True),
16
- Output("logout-modal", "is_open", allow_duplicate=True),
17
- ],
18
- [Input("login-btn", "n_clicks"), State("login-btn", "children")],
19
- prevent_initial_call=True,
20
- )
21
- def open_login_modal(n_clicks, children):
22
- # Open login / logout modal.
23
- if n_clicks:
24
- if children == "Log in":
25
- return True, False
26
- else:
27
- return False, True
28
-
29
- return False, False
30
-
31
-
32
- @callback(
33
- [
34
- Output("user-store", "data"),
35
- Output("login-failed", "hidden", allow_duplicate=True),
36
- Output("login-modal", "is_open", allow_duplicate=True),
37
- Output("login", "value", allow_duplicate=True),
38
- Output("password", "value", allow_duplicate=True),
39
- ],
40
- [
41
- Input("log-in-btn", "n_clicks"),
42
- State("login", "value"),
43
- State("password", "value"),
44
- ],
45
- prevent_initial_call=True,
46
- )
47
- def login(n_clicks, login, password):
48
- # Try to login.
49
- gc = GirderClient(apiUrl=getenv("DSA_API_URL"))
50
-
51
- try:
52
- _ = gc.authenticate(username=login, password=password)
53
-
54
- response = gc.get("token/session")
55
-
56
- user = gc.get("user/me")["login"]
57
-
58
- return {"user": user, "token": response["token"]}, True, False, "", ""
59
- except:
60
- return (
61
- {},
62
- False,
63
- True,
64
- no_update,
65
- no_update,
66
- )
67
-
68
-
69
- @callback(
70
- [
71
- Output("login-modal", "is_open", allow_duplicate=True),
72
- Output("login", "value", allow_duplicate=True),
73
- Output("password", "value", allow_duplicate=True),
74
- Output("login-failed", "hidden", allow_duplicate=True),
75
- ],
76
- Input("close-login-modal", "n_clicks"),
77
- prevent_initial_call=True,
78
- )
79
- def close_login_modal(n_clicks):
80
- if n_clicks:
81
- return False, "", "", True
82
-
83
- return False, "", "", True
84
-
85
-
86
- @callback(
87
- [
88
- Output("user-store", "data", allow_duplicate=True),
89
- Output("logout-modal", "is_open", allow_duplicate=True),
90
- ],
91
- Input("logout-btn", "n_clicks"),
92
- prevent_initial_call=True,
93
- )
94
- def logout(n_clicks):
95
- if n_clicks:
96
- return {}, False
97
-
98
- return no_update, False