Skip to content

Commit 2e36cb2

Browse files
authored
Plugin class (#350)
* WIP: class to encapsulate widget logic * Potentially working widget things * Example of chat plugin * Lint * Update * Update
1 parent 31bd2cc commit 2e36cb2

File tree

8 files changed

+454
-34
lines changed

8 files changed

+454
-34
lines changed

.coveragerc_omit

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ omit =
1010
vitessce/data_utils/anndata.py
1111
vitessce/data_utils/ome.py
1212
vitessce/data_utils/entities.py
13-
vitessce/data_utils/multivec.py
13+
vitessce/data_utils/multivec.py
14+
vitessce/widget_plugins/demo_plugin.py
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"metadata": {
6+
"nbsphinx": "hidden"
7+
},
8+
"source": [
9+
"# Vitessce Widget Tutorial"
10+
]
11+
},
12+
{
13+
"cell_type": "code",
14+
"execution_count": 18,
15+
"metadata": {},
16+
"outputs": [],
17+
"source": [
18+
"from vitessce import (\n",
19+
" VitessceConfig,\n",
20+
" Component as cm,\n",
21+
" CoordinationType as ct,\n",
22+
" OmeTiffWrapper,\n",
23+
" MultiImageWrapper,\n",
24+
" VitesscePlugin\n",
25+
")\n",
26+
"from esbuild_py import transform"
27+
]
28+
},
29+
{
30+
"cell_type": "code",
31+
"execution_count": 40,
32+
"metadata": {},
33+
"outputs": [],
34+
"source": [
35+
"PLUGIN_ESM = transform(\"\"\"\n",
36+
"function createPlugins(utilsForPlugins) {\n",
37+
" const {\n",
38+
" React,\n",
39+
" PluginFileType,\n",
40+
" PluginViewType,\n",
41+
" PluginCoordinationType,\n",
42+
" PluginJointFileType,\n",
43+
" z,\n",
44+
" useCoordination,\n",
45+
" invokeCommand,\n",
46+
" } = utilsForPlugins;\n",
47+
" \n",
48+
" const CSS = `\n",
49+
" .chat {\n",
50+
" overflow-y: scroll;\n",
51+
" }\n",
52+
" `;\n",
53+
" \n",
54+
" function ChatView(props) {\n",
55+
" \n",
56+
" const [nextMessage, setNextMessage] = React.useState('');\n",
57+
" const [isLoading, setIsLoading] = React.useState(false);\n",
58+
" const [chatHistory, setChatHistory] = React.useState([]); // chatHistory is an array of message objects like [{ user, text }, ...]\n",
59+
" \n",
60+
" async function handleClick() { \n",
61+
" setChatHistory(prev => ([\n",
62+
" ...prev,\n",
63+
" { user: 'You', text: nextMessage },\n",
64+
" ]));\n",
65+
" setIsLoading(true);\n",
66+
" const [chatReceiveValue, chatReceiveBuffers] = await invokeCommand(\"chat_send\", nextMessage, []);\n",
67+
" setChatHistory(prev => ([\n",
68+
" ...prev,\n",
69+
" { user: 'AI', text: chatReceiveValue.text },\n",
70+
" ]));\n",
71+
" setIsLoading(false);\n",
72+
" }\n",
73+
" \n",
74+
" return (\n",
75+
" <>\n",
76+
" <style>{CSS}</style>\n",
77+
" <div className=\"chat\">\n",
78+
" <p>Chat view</p>\n",
79+
" <div>\n",
80+
" {chatHistory.map(message => (\n",
81+
" <p key={`${message.user}-${message.text}`}>\n",
82+
" <b>{message.user}</b>:\n",
83+
" <span>{message.text}</span>\n",
84+
" </p>\n",
85+
" ))}\n",
86+
" </div>\n",
87+
" <input type=\"text\" value={nextMessage} onChange={e => setNextMessage(e.target.value)} disabled={isLoading} />\n",
88+
" <button onClick={handleClick}>Send message</button>\n",
89+
" </div>\n",
90+
" </>\n",
91+
" );\n",
92+
" }\n",
93+
"\n",
94+
" const pluginViewTypes = [\n",
95+
" new PluginViewType('chat', ChatView, []),\n",
96+
" ];\n",
97+
" return { pluginViewTypes };\n",
98+
"}\n",
99+
"export default { createPlugins };\n",
100+
"\"\"\")\n",
101+
"\n",
102+
"\n",
103+
"def handle_chat_message(message, buffers):\n",
104+
" return { \"text\": message.upper() }, []\n",
105+
"\n",
106+
"\n",
107+
"class ChatPlugin(VitesscePlugin):\n",
108+
" plugin_esm = PLUGIN_ESM\n",
109+
" commands = {\n",
110+
" \"chat_send\": handle_chat_message,\n",
111+
" }"
112+
]
113+
},
114+
{
115+
"cell_type": "code",
116+
"execution_count": 41,
117+
"metadata": {},
118+
"outputs": [],
119+
"source": [
120+
"vc = VitessceConfig(schema_version=\"1.0.15\", name='Spraggins Multi-Modal', description='PAS + IMS + AF From https://portal.hubmapconsortium.org/browse/collection/6a6efd0c1a2681dc7d2faab8e4ab0bca')\n",
121+
"dataset = vc.add_dataset(name='Spraggins').add_object(\n",
122+
" MultiImageWrapper(\n",
123+
" image_wrappers=[\n",
124+
" OmeTiffWrapper(img_url='https://assets.hubmapconsortium.org/f4188a148e4c759092d19369d310883b/ometiff-pyramids/processedMicroscopy/VAN0006-LK-2-85-PAS_images/VAN0006-LK-2-85-PAS_registered.ome.tif?token=', name='PAS'),\n",
125+
" OmeTiffWrapper(img_url='https://assets.hubmapconsortium.org/2130d5f91ce61d7157a42c0497b06de8/ometiff-pyramids/processedMicroscopy/VAN0006-LK-2-85-AF_preIMS_images/VAN0006-LK-2-85-AF_preIMS_registered.ome.tif?token=', name='AF'),\n",
126+
" OmeTiffWrapper(img_url='https://assets.hubmapconsortium.org/be503a021ed910c0918842e318e6efa2/ometiff-pyramids/ometiffs/VAN0006-LK-2-85-IMS_PosMode_multilayer.ome.tif?token=', name='IMS Pos Mode'),\n",
127+
" OmeTiffWrapper(img_url='https://assets.hubmapconsortium.org/ca886a630b2038997a4cfbbf4abfd283/ometiff-pyramids/ometiffs/VAN0006-LK-2-85-IMS_NegMode_multilayer.ome.tif?token=', name='IMS Neg Mode')\n",
128+
" ],\n",
129+
" use_physical_size_scaling=True,\n",
130+
" )\n",
131+
")\n",
132+
"spatial = vc.add_view(cm.SPATIAL, dataset=dataset)\n",
133+
"status = vc.add_view(\"chat\", dataset=dataset)\n",
134+
"lc = vc.add_view(cm.LAYER_CONTROLLER, dataset=dataset).set_props(disableChannelsIfRgbDetected=True)\n",
135+
"vc.layout(spatial | (lc / status));"
136+
]
137+
},
138+
{
139+
"cell_type": "markdown",
140+
"metadata": {},
141+
"source": [
142+
"## 2. Create the Vitessce widget"
143+
]
144+
},
145+
{
146+
"cell_type": "code",
147+
"execution_count": 42,
148+
"metadata": {},
149+
"outputs": [
150+
{
151+
"data": {
152+
"application/vnd.jupyter.widget-view+json": {
153+
"model_id": "52bbdb1e3f91423b8dd934e3a4ff796e",
154+
"version_major": 2,
155+
"version_minor": 1
156+
},
157+
"text/plain": [
158+
"VitessceWidget(config={'version': '1.0.15', 'name': 'Spraggins Multi-Modal', 'description': 'PAS + IMS + AF Fr…"
159+
]
160+
},
161+
"execution_count": 42,
162+
"metadata": {},
163+
"output_type": "execute_result"
164+
}
165+
],
166+
"source": [
167+
"vw = vc.widget(plugins=[ChatPlugin()])\n",
168+
"vw"
169+
]
170+
},
171+
{
172+
"cell_type": "code",
173+
"execution_count": null,
174+
"metadata": {},
175+
"outputs": [],
176+
"source": []
177+
},
178+
{
179+
"cell_type": "code",
180+
"execution_count": null,
181+
"metadata": {},
182+
"outputs": [],
183+
"source": []
184+
}
185+
],
186+
"metadata": {
187+
"kernelspec": {
188+
"display_name": "Python 3 (ipykernel)",
189+
"language": "python",
190+
"name": "python3"
191+
},
192+
"language_info": {
193+
"codemirror_mode": {
194+
"name": "ipython",
195+
"version": 3
196+
},
197+
"file_extension": ".py",
198+
"mimetype": "text/x-python",
199+
"name": "python",
200+
"nbconvert_exporter": "python",
201+
"pygments_lexer": "ipython3",
202+
"version": "3.9.0"
203+
}
204+
},
205+
"nbformat": 4,
206+
"nbformat_minor": 4
207+
}
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"metadata": {
6+
"nbsphinx": "hidden"
7+
},
8+
"source": [
9+
"# Vitessce Widget Tutorial"
10+
]
11+
},
12+
{
13+
"cell_type": "markdown",
14+
"metadata": {},
15+
"source": [
16+
"# Visualization of Multi-Modal Imaging Data\n",
17+
"We visualize IMS, PAS, and AF imaging data overlaid from the Spraggins Lab of the Biomolecular Multimodal Imaging Center (BIOMC) at Vanderbilt University, uploaded to the HuBMAP data portal."
18+
]
19+
},
20+
{
21+
"cell_type": "code",
22+
"execution_count": 1,
23+
"metadata": {},
24+
"outputs": [],
25+
"source": [
26+
"from vitessce import (\n",
27+
" VitessceConfig,\n",
28+
" Component as cm,\n",
29+
" CoordinationType as ct,\n",
30+
" OmeTiffWrapper,\n",
31+
" MultiImageWrapper,\n",
32+
")\n",
33+
"from os.path import join"
34+
]
35+
},
36+
{
37+
"cell_type": "code",
38+
"execution_count": 2,
39+
"metadata": {},
40+
"outputs": [],
41+
"source": [
42+
"from vitessce.widget_plugins import DemoPlugin"
43+
]
44+
},
45+
{
46+
"cell_type": "markdown",
47+
"metadata": {},
48+
"source": [
49+
"## 1. Configure Vitessce\n",
50+
"Set up the images from the three different assays, with the `use_physical_size_scaling` set to `True` so that the IMS image scales to the other images based on their physical sizes."
51+
]
52+
},
53+
{
54+
"cell_type": "code",
55+
"execution_count": 3,
56+
"metadata": {},
57+
"outputs": [],
58+
"source": [
59+
"vc = VitessceConfig(schema_version=\"1.0.15\", name='Spraggins Multi-Modal', description='PAS + IMS + AF From https://portal.hubmapconsortium.org/browse/collection/6a6efd0c1a2681dc7d2faab8e4ab0bca')\n",
60+
"dataset = vc.add_dataset(name='Spraggins').add_object(\n",
61+
" MultiImageWrapper(\n",
62+
" image_wrappers=[\n",
63+
" OmeTiffWrapper(img_url='https://assets.hubmapconsortium.org/f4188a148e4c759092d19369d310883b/ometiff-pyramids/processedMicroscopy/VAN0006-LK-2-85-PAS_images/VAN0006-LK-2-85-PAS_registered.ome.tif?token=', name='PAS'),\n",
64+
" OmeTiffWrapper(img_url='https://assets.hubmapconsortium.org/2130d5f91ce61d7157a42c0497b06de8/ometiff-pyramids/processedMicroscopy/VAN0006-LK-2-85-AF_preIMS_images/VAN0006-LK-2-85-AF_preIMS_registered.ome.tif?token=', name='AF'),\n",
65+
" OmeTiffWrapper(img_url='https://assets.hubmapconsortium.org/be503a021ed910c0918842e318e6efa2/ometiff-pyramids/ometiffs/VAN0006-LK-2-85-IMS_PosMode_multilayer.ome.tif?token=', name='IMS Pos Mode'),\n",
66+
" OmeTiffWrapper(img_url='https://assets.hubmapconsortium.org/ca886a630b2038997a4cfbbf4abfd283/ometiff-pyramids/ometiffs/VAN0006-LK-2-85-IMS_NegMode_multilayer.ome.tif?token=', name='IMS Neg Mode')\n",
67+
" ],\n",
68+
" use_physical_size_scaling=True,\n",
69+
" )\n",
70+
")\n",
71+
"spatial = vc.add_view(cm.SPATIAL, dataset=dataset)\n",
72+
"status = vc.add_view(\"demo\", dataset=dataset)\n",
73+
"lc = vc.add_view(cm.LAYER_CONTROLLER, dataset=dataset).set_props(disableChannelsIfRgbDetected=True)\n",
74+
"vc.layout(spatial | (lc / status));"
75+
]
76+
},
77+
{
78+
"cell_type": "markdown",
79+
"metadata": {},
80+
"source": [
81+
"## 2. Create the Vitessce widget"
82+
]
83+
},
84+
{
85+
"cell_type": "code",
86+
"execution_count": 4,
87+
"metadata": {},
88+
"outputs": [
89+
{
90+
"data": {
91+
"application/vnd.jupyter.widget-view+json": {
92+
"model_id": "837fec6d047c4f83be8530996e324fb9",
93+
"version_major": 2,
94+
"version_minor": 1
95+
},
96+
"text/plain": [
97+
"VitessceWidget(config={'version': '1.0.15', 'name': 'Spraggins Multi-Modal', 'description': 'PAS + IMS + AF Fr…"
98+
]
99+
},
100+
"execution_count": 4,
101+
"metadata": {},
102+
"output_type": "execute_result"
103+
}
104+
],
105+
"source": [
106+
"vw = vc.widget(plugins=[DemoPlugin()])\n",
107+
"vw"
108+
]
109+
},
110+
{
111+
"cell_type": "code",
112+
"execution_count": null,
113+
"metadata": {},
114+
"outputs": [],
115+
"source": []
116+
}
117+
],
118+
"metadata": {
119+
"kernelspec": {
120+
"display_name": "Python 3 (ipykernel)",
121+
"language": "python",
122+
"name": "python3"
123+
},
124+
"language_info": {
125+
"codemirror_mode": {
126+
"name": "ipython",
127+
"version": 3
128+
},
129+
"file_extension": ".py",
130+
"mimetype": "text/x-python",
131+
"name": "python",
132+
"nbconvert_exporter": "python",
133+
"pygments_lexer": "ipython3",
134+
"version": "3.9.0"
135+
}
136+
},
137+
"nbformat": 4,
138+
"nbformat_minor": 4
139+
}

pyproject.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "vitessce"
7-
version = "3.2.8"
7+
version = "3.3.0"
88
authors = [
99
{ name="Mark Keller", email="[email protected]" },
1010
]
@@ -19,10 +19,11 @@ classifiers = [
1919
'Intended Audience :: Developers',
2020
'Intended Audience :: Science/Research',
2121
'Topic :: Multimedia :: Graphics',
22-
'Programming Language :: Python :: 3.7',
2322
'Programming Language :: Python :: 3.8',
2423
'Programming Language :: Python :: 3.9',
2524
'Programming Language :: Python :: 3.10',
25+
'Programming Language :: Python :: 3.11',
26+
'Programming Language :: Python :: 3.12',
2627
]
2728
dependencies = [
2829
'zarr>=2.5.0',

vitessce/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
# We allow installation without all of the dependencies that the widget requires.
3838
# The imports below will fail in that case, and corresponding globals will be undefined.
3939
try:
40-
from .widget import VitessceWidget, data_server
40+
from .widget import VitessceWidget, VitesscePlugin, data_server
4141
except ModuleNotFoundError as e: # pragma: no cover
4242
warn(f'Extra installs are necessary to use widgets: {e}')
4343

0 commit comments

Comments
 (0)