openms-insight 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,8 @@
1
+ """Rendering utilities for Python-to-Vue communication."""
2
+
3
+ from .bridge import render_component, get_vue_component_function
4
+
5
+ __all__ = [
6
+ "render_component",
7
+ "get_vue_component_function",
8
+ ]
@@ -0,0 +1,312 @@
1
+ """Bridge between Python components and Vue frontend."""
2
+
3
+ import hashlib
4
+ import json
5
+ import os
6
+ from typing import TYPE_CHECKING, Any, Dict, Optional, Tuple
7
+
8
+ import pandas as pd
9
+ import polars as pl
10
+ import streamlit as st
11
+
12
+
13
+ def _make_hashable(value: Any) -> Any:
14
+ """
15
+ Convert a value to a hashable form for use in cache keys.
16
+
17
+ Handles dicts and lists by converting to JSON strings.
18
+
19
+ Args:
20
+ value: Any value from state
21
+
22
+ Returns:
23
+ A hashable version of the value
24
+ """
25
+ if isinstance(value, dict):
26
+ # Convert dict to sorted JSON string for consistent hashing
27
+ return json.dumps(value, sort_keys=True)
28
+ if isinstance(value, list):
29
+ return json.dumps(value)
30
+ return value
31
+
32
+ if TYPE_CHECKING:
33
+ from ..core.base import BaseComponent
34
+ from ..core.state import StateManager
35
+
36
+
37
+ # Cache the Vue component function
38
+ _vue_component_func = None
39
+
40
+ # Session state key for Vue's echoed hash (what Vue currently has)
41
+ # Used for bidirectional hash confirmation - we only send data when
42
+ # Vue's echoed hash doesn't match the current data hash
43
+ _VUE_ECHOED_HASH_KEY = "_svc_vue_echoed_hashes"
44
+
45
+
46
+
47
+ @st.cache_data(max_entries=10, show_spinner=False)
48
+ def _cached_prepare_vue_data(
49
+ _component: 'BaseComponent',
50
+ component_id: str,
51
+ filter_state_hashable: Tuple[Tuple[str, Any], ...],
52
+ _data_id: int,
53
+ _state_dict: Dict[str, Any],
54
+ ) -> Tuple[Dict[str, Any], str]:
55
+ """
56
+ Cached wrapper for _prepare_vue_data.
57
+
58
+ Cache key is based on:
59
+ - component_id: unique key for this component instance
60
+ - filter_state_hashable: hashable version of state values (for cache key only)
61
+
62
+ The _component, _data_id, and _state_dict parameters are prefixed with underscore
63
+ so they are not hashed (component instances are not hashable, and state_dict
64
+ may contain unhashable values like dicts).
65
+
66
+ Args:
67
+ _component: The component to prepare data for (not hashed)
68
+ component_id: Unique identifier for this component
69
+ filter_state_hashable: Tuple of (identifier, hashable_value) for cache key
70
+ _data_id: id() of the raw data object (not used in cache key)
71
+ _state_dict: Original state dict with actual values (not hashed)
72
+
73
+ Returns:
74
+ Tuple of (vue_data dict, data_hash string)
75
+ """
76
+ # Use the original state dict (not the hashable version)
77
+ vue_data = _component._prepare_vue_data(_state_dict)
78
+
79
+ # Compute hash before any conversion
80
+ data_hash = _hash_data(vue_data)
81
+
82
+ return vue_data, data_hash
83
+
84
+
85
+ def get_vue_component_function():
86
+ """
87
+ Get the Streamlit component function for the Vue frontend.
88
+
89
+ Returns:
90
+ The declared Streamlit component function
91
+ """
92
+ global _vue_component_func
93
+
94
+ if _vue_component_func is None:
95
+ import streamlit.components.v1 as st_components
96
+
97
+ # Check for development mode
98
+ dev_mode = os.environ.get('SVC_DEV_MODE', 'false').lower() == 'true'
99
+
100
+ if dev_mode:
101
+ # Development mode: connect to Vite dev server
102
+ dev_url = os.environ.get('SVC_DEV_URL', 'http://localhost:5173')
103
+ _vue_component_func = st_components.declare_component(
104
+ "streamlit_vue_component",
105
+ url=dev_url,
106
+ )
107
+ else:
108
+ # Production mode: use built component
109
+ parent_dir = os.path.dirname(os.path.abspath(__file__))
110
+ build_dir = os.path.join(parent_dir, '..', 'js-component', 'dist')
111
+
112
+ if not os.path.exists(build_dir):
113
+ raise RuntimeError(
114
+ f"Vue component build not found at {build_dir}. "
115
+ "Please build the Vue component or set SVC_DEV_MODE=true "
116
+ "for development."
117
+ )
118
+
119
+ _vue_component_func = st_components.declare_component(
120
+ "streamlit_vue_component",
121
+ path=build_dir,
122
+ )
123
+
124
+ return _vue_component_func
125
+
126
+
127
+ def render_component(
128
+ component: 'BaseComponent',
129
+ state_manager: 'StateManager',
130
+ key: Optional[str] = None,
131
+ height: Optional[int] = None,
132
+ ) -> Any:
133
+ """
134
+ Render a component in Streamlit.
135
+
136
+ This function:
137
+ 1. Gets current state from StateManager
138
+ 2. Calls component._prepare_vue_data() to get filtered data (cached!)
139
+ 3. Computes hash for change detection
140
+ 4. Only sends data if hash changed from last render (optimization)
141
+ 5. Calls the Vue component with data payload
142
+ 6. Updates StateManager from Vue response
143
+ 7. Triggers st.rerun() if state changed
144
+
145
+ Args:
146
+ component: The component to render
147
+ state_manager: StateManager for cross-component state
148
+ key: Optional unique key for the Streamlit component
149
+ height: Optional height in pixels
150
+
151
+ Returns:
152
+ The value returned by the Vue component
153
+ """
154
+ # Get current state
155
+ state = state_manager.get_state_for_vue()
156
+
157
+ # Generate unique key if not provided (needed for cache)
158
+ # Use cache_id instead of id(component) since components are recreated each rerun
159
+ if key is None:
160
+ key = f"svc_{component._cache_id}_{hash(str(component._interactivity))}"
161
+
162
+ # Extract state keys that affect this component's data for cache key
163
+ # This includes filters and any additional dependencies (e.g., zoom for heatmaps)
164
+ # Uses get_state_dependencies() which can be overridden by subclasses
165
+ state_keys = set(component.get_state_dependencies())
166
+
167
+ # Build hashable version for cache key (converts dicts/lists to JSON strings)
168
+ filter_state_hashable = tuple(sorted(
169
+ (k, _make_hashable(state.get(k))) for k in state_keys
170
+ ))
171
+
172
+ # Build original state dict for passing to _prepare_vue_data
173
+ # (contains actual values, not JSON strings)
174
+ relevant_state = {k: state.get(k) for k in state_keys}
175
+
176
+ # Build component ID for cache (includes type to avoid collisions)
177
+ component_type = component._get_vue_component_name()
178
+ component_id = f"{component_type}:{key}"
179
+
180
+ # Get data identity - cache invalidates if raw data object changes
181
+ data_id = id(component._raw_data)
182
+
183
+ # Get component data using cached function
184
+ # Cache key: (component_id, filter_state_hashable, data_id)
185
+ # - Filterless components: filter_state=() always → always cache hit
186
+ # - Filtered components: cache hit when filter values unchanged
187
+ vue_data, data_hash = _cached_prepare_vue_data(
188
+ component, component_id, filter_state_hashable, data_id, relevant_state
189
+ )
190
+
191
+ component_args = component._get_component_args()
192
+
193
+ # Initialize hash cache in session state if needed
194
+ if _VUE_ECHOED_HASH_KEY not in st.session_state:
195
+ st.session_state[_VUE_ECHOED_HASH_KEY] = {}
196
+
197
+ # Hash tracking key includes filter state so different filter values have separate tracking
198
+ # This ensures data is re-sent when filters change (e.g., different spectrum selected)
199
+ hash_tracking_key = f"{key}:{filter_state_hashable}"
200
+
201
+ # Get Vue's last-echoed hash for this component + filter state
202
+ # This is what Vue reported having in its last response for this exact filter state
203
+ vue_echoed_hash = st.session_state[_VUE_ECHOED_HASH_KEY].get(hash_tracking_key)
204
+
205
+ # Send data if Vue's hash doesn't match current hash
206
+ # This handles: first render, data change, browser refresh, Vue hot reload
207
+ # Vue echoes null/None if it has no data, so mismatch triggers send
208
+ # IMPORTANT: Also send data if vue_echoed_hash is None - this means Vue
209
+ # hasn't confirmed receipt yet (e.g., after page navigation destroys Vue component)
210
+ data_changed = (vue_echoed_hash is None) or (vue_echoed_hash != data_hash)
211
+
212
+ # Only include full data if hash changed
213
+ if data_changed:
214
+ # Convert any non-pandas data to pandas for Arrow serialization
215
+ # pandas DataFrames are passed through (already optimal for Arrow)
216
+ # Also filter out internal keys (starting with _)
217
+ converted_data = {}
218
+ for data_key, value in vue_data.items():
219
+ if data_key.startswith('_'):
220
+ # Skip metadata keys like _hash, _plotConfig
221
+ continue
222
+ if isinstance(value, pl.LazyFrame):
223
+ converted_data[data_key] = value.collect().to_pandas()
224
+ elif isinstance(value, pl.DataFrame):
225
+ converted_data[data_key] = value.to_pandas()
226
+ else:
227
+ converted_data[data_key] = value
228
+ # pandas DataFrames pass through unchanged (optimal for Arrow)
229
+ data_payload = {
230
+ **converted_data,
231
+ 'selection_store': state,
232
+ 'hash': data_hash,
233
+ 'dataChanged': True,
234
+ }
235
+ # Note: We don't pre-set the hash here anymore. We trust Vue's echo
236
+ # at the end of the render cycle. This ensures we detect when Vue
237
+ # loses its data (e.g., page navigation) and needs it resent.
238
+ else:
239
+ # Data unchanged - only send hash and state, Vue will use cached data
240
+ data_payload = {
241
+ 'selection_store': state,
242
+ 'hash': data_hash,
243
+ 'dataChanged': False,
244
+ }
245
+
246
+ # Add height to component args if specified
247
+ if height is not None:
248
+ component_args['height'] = height
249
+
250
+ # Component layout: [[{componentArgs: {...}}]]
251
+ components = [[{'componentArgs': component_args}]]
252
+
253
+ # Call Vue component
254
+ vue_func = get_vue_component_function()
255
+
256
+ kwargs = {
257
+ 'components': components,
258
+ 'key': key,
259
+ **data_payload,
260
+ }
261
+ if height is not None:
262
+ kwargs['height'] = height
263
+
264
+ result = vue_func(**kwargs)
265
+
266
+ # Update state from Vue response
267
+ if result is not None:
268
+ # Store Vue's echoed hash for next render comparison
269
+ # ALWAYS update from Vue's echo - if Vue lost its data (page navigation),
270
+ # it echoes None, and we need to know that to resend data next time
271
+ vue_hash = result.get('_vueDataHash')
272
+ st.session_state[_VUE_ECHOED_HASH_KEY][hash_tracking_key] = vue_hash
273
+
274
+ # Update state and rerun if state changed
275
+ if state_manager.update_from_vue(result):
276
+ st.rerun()
277
+
278
+ return result
279
+
280
+
281
+ def _hash_data(data: Dict[str, Any]) -> str:
282
+ """
283
+ Compute hash of data payload for change detection.
284
+
285
+ Uses efficient hashing based on shape and samples for DataFrames,
286
+ avoiding full data serialization.
287
+
288
+ Args:
289
+ data: The data dict to hash
290
+
291
+ Returns:
292
+ SHA256 hash string
293
+ """
294
+ from ..preprocessing.filtering import compute_dataframe_hash
295
+
296
+ hash_parts = []
297
+ for key, value in sorted(data.items()):
298
+ if key.startswith('_'):
299
+ continue # Skip metadata
300
+ if isinstance(value, pd.DataFrame):
301
+ # Efficient hash for DataFrames
302
+ df_polars = pl.from_pandas(value)
303
+ hash_parts.append(f"{key}:{compute_dataframe_hash(df_polars)}")
304
+ elif isinstance(value, pl.DataFrame):
305
+ hash_parts.append(f"{key}:{compute_dataframe_hash(value)}")
306
+ elif isinstance(value, (list, dict)):
307
+ # For small data, use string repr
308
+ hash_parts.append(f"{key}:{hash(str(value)[:1000])}")
309
+ else:
310
+ hash_parts.append(f"{key}:{hash(str(value))}")
311
+
312
+ return hashlib.sha256("|".join(hash_parts).encode()).hexdigest()
@@ -0,0 +1,256 @@
1
+ Metadata-Version: 2.4
2
+ Name: openms-insight
3
+ Version: 0.1.0
4
+ Summary: Interactive visualization components for mass spectrometry data in Streamlit
5
+ Project-URL: Homepage, https://github.com/t0mdavid-m/OpenMS-Insight
6
+ Project-URL: Documentation, https://github.com/t0mdavid-m/OpenMS-Insight#readme
7
+ Project-URL: Repository, https://github.com/t0mdavid-m/OpenMS-Insight
8
+ Project-URL: Issues, https://github.com/t0mdavid-m/OpenMS-Insight/issues
9
+ Author: Kohlbacher Lab
10
+ License-Expression: BSD-3-Clause
11
+ License-File: LICENSE
12
+ Keywords: mass-spectrometry,openms,plotly,proteomics,streamlit,tabulator,visualization,vue
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: License :: OSI Approved :: BSD License
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
23
+ Classifier: Topic :: Scientific/Engineering :: Visualization
24
+ Requires-Python: >=3.9
25
+ Requires-Dist: pandas>=1.5.0
26
+ Requires-Dist: polars>=0.19.0
27
+ Requires-Dist: streamlit>=1.20.0
28
+ Provides-Extra: dev
29
+ Requires-Dist: black>=23.0.0; extra == 'dev'
30
+ Requires-Dist: mypy>=1.0.0; extra == 'dev'
31
+ Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
32
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
33
+ Requires-Dist: ruff>=0.1.0; extra == 'dev'
34
+ Description-Content-Type: text/markdown
35
+
36
+ # OpenMS-Insight
37
+
38
+ [![PyPI version](https://badge.fury.io/py/openms-insight.svg)](https://badge.fury.io/py/openms-insight)
39
+ [![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/)
40
+
41
+ Interactive visualization components for mass spectrometry data in Streamlit, backed by Vue.js.
42
+
43
+ ## Features
44
+
45
+ - **Cross-component selection linking** via shared identifiers
46
+ - **Polars LazyFrame support** for efficient data handling
47
+ - **Automatic disk caching** with config-based invalidation
48
+ - **Table component** (Tabulator.js) with filtering, sorting, go-to, pagination
49
+ - **Line plot component** (Plotly.js) with highlighting, annotations, zoom
50
+ - **Heatmap component** (Plotly scattergl) with multi-resolution downsampling
51
+ - **Sequence view component** for peptide/protein visualization
52
+
53
+ ## Installation
54
+
55
+ ```bash
56
+ pip install openms-insight
57
+ ```
58
+
59
+ ## Quick Start
60
+
61
+ ```python
62
+ import streamlit as st
63
+ import polars as pl
64
+ from openms_insight import Table, LinePlot, StateManager
65
+
66
+ # Create state manager for cross-component linking
67
+ state_manager = StateManager()
68
+
69
+ # Create a table - clicking a row sets the 'item' selection
70
+ table = Table(
71
+ cache_id="items_table",
72
+ data=pl.scan_parquet("items.parquet"),
73
+ interactivity={'item': 'item_id'},
74
+ column_definitions=[
75
+ {'field': 'item_id', 'title': 'ID', 'sorter': 'number'},
76
+ {'field': 'name', 'title': 'Name'},
77
+ ],
78
+ )
79
+ table(state_manager=state_manager)
80
+
81
+ # Create a linked plot - filters by the selected 'item'
82
+ plot = LinePlot(
83
+ cache_id="values_plot",
84
+ data=pl.scan_parquet("values.parquet"),
85
+ filters={'item': 'item_id'},
86
+ x_column='x',
87
+ y_column='y',
88
+ )
89
+ plot(state_manager=state_manager)
90
+ ```
91
+
92
+ ## Cross-Component Linking
93
+
94
+ Components communicate through **identifiers** using two mechanisms:
95
+
96
+ - **`filters`**: INPUT - filter this component's data by the selection
97
+ - **`interactivity`**: OUTPUT - set a selection when user clicks
98
+
99
+ ```python
100
+ # Master table: no filters, sets 'spectrum' on click
101
+ master = Table(
102
+ cache_id="spectra",
103
+ data=spectra_data,
104
+ interactivity={'spectrum': 'scan_id'}, # Click -> sets spectrum=scan_id
105
+ )
106
+
107
+ # Detail table: filters by 'spectrum', sets 'peak' on click
108
+ detail = Table(
109
+ cache_id="peaks",
110
+ data=peaks_data,
111
+ filters={'spectrum': 'scan_id'}, # Filters where scan_id = selected spectrum
112
+ interactivity={'peak': 'peak_id'}, # Click -> sets peak=peak_id
113
+ )
114
+
115
+ # Plot: filters by 'spectrum', highlights selected 'peak'
116
+ plot = LinePlot(
117
+ cache_id="plot",
118
+ data=peaks_data,
119
+ filters={'spectrum': 'scan_id'},
120
+ interactivity={'peak': 'peak_id'},
121
+ x_column='mass',
122
+ y_column='intensity',
123
+ )
124
+ ```
125
+
126
+ ---
127
+
128
+ ## Components
129
+
130
+ ### Table
131
+
132
+ Interactive table using Tabulator.js with filtering dialogs, sorting, pagination, and CSV export.
133
+
134
+ ```python
135
+ Table(
136
+ cache_id="spectra_table",
137
+ data=pl.scan_parquet("spectra.parquet"),
138
+ interactivity={'spectrum': 'scan_id'},
139
+ column_definitions=[
140
+ {'field': 'scan_id', 'title': 'Scan', 'sorter': 'number'},
141
+ {'field': 'rt', 'title': 'RT (min)', 'sorter': 'number', 'hozAlign': 'right'},
142
+ {'field': 'precursor_mz', 'title': 'm/z', 'sorter': 'number'},
143
+ ],
144
+ index_field='scan_id',
145
+ go_to_fields=['scan_id'],
146
+ default_row=0,
147
+ pagination=True,
148
+ page_size=50,
149
+ )
150
+ ```
151
+
152
+ ### LinePlot
153
+
154
+ Stick-style line plot using Plotly.js for mass spectra visualization.
155
+
156
+ ```python
157
+ LinePlot(
158
+ cache_id="spectrum_plot",
159
+ data=pl.scan_parquet("peaks.parquet"),
160
+ filters={'spectrum': 'scan_id'},
161
+ interactivity={'peak': 'peak_id'},
162
+ x_column='mass',
163
+ y_column='intensity',
164
+ highlight_column='is_annotated',
165
+ annotation_column='ion_label',
166
+ title="MS/MS Spectrum",
167
+ x_label="m/z",
168
+ y_label="Intensity",
169
+ )
170
+ ```
171
+
172
+ ### Heatmap
173
+
174
+ 2D scatter heatmap using Plotly scattergl with multi-resolution downsampling for large datasets (millions of points).
175
+
176
+ ```python
177
+ Heatmap(
178
+ cache_id="peaks_heatmap",
179
+ data=pl.scan_parquet("all_peaks.parquet"),
180
+ x_column='retention_time',
181
+ y_column='mass',
182
+ intensity_column='intensity',
183
+ interactivity={'spectrum': 'scan_id', 'peak': 'peak_id'},
184
+ min_points=30000,
185
+ title="Peak Map",
186
+ x_label="Retention Time (min)",
187
+ y_label="m/z",
188
+ )
189
+ ```
190
+
191
+ ### SequenceView
192
+
193
+ Peptide/protein sequence visualization with fragment ion matching.
194
+
195
+ ```python
196
+ SequenceView(
197
+ cache_id="peptide_view",
198
+ sequence="PEPTIDEK",
199
+ observed_masses=[147.1, 244.2, 359.3, 456.4],
200
+ peak_ids=[0, 1, 2, 3],
201
+ precursor_mass=944.5,
202
+ interactivity={'peak': 'peak_id'},
203
+ title="Fragment Coverage",
204
+ )
205
+ ```
206
+
207
+ ---
208
+
209
+ ## Shared Component Arguments
210
+
211
+ All components accept these common arguments:
212
+
213
+ | Argument | Type | Default | Description |
214
+ |----------|------|---------|-------------|
215
+ | `cache_id` | `str` | **Required** | Unique identifier for disk cache |
216
+ | `data` | `pl.LazyFrame` | `None` | Polars LazyFrame with source data |
217
+ | `filters` | `Dict[str, str]` | `None` | Map identifier -> column for filtering |
218
+ | `interactivity` | `Dict[str, str]` | `None` | Map identifier -> column for click actions |
219
+ | `cache_path` | `str` | `"."` | Base directory for cache storage |
220
+
221
+ ## Rendering
222
+
223
+ All components are callable. Pass a `StateManager` to enable cross-component linking:
224
+
225
+ ```python
226
+ from openms_insight import StateManager
227
+
228
+ state_manager = StateManager()
229
+
230
+ table(state_manager=state_manager, height=300)
231
+ plot(state_manager=state_manager, height=400)
232
+ ```
233
+
234
+ ---
235
+
236
+ ## Development
237
+
238
+ ### Building the Vue Component
239
+
240
+ ```bash
241
+ cd js-component
242
+ npm install
243
+ npm run build
244
+ ```
245
+
246
+ ### Development Mode
247
+
248
+ ```bash
249
+ cd js-component
250
+ npm run dev
251
+
252
+ # In another terminal:
253
+ export SVC_DEV_MODE=true
254
+ export SVC_DEV_URL=http://localhost:5173
255
+ streamlit run app.py
256
+ ```
@@ -0,0 +1,27 @@
1
+ openms_insight/__init__.py,sha256=-QMPUfCk1DwwlQKW6NFSZodRz-r82R4rJPOiWDf_mwA,830
2
+ openms_insight/components/__init__.py,sha256=aNy1E8ttqQiiA5Ka9sviRy17gQT8lfc_EHsl1v1o-UQ,177
3
+ openms_insight/components/heatmap.py,sha256=wqNgmccxI5PeTC08kVf06UUtVEg8YhUf_eY9CN4wAMw,33125
4
+ openms_insight/components/lineplot.py,sha256=klGzpGO-gi76sIocr9T4TYUTV-ztfIIAtdd5k-U-aGE,19382
5
+ openms_insight/components/sequenceview.py,sha256=IPLyUiXTLYwdZ79B3pZDH1intUsjBIknTSLUQ2ftdD4,14359
6
+ openms_insight/components/table.py,sha256=VaUbn2lckeT3shqn9quDvw1HGMsiQrIPPK4w1XQFzzc,14795
7
+ openms_insight/core/__init__.py,sha256=yKRgLfRm1CQm6ZGqQiyDwblzw2Qh3jw57U-ZSd63PYk,338
8
+ openms_insight/core/base.py,sha256=e939N2cu0TEllj09Uw7AKS0FqxE2n_XecwF3ckM_YM0,14746
9
+ openms_insight/core/cache.py,sha256=3fnPDWjuWUnxazK2XflcUIeRZZPQ3N45kAKYu-xGBKw,1197
10
+ openms_insight/core/registry.py,sha256=iBb9xWvgOisxjVX74wtCvqWO20eBW5xH-XcNcVuW-Dg,2107
11
+ openms_insight/core/state.py,sha256=VhY_3Yg-zbx9VsdqHElsNyD2UbJj6ApE4TRcUywDrjQ,6871
12
+ openms_insight/preprocessing/__init__.py,sha256=XFnxlvG-VRMrFbreGmFSIDqfYhev8WPUyZluadMmCgY,462
13
+ openms_insight/preprocessing/compression.py,sha256=8oe-vqeSX-Xf1okPX0C0km2DRnl6Iz53Y1UgsLdMUPI,10499
14
+ openms_insight/preprocessing/filtering.py,sha256=chvmCqLLsMe5mXwG_S4KUagNqJZFLI_iLKKr9g-MkLM,10907
15
+ openms_insight/rendering/__init__.py,sha256=i9MRFrAEAX5kjbOnMjw2woP_6mEaI6HcxtbrNwUxNaM,198
16
+ openms_insight/rendering/bridge.py,sha256=yzXPyK_oKVGBymeDWxgzXeI_jOP7ntJ4p_npOQ1-d1A,11279
17
+ openms_insight/js-component/dist/index.html,sha256=LSJ3B_YmGUrCCdZ1UaZO2p6Wqsih6nTH62Z_0uZxpD8,430
18
+ openms_insight/js-component/dist/assets/index.css,sha256=h0LrX503uebeJrJB0LtoPCVwA4QfDBMmOOR_tU2Wkic,883995
19
+ openms_insight/js-component/dist/assets/index.js,sha256=pakZe7BdeEjiDCPhzGYqEFumB3WtbdnnXYnBuTDVfWo,6060653
20
+ openms_insight/js-component/dist/assets/materialdesignicons-webfont.eot,sha256=CxgxBNL8XyYZbnc8d72vLgVQn9QlnS0V7O3Kebh-hPk,1307880
21
+ openms_insight/js-component/dist/assets/materialdesignicons-webfont.ttf,sha256=YeirpaTpgf4iz3yOi82-oAR251xiw38Bv37jM2HWhCg,1307660
22
+ openms_insight/js-component/dist/assets/materialdesignicons-webfont.woff,sha256=pZKKDVwvYk5G-Y2bFcL2AEU3f3xZTdeKF1kTLqO0Y-s,587984
23
+ openms_insight/js-component/dist/assets/materialdesignicons-webfont.woff2,sha256=Zi_vqPL4qVwYWI0hd0eJwQfGTnccvmWmmvRikcQxGvw,403216
24
+ openms_insight-0.1.0.dist-info/METADATA,sha256=S7rH1PAk9nJDomrQSDnJFmiGC7v8JcwnfrGcBqe55iM,7288
25
+ openms_insight-0.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
26
+ openms_insight-0.1.0.dist-info/licenses/LICENSE,sha256=INFF4rOMmpah7Oi14hLqu7NTOsx56KRRNChAAUcfh2E,1823
27
+ openms_insight-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.28.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,29 @@
1
+ --------------------------------------------------------------------------
2
+ OpenMS -- Open-Source Mass Spectrometry
3
+ --------------------------------------------------------------------------
4
+ Copyright OpenMS Inc. -- Eberhard Karls University Tuebingen,
5
+ ETH Zurich, and Freie Universitaet Berlin 2002-present.
6
+
7
+ This software is released under a three-clause BSD license:
8
+ * Redistributions of source code must retain the above copyright
9
+ notice, this list of conditions and the following disclaimer.
10
+ * Redistributions in binary form must reproduce the above copyright
11
+ notice, this list of conditions and the following disclaimer in the
12
+ documentation and/or other materials provided with the distribution.
13
+ * Neither the name of any author or any participating institution
14
+ may be used to endorse or promote products derived from this software
15
+ without specific prior written permission.
16
+ For a full list of authors, refer to the git contributions.
17
+ --------------------------------------------------------------------------
18
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
+ ARE DISCLAIMED. IN NO EVENT SHALL ANY OF THE AUTHORS OR THE CONTRIBUTING
22
+ INSTITUTIONS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25
+ OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
27
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
28
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
+