openms-insight 0.1.4__tar.gz → 0.1.6__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.
- {openms_insight-0.1.4 → openms_insight-0.1.6}/.gitignore +1 -0
- {openms_insight-0.1.4 → openms_insight-0.1.6}/PKG-INFO +101 -2
- {openms_insight-0.1.4 → openms_insight-0.1.6}/README.md +100 -1
- {openms_insight-0.1.4 → openms_insight-0.1.6}/openms_insight/__init__.py +3 -1
- {openms_insight-0.1.4 → openms_insight-0.1.6}/openms_insight/components/__init__.py +2 -0
- {openms_insight-0.1.4 → openms_insight-0.1.6}/openms_insight/components/heatmap.py +69 -15
- openms_insight-0.1.6/openms_insight/components/volcanoplot.py +374 -0
- {openms_insight-0.1.4 → openms_insight-0.1.6}/openms_insight/core/base.py +10 -1
- {openms_insight-0.1.4 → openms_insight-0.1.6}/openms_insight/js-component/dist/assets/index.css +1 -1
- {openms_insight-0.1.4 → openms_insight-0.1.6}/openms_insight/js-component/dist/assets/index.js +148 -139
- {openms_insight-0.1.4 → openms_insight-0.1.6}/openms_insight/preprocessing/__init__.py +6 -0
- openms_insight-0.1.6/openms_insight/preprocessing/scatter.py +136 -0
- {openms_insight-0.1.4 → openms_insight-0.1.6}/openms_insight/rendering/bridge.py +32 -6
- {openms_insight-0.1.4 → openms_insight-0.1.6}/pyproject.toml +1 -1
- {openms_insight-0.1.4 → openms_insight-0.1.6}/LICENSE +0 -0
- {openms_insight-0.1.4 → openms_insight-0.1.6}/openms_insight/components/lineplot.py +0 -0
- {openms_insight-0.1.4 → openms_insight-0.1.6}/openms_insight/components/sequenceview.py +0 -0
- {openms_insight-0.1.4 → openms_insight-0.1.6}/openms_insight/components/table.py +0 -0
- {openms_insight-0.1.4 → openms_insight-0.1.6}/openms_insight/core/__init__.py +0 -0
- {openms_insight-0.1.4 → openms_insight-0.1.6}/openms_insight/core/cache.py +0 -0
- {openms_insight-0.1.4 → openms_insight-0.1.6}/openms_insight/core/registry.py +0 -0
- {openms_insight-0.1.4 → openms_insight-0.1.6}/openms_insight/core/state.py +0 -0
- {openms_insight-0.1.4 → openms_insight-0.1.6}/openms_insight/core/subprocess_preprocess.py +0 -0
- {openms_insight-0.1.4 → openms_insight-0.1.6}/openms_insight/js-component/dist/assets/materialdesignicons-webfont.eot +0 -0
- {openms_insight-0.1.4 → openms_insight-0.1.6}/openms_insight/js-component/dist/assets/materialdesignicons-webfont.ttf +0 -0
- {openms_insight-0.1.4 → openms_insight-0.1.6}/openms_insight/js-component/dist/assets/materialdesignicons-webfont.woff +0 -0
- {openms_insight-0.1.4 → openms_insight-0.1.6}/openms_insight/js-component/dist/assets/materialdesignicons-webfont.woff2 +0 -0
- {openms_insight-0.1.4 → openms_insight-0.1.6}/openms_insight/js-component/dist/index.html +0 -0
- {openms_insight-0.1.4 → openms_insight-0.1.6}/openms_insight/preprocessing/compression.py +0 -0
- {openms_insight-0.1.4 → openms_insight-0.1.6}/openms_insight/preprocessing/filtering.py +0 -0
- {openms_insight-0.1.4 → openms_insight-0.1.6}/openms_insight/rendering/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openms-insight
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.6
|
|
4
4
|
Summary: Interactive visualization components for mass spectrometry data in Streamlit
|
|
5
5
|
Project-URL: Homepage, https://github.com/t0mdavid-m/OpenMS-Insight
|
|
6
6
|
Project-URL: Documentation, https://github.com/t0mdavid-m/OpenMS-Insight#readme
|
|
@@ -50,6 +50,7 @@ Interactive visualization components for mass spectrometry data in Streamlit, ba
|
|
|
50
50
|
- **Table component** (Tabulator.js) with filtering, sorting, go-to, pagination, CSV export
|
|
51
51
|
- **Line plot component** (Plotly.js) with highlighting, annotations, zoom
|
|
52
52
|
- **Heatmap component** (Plotly scattergl) with multi-resolution downsampling for millions of points
|
|
53
|
+
- **Volcano plot component** for differential expression visualization with significance thresholds
|
|
53
54
|
- **Sequence view component** for peptide visualization with fragment ion matching and auto-zoom
|
|
54
55
|
|
|
55
56
|
## Installation
|
|
@@ -62,7 +63,7 @@ pip install openms-insight
|
|
|
62
63
|
|
|
63
64
|
```python
|
|
64
65
|
import streamlit as st
|
|
65
|
-
from openms_insight import Table, LinePlot, StateManager
|
|
66
|
+
from openms_insight import Table, LinePlot, Heatmap, VolcanoPlot, StateManager
|
|
66
67
|
|
|
67
68
|
# Create state manager for cross-component linking
|
|
68
69
|
state_manager = StateManager()
|
|
@@ -169,6 +170,21 @@ Table(
|
|
|
169
170
|
- `pagination`: Enable pagination for large tables (default: True)
|
|
170
171
|
- `page_size`: Rows per page (default: 100)
|
|
171
172
|
|
|
173
|
+
**Custom formatters:**
|
|
174
|
+
In addition to Tabulator's built-in formatters, these custom formatters are available:
|
|
175
|
+
- `scientific`: Exponential notation (e.g., "1.23e-05") - use `formatterParams: {precision: 3}`
|
|
176
|
+
- `signed`: Explicit +/- prefix (e.g., "+1.234") - use `formatterParams: {precision: 3, showPositive: true}`
|
|
177
|
+
- `badge`: Colored pill/badge for categorical values - use `formatterParams: {colorMap: {"Up": "#FF0000"}, defaultColor: "#888"}`
|
|
178
|
+
|
|
179
|
+
```python
|
|
180
|
+
column_definitions=[
|
|
181
|
+
{'field': 'pvalue', 'title': 'P-value', 'formatter': 'scientific', 'formatterParams': {'precision': 2}},
|
|
182
|
+
{'field': 'log2fc', 'title': 'Log2 FC', 'formatter': 'signed', 'formatterParams': {'precision': 3}},
|
|
183
|
+
{'field': 'regulation', 'title': 'Status', 'formatter': 'badge',
|
|
184
|
+
'formatterParams': {'colorMap': {'Up': '#d62728', 'Down': '#1f77b4', 'NS': '#888888'}}},
|
|
185
|
+
]
|
|
186
|
+
```
|
|
187
|
+
|
|
172
188
|
### LinePlot
|
|
173
189
|
|
|
174
190
|
Stick-style line plot using Plotly.js for mass spectra visualization.
|
|
@@ -227,6 +243,80 @@ Heatmap(
|
|
|
227
243
|
- `min_points`: Target size for downsampling (default: 20000)
|
|
228
244
|
- `x_bins`, `y_bins`: Grid resolution for spatial binning
|
|
229
245
|
- `colorscale`: Plotly colorscale name (default: 'Portland')
|
|
246
|
+
- `log_scale`: Use log10 color mapping (default: True). Set to False for linear.
|
|
247
|
+
- `intensity_label`: Custom colorbar label (default: 'Intensity')
|
|
248
|
+
|
|
249
|
+
**Linear scale example:**
|
|
250
|
+
```python
|
|
251
|
+
Heatmap(
|
|
252
|
+
cache_id="psm_scores",
|
|
253
|
+
data_path="psm_data.parquet",
|
|
254
|
+
x_column='rt',
|
|
255
|
+
y_column='mz',
|
|
256
|
+
intensity_column='score',
|
|
257
|
+
log_scale=False, # Linear color mapping
|
|
258
|
+
intensity_label='Score', # Custom colorbar label
|
|
259
|
+
colorscale='Blues',
|
|
260
|
+
)
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
**Categorical mode:**
|
|
264
|
+
Use `category_column` for discrete coloring by category instead of continuous intensity colorscale:
|
|
265
|
+
|
|
266
|
+
```python
|
|
267
|
+
Heatmap(
|
|
268
|
+
cache_id="samples_heatmap",
|
|
269
|
+
data_path="samples.parquet",
|
|
270
|
+
x_column='retention_time',
|
|
271
|
+
y_column='mass',
|
|
272
|
+
intensity_column='intensity',
|
|
273
|
+
category_column='sample_group', # Color by category instead of intensity
|
|
274
|
+
category_colors={ # Optional custom colors
|
|
275
|
+
'Control': '#1f77b4',
|
|
276
|
+
'Treatment_A': '#ff7f0e',
|
|
277
|
+
'Treatment_B': '#2ca02c',
|
|
278
|
+
},
|
|
279
|
+
)
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### VolcanoPlot
|
|
283
|
+
|
|
284
|
+
Interactive volcano plot for differential expression analysis with significance thresholds.
|
|
285
|
+
|
|
286
|
+
```python
|
|
287
|
+
from openms_insight import VolcanoPlot
|
|
288
|
+
|
|
289
|
+
VolcanoPlot(
|
|
290
|
+
cache_id="de_volcano",
|
|
291
|
+
data_path="differential_expression.parquet",
|
|
292
|
+
log2fc_column='log2FC',
|
|
293
|
+
pvalue_column='pvalue',
|
|
294
|
+
label_column='protein_name', # Optional: labels for significant points
|
|
295
|
+
filters={'comparison': 'comparison_id'},
|
|
296
|
+
interactivity={'protein': 'protein_id'},
|
|
297
|
+
title="Differential Expression",
|
|
298
|
+
x_label="Log2 Fold Change",
|
|
299
|
+
y_label="-log10(p-value)",
|
|
300
|
+
up_color='#d62728', # Color for up-regulated
|
|
301
|
+
down_color='#1f77b4', # Color for down-regulated
|
|
302
|
+
ns_color='#888888', # Color for not significant
|
|
303
|
+
)(
|
|
304
|
+
state_manager=state_manager,
|
|
305
|
+
fc_threshold=1.0, # Fold change threshold (render-time)
|
|
306
|
+
p_threshold=0.05, # P-value threshold (render-time)
|
|
307
|
+
max_labels=20, # Max labels to show
|
|
308
|
+
)
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
**Key parameters:**
|
|
312
|
+
- `log2fc_column`: Column with log2 fold change values
|
|
313
|
+
- `pvalue_column`: Column with p-values (automatically converted to -log10)
|
|
314
|
+
- `label_column`: Optional column for point labels
|
|
315
|
+
- `up_color`, `down_color`, `ns_color`: Colors for significance categories
|
|
316
|
+
- `fc_threshold`, `p_threshold`: Significance thresholds (passed at render time, not cached)
|
|
317
|
+
- `max_labels`: Maximum number of labels to display on significant points
|
|
318
|
+
|
|
319
|
+
**Render-time thresholds:** The `fc_threshold` and `p_threshold` are passed via `__call__()`, not `__init__()`. This allows instant threshold adjustment without cache invalidation.
|
|
230
320
|
|
|
231
321
|
### SequenceView
|
|
232
322
|
|
|
@@ -290,6 +380,7 @@ All components accept these common arguments:
|
|
|
290
380
|
| `interactivity` | `Dict[str, str]` | `None` | Map identifier -> column for click actions |
|
|
291
381
|
| `cache_path` | `str` | `"."` | Base directory for cache storage |
|
|
292
382
|
| `regenerate_cache` | `bool` | `False` | Force cache regeneration |
|
|
383
|
+
| `height` | `int` | `400` | Component height in pixels (render-time parameter) |
|
|
293
384
|
|
|
294
385
|
## Memory-Efficient Preprocessing
|
|
295
386
|
|
|
@@ -373,6 +464,14 @@ npm run dev
|
|
|
373
464
|
SVC_DEV_MODE=true SVC_DEV_URL=http://localhost:5173 streamlit run app.py
|
|
374
465
|
```
|
|
375
466
|
|
|
467
|
+
### Debug Mode
|
|
468
|
+
|
|
469
|
+
Enable hash tracking logs to debug data synchronization issues:
|
|
470
|
+
|
|
471
|
+
```bash
|
|
472
|
+
SVC_DEBUG_HASH=true streamlit run app.py
|
|
473
|
+
```
|
|
474
|
+
|
|
376
475
|
### Running Tests
|
|
377
476
|
|
|
378
477
|
```bash
|
|
@@ -15,6 +15,7 @@ Interactive visualization components for mass spectrometry data in Streamlit, ba
|
|
|
15
15
|
- **Table component** (Tabulator.js) with filtering, sorting, go-to, pagination, CSV export
|
|
16
16
|
- **Line plot component** (Plotly.js) with highlighting, annotations, zoom
|
|
17
17
|
- **Heatmap component** (Plotly scattergl) with multi-resolution downsampling for millions of points
|
|
18
|
+
- **Volcano plot component** for differential expression visualization with significance thresholds
|
|
18
19
|
- **Sequence view component** for peptide visualization with fragment ion matching and auto-zoom
|
|
19
20
|
|
|
20
21
|
## Installation
|
|
@@ -27,7 +28,7 @@ pip install openms-insight
|
|
|
27
28
|
|
|
28
29
|
```python
|
|
29
30
|
import streamlit as st
|
|
30
|
-
from openms_insight import Table, LinePlot, StateManager
|
|
31
|
+
from openms_insight import Table, LinePlot, Heatmap, VolcanoPlot, StateManager
|
|
31
32
|
|
|
32
33
|
# Create state manager for cross-component linking
|
|
33
34
|
state_manager = StateManager()
|
|
@@ -134,6 +135,21 @@ Table(
|
|
|
134
135
|
- `pagination`: Enable pagination for large tables (default: True)
|
|
135
136
|
- `page_size`: Rows per page (default: 100)
|
|
136
137
|
|
|
138
|
+
**Custom formatters:**
|
|
139
|
+
In addition to Tabulator's built-in formatters, these custom formatters are available:
|
|
140
|
+
- `scientific`: Exponential notation (e.g., "1.23e-05") - use `formatterParams: {precision: 3}`
|
|
141
|
+
- `signed`: Explicit +/- prefix (e.g., "+1.234") - use `formatterParams: {precision: 3, showPositive: true}`
|
|
142
|
+
- `badge`: Colored pill/badge for categorical values - use `formatterParams: {colorMap: {"Up": "#FF0000"}, defaultColor: "#888"}`
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
column_definitions=[
|
|
146
|
+
{'field': 'pvalue', 'title': 'P-value', 'formatter': 'scientific', 'formatterParams': {'precision': 2}},
|
|
147
|
+
{'field': 'log2fc', 'title': 'Log2 FC', 'formatter': 'signed', 'formatterParams': {'precision': 3}},
|
|
148
|
+
{'field': 'regulation', 'title': 'Status', 'formatter': 'badge',
|
|
149
|
+
'formatterParams': {'colorMap': {'Up': '#d62728', 'Down': '#1f77b4', 'NS': '#888888'}}},
|
|
150
|
+
]
|
|
151
|
+
```
|
|
152
|
+
|
|
137
153
|
### LinePlot
|
|
138
154
|
|
|
139
155
|
Stick-style line plot using Plotly.js for mass spectra visualization.
|
|
@@ -192,6 +208,80 @@ Heatmap(
|
|
|
192
208
|
- `min_points`: Target size for downsampling (default: 20000)
|
|
193
209
|
- `x_bins`, `y_bins`: Grid resolution for spatial binning
|
|
194
210
|
- `colorscale`: Plotly colorscale name (default: 'Portland')
|
|
211
|
+
- `log_scale`: Use log10 color mapping (default: True). Set to False for linear.
|
|
212
|
+
- `intensity_label`: Custom colorbar label (default: 'Intensity')
|
|
213
|
+
|
|
214
|
+
**Linear scale example:**
|
|
215
|
+
```python
|
|
216
|
+
Heatmap(
|
|
217
|
+
cache_id="psm_scores",
|
|
218
|
+
data_path="psm_data.parquet",
|
|
219
|
+
x_column='rt',
|
|
220
|
+
y_column='mz',
|
|
221
|
+
intensity_column='score',
|
|
222
|
+
log_scale=False, # Linear color mapping
|
|
223
|
+
intensity_label='Score', # Custom colorbar label
|
|
224
|
+
colorscale='Blues',
|
|
225
|
+
)
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
**Categorical mode:**
|
|
229
|
+
Use `category_column` for discrete coloring by category instead of continuous intensity colorscale:
|
|
230
|
+
|
|
231
|
+
```python
|
|
232
|
+
Heatmap(
|
|
233
|
+
cache_id="samples_heatmap",
|
|
234
|
+
data_path="samples.parquet",
|
|
235
|
+
x_column='retention_time',
|
|
236
|
+
y_column='mass',
|
|
237
|
+
intensity_column='intensity',
|
|
238
|
+
category_column='sample_group', # Color by category instead of intensity
|
|
239
|
+
category_colors={ # Optional custom colors
|
|
240
|
+
'Control': '#1f77b4',
|
|
241
|
+
'Treatment_A': '#ff7f0e',
|
|
242
|
+
'Treatment_B': '#2ca02c',
|
|
243
|
+
},
|
|
244
|
+
)
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### VolcanoPlot
|
|
248
|
+
|
|
249
|
+
Interactive volcano plot for differential expression analysis with significance thresholds.
|
|
250
|
+
|
|
251
|
+
```python
|
|
252
|
+
from openms_insight import VolcanoPlot
|
|
253
|
+
|
|
254
|
+
VolcanoPlot(
|
|
255
|
+
cache_id="de_volcano",
|
|
256
|
+
data_path="differential_expression.parquet",
|
|
257
|
+
log2fc_column='log2FC',
|
|
258
|
+
pvalue_column='pvalue',
|
|
259
|
+
label_column='protein_name', # Optional: labels for significant points
|
|
260
|
+
filters={'comparison': 'comparison_id'},
|
|
261
|
+
interactivity={'protein': 'protein_id'},
|
|
262
|
+
title="Differential Expression",
|
|
263
|
+
x_label="Log2 Fold Change",
|
|
264
|
+
y_label="-log10(p-value)",
|
|
265
|
+
up_color='#d62728', # Color for up-regulated
|
|
266
|
+
down_color='#1f77b4', # Color for down-regulated
|
|
267
|
+
ns_color='#888888', # Color for not significant
|
|
268
|
+
)(
|
|
269
|
+
state_manager=state_manager,
|
|
270
|
+
fc_threshold=1.0, # Fold change threshold (render-time)
|
|
271
|
+
p_threshold=0.05, # P-value threshold (render-time)
|
|
272
|
+
max_labels=20, # Max labels to show
|
|
273
|
+
)
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
**Key parameters:**
|
|
277
|
+
- `log2fc_column`: Column with log2 fold change values
|
|
278
|
+
- `pvalue_column`: Column with p-values (automatically converted to -log10)
|
|
279
|
+
- `label_column`: Optional column for point labels
|
|
280
|
+
- `up_color`, `down_color`, `ns_color`: Colors for significance categories
|
|
281
|
+
- `fc_threshold`, `p_threshold`: Significance thresholds (passed at render time, not cached)
|
|
282
|
+
- `max_labels`: Maximum number of labels to display on significant points
|
|
283
|
+
|
|
284
|
+
**Render-time thresholds:** The `fc_threshold` and `p_threshold` are passed via `__call__()`, not `__init__()`. This allows instant threshold adjustment without cache invalidation.
|
|
195
285
|
|
|
196
286
|
### SequenceView
|
|
197
287
|
|
|
@@ -255,6 +345,7 @@ All components accept these common arguments:
|
|
|
255
345
|
| `interactivity` | `Dict[str, str]` | `None` | Map identifier -> column for click actions |
|
|
256
346
|
| `cache_path` | `str` | `"."` | Base directory for cache storage |
|
|
257
347
|
| `regenerate_cache` | `bool` | `False` | Force cache regeneration |
|
|
348
|
+
| `height` | `int` | `400` | Component height in pixels (render-time parameter) |
|
|
258
349
|
|
|
259
350
|
## Memory-Efficient Preprocessing
|
|
260
351
|
|
|
@@ -338,6 +429,14 @@ npm run dev
|
|
|
338
429
|
SVC_DEV_MODE=true SVC_DEV_URL=http://localhost:5173 streamlit run app.py
|
|
339
430
|
```
|
|
340
431
|
|
|
432
|
+
### Debug Mode
|
|
433
|
+
|
|
434
|
+
Enable hash tracking logs to debug data synchronization issues:
|
|
435
|
+
|
|
436
|
+
```bash
|
|
437
|
+
SVC_DEBUG_HASH=true streamlit run app.py
|
|
438
|
+
```
|
|
439
|
+
|
|
341
440
|
### Running Tests
|
|
342
441
|
|
|
343
442
|
```bash
|
|
@@ -9,13 +9,14 @@ from .components.heatmap import Heatmap
|
|
|
9
9
|
from .components.lineplot import LinePlot
|
|
10
10
|
from .components.sequenceview import SequenceView, SequenceViewResult
|
|
11
11
|
from .components.table import Table
|
|
12
|
+
from .components.volcanoplot import VolcanoPlot
|
|
12
13
|
from .core.base import BaseComponent
|
|
13
14
|
from .core.cache import CacheMissError
|
|
14
15
|
from .core.registry import get_component_class, register_component
|
|
15
16
|
from .core.state import StateManager
|
|
16
17
|
from .rendering.bridge import clear_component_annotations, get_component_annotations
|
|
17
18
|
|
|
18
|
-
__version__ = "0.1.
|
|
19
|
+
__version__ = "0.1.6"
|
|
19
20
|
|
|
20
21
|
__all__ = [
|
|
21
22
|
# Core
|
|
@@ -28,6 +29,7 @@ __all__ = [
|
|
|
28
29
|
"Table",
|
|
29
30
|
"LinePlot",
|
|
30
31
|
"Heatmap",
|
|
32
|
+
"VolcanoPlot",
|
|
31
33
|
"SequenceView",
|
|
32
34
|
"SequenceViewResult",
|
|
33
35
|
# Utilities
|
|
@@ -86,9 +86,14 @@ class Heatmap(BaseComponent):
|
|
|
86
86
|
x_label: Optional[str] = None,
|
|
87
87
|
y_label: Optional[str] = None,
|
|
88
88
|
colorscale: str = "Portland",
|
|
89
|
+
reversescale: bool = False,
|
|
89
90
|
use_simple_downsample: bool = False,
|
|
90
91
|
use_streaming: bool = True,
|
|
91
92
|
categorical_filters: Optional[List[str]] = None,
|
|
93
|
+
category_column: Optional[str] = None,
|
|
94
|
+
category_colors: Optional[Dict[str, str]] = None,
|
|
95
|
+
log_scale: bool = True,
|
|
96
|
+
intensity_label: Optional[str] = None,
|
|
92
97
|
**kwargs,
|
|
93
98
|
):
|
|
94
99
|
"""
|
|
@@ -133,6 +138,18 @@ class Heatmap(BaseComponent):
|
|
|
133
138
|
are sent to the client regardless of filter selection. Should be
|
|
134
139
|
used for filters with a small number of unique values (<20).
|
|
135
140
|
Example: ['im_dimension'] for ion mobility filtering.
|
|
141
|
+
category_column: Optional column name for categorical coloring.
|
|
142
|
+
When provided, points are colored by discrete category values
|
|
143
|
+
instead of the continuous intensity colorscale. Useful for
|
|
144
|
+
condition-based heatmaps (e.g., coloring by sample group).
|
|
145
|
+
category_colors: Optional mapping of category values to colors.
|
|
146
|
+
Keys should match values in category_column.
|
|
147
|
+
Values should be CSS color strings (e.g., '#FF0000', 'red').
|
|
148
|
+
If not provided, default Plotly colors will be used.
|
|
149
|
+
log_scale: If True (default), apply log10 transformation to intensity
|
|
150
|
+
values for color mapping. Set to False for linear color mapping.
|
|
151
|
+
intensity_label: Custom label for the colorbar. Default is "Intensity".
|
|
152
|
+
Useful when displaying non-intensity values like scores or counts.
|
|
136
153
|
**kwargs: Additional configuration options
|
|
137
154
|
"""
|
|
138
155
|
self._x_column = x_column
|
|
@@ -147,7 +164,12 @@ class Heatmap(BaseComponent):
|
|
|
147
164
|
self._x_label = x_label or x_column
|
|
148
165
|
self._y_label = y_label or y_column
|
|
149
166
|
self._colorscale = colorscale
|
|
167
|
+
self._reversescale = reversescale
|
|
150
168
|
self._use_simple_downsample = use_simple_downsample
|
|
169
|
+
self._category_column = category_column
|
|
170
|
+
self._category_colors = category_colors or {}
|
|
171
|
+
self._log_scale = log_scale
|
|
172
|
+
self._intensity_label = intensity_label
|
|
151
173
|
self._use_streaming = use_streaming
|
|
152
174
|
self._categorical_filters = categorical_filters or []
|
|
153
175
|
|
|
@@ -176,6 +198,8 @@ class Heatmap(BaseComponent):
|
|
|
176
198
|
use_simple_downsample=use_simple_downsample,
|
|
177
199
|
use_streaming=use_streaming,
|
|
178
200
|
categorical_filters=categorical_filters,
|
|
201
|
+
category_column=category_column,
|
|
202
|
+
category_colors=category_colors,
|
|
179
203
|
**kwargs,
|
|
180
204
|
)
|
|
181
205
|
|
|
@@ -202,6 +226,10 @@ class Heatmap(BaseComponent):
|
|
|
202
226
|
"x_label": self._x_label,
|
|
203
227
|
"y_label": self._y_label,
|
|
204
228
|
"colorscale": self._colorscale,
|
|
229
|
+
"category_column": self._category_column,
|
|
230
|
+
"log_scale": self._log_scale,
|
|
231
|
+
"intensity_label": self._intensity_label,
|
|
232
|
+
# Note: category_colors is render-time styling, doesn't affect cache
|
|
205
233
|
}
|
|
206
234
|
|
|
207
235
|
def _restore_cache_config(self, config: Dict[str, Any]) -> None:
|
|
@@ -223,6 +251,10 @@ class Heatmap(BaseComponent):
|
|
|
223
251
|
self._x_label = config.get("x_label", self._x_column)
|
|
224
252
|
self._y_label = config.get("y_label", self._y_column)
|
|
225
253
|
self._colorscale = config.get("colorscale", "Portland")
|
|
254
|
+
self._category_column = config.get("category_column")
|
|
255
|
+
self._log_scale = config.get("log_scale", True)
|
|
256
|
+
self._intensity_label = config.get("intensity_label")
|
|
257
|
+
# category_colors is not stored in cache (render-time styling)
|
|
226
258
|
|
|
227
259
|
def get_state_dependencies(self) -> list:
|
|
228
260
|
"""
|
|
@@ -457,9 +489,7 @@ class Heatmap(BaseComponent):
|
|
|
457
489
|
filtered_total = filtered_data.select(pl.len()).collect().item()
|
|
458
490
|
|
|
459
491
|
# Compute level sizes for this filtered subset (2× for cache buffer)
|
|
460
|
-
level_sizes = compute_compression_levels(
|
|
461
|
-
cache_target, filtered_total
|
|
462
|
-
)
|
|
492
|
+
level_sizes = compute_compression_levels(cache_target, filtered_total)
|
|
463
493
|
|
|
464
494
|
print(
|
|
465
495
|
f"[HEATMAP] Value {filter_value}: {filtered_total:,} pts → levels {level_sizes}",
|
|
@@ -937,12 +967,15 @@ class Heatmap(BaseComponent):
|
|
|
937
967
|
|
|
938
968
|
zoom = state.get(self._zoom_identifier)
|
|
939
969
|
|
|
940
|
-
# Build columns to select
|
|
970
|
+
# Build columns to select (filter out None values)
|
|
941
971
|
columns_to_select = [
|
|
942
|
-
|
|
943
|
-
self._y_column,
|
|
944
|
-
|
|
972
|
+
col
|
|
973
|
+
for col in [self._x_column, self._y_column, self._intensity_column]
|
|
974
|
+
if col is not None
|
|
945
975
|
]
|
|
976
|
+
# Include category column if specified
|
|
977
|
+
if self._category_column and self._category_column not in columns_to_select:
|
|
978
|
+
columns_to_select.append(self._category_column)
|
|
946
979
|
# Include columns needed for interactivity
|
|
947
980
|
if self._interactivity:
|
|
948
981
|
for col in self._interactivity.values():
|
|
@@ -995,17 +1028,25 @@ class Heatmap(BaseComponent):
|
|
|
995
1028
|
columns=columns_to_select,
|
|
996
1029
|
filter_defaults=self._filter_defaults,
|
|
997
1030
|
)
|
|
998
|
-
# Sort by intensity ascending so high-intensity points are drawn on top
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1031
|
+
# Sort by intensity ascending so high-intensity points are drawn on top (scattergl)
|
|
1032
|
+
if (
|
|
1033
|
+
self._intensity_column
|
|
1034
|
+
and self._intensity_column in df_pandas.columns
|
|
1035
|
+
):
|
|
1036
|
+
df_pandas = df_pandas.sort_values(
|
|
1037
|
+
self._intensity_column, ascending=True
|
|
1038
|
+
).reset_index(drop=True)
|
|
1002
1039
|
else:
|
|
1003
1040
|
# No filters to apply - levels already filtered by categorical filter
|
|
1004
1041
|
schema_names = data.collect_schema().names()
|
|
1005
1042
|
available_cols = [c for c in columns_to_select if c in schema_names]
|
|
1006
1043
|
df_polars = data.select(available_cols).collect()
|
|
1007
|
-
# Sort by intensity ascending so high-intensity points are drawn on top
|
|
1008
|
-
|
|
1044
|
+
# Sort by intensity ascending so high-intensity points are drawn on top (scattergl)
|
|
1045
|
+
if (
|
|
1046
|
+
self._intensity_column
|
|
1047
|
+
and self._intensity_column in df_polars.columns
|
|
1048
|
+
):
|
|
1049
|
+
df_polars = df_polars.sort(self._intensity_column)
|
|
1009
1050
|
data_hash = compute_dataframe_hash(df_polars)
|
|
1010
1051
|
df_pandas = df_polars.to_pandas()
|
|
1011
1052
|
else:
|
|
@@ -1017,8 +1058,9 @@ class Heatmap(BaseComponent):
|
|
|
1017
1058
|
# Select only needed columns
|
|
1018
1059
|
available_cols = [c for c in columns_to_select if c in df_polars.columns]
|
|
1019
1060
|
df_polars = df_polars.select(available_cols)
|
|
1020
|
-
# Sort by intensity ascending so high-intensity points are drawn on top
|
|
1021
|
-
|
|
1061
|
+
# Sort by intensity ascending so high-intensity points are drawn on top (scattergl)
|
|
1062
|
+
if self._intensity_column and self._intensity_column in df_polars.columns:
|
|
1063
|
+
df_polars = df_polars.sort(self._intensity_column)
|
|
1022
1064
|
print(
|
|
1023
1065
|
f"[HEATMAP] Selected {len(df_polars)} pts for zoom, levels={level_sizes}",
|
|
1024
1066
|
file=sys.stderr,
|
|
@@ -1046,6 +1088,7 @@ class Heatmap(BaseComponent):
|
|
|
1046
1088
|
"xLabel": self._x_label,
|
|
1047
1089
|
"yLabel": self._y_label,
|
|
1048
1090
|
"colorscale": self._colorscale,
|
|
1091
|
+
"reversescale": self._reversescale,
|
|
1049
1092
|
"zoomIdentifier": self._zoom_identifier,
|
|
1050
1093
|
"interactivity": self._interactivity,
|
|
1051
1094
|
}
|
|
@@ -1053,6 +1096,17 @@ class Heatmap(BaseComponent):
|
|
|
1053
1096
|
if self._title:
|
|
1054
1097
|
args["title"] = self._title
|
|
1055
1098
|
|
|
1099
|
+
# Add category column configuration for categorical coloring mode
|
|
1100
|
+
if self._category_column:
|
|
1101
|
+
args["categoryColumn"] = self._category_column
|
|
1102
|
+
if self._category_colors:
|
|
1103
|
+
args["categoryColors"] = self._category_colors
|
|
1104
|
+
|
|
1105
|
+
# Add log scale and intensity label configuration
|
|
1106
|
+
args["logScale"] = self._log_scale
|
|
1107
|
+
if self._intensity_label:
|
|
1108
|
+
args["intensityLabel"] = self._intensity_label
|
|
1109
|
+
|
|
1056
1110
|
# Add any extra config options
|
|
1057
1111
|
args.update(self._config)
|
|
1058
1112
|
|