masster 0.4.10__py3-none-any.whl → 0.4.11__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.

Potentially problematic release.


This version of masster might be problematic. Click here for more details.

masster/_version.py CHANGED
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
 
4
- __version__ = "0.4.10"
4
+ __version__ = "0.4.11"
5
5
 
6
6
 
7
7
  def get_version():
@@ -1,95 +1,95 @@
1
1
  {
2
2
  "features_df": {
3
3
  "columns": {
4
- "adduct": {
5
- "dtype": "pl.Utf8"
6
- },
7
- "adduct_charge": {
8
- "dtype": "pl.Int64"
9
- },
10
- "adduct_group": {
4
+ "feature_uid": {
11
5
  "dtype": "pl.Int64"
12
6
  },
13
- "adduct_mass_neutral": {
14
- "dtype": "pl.Float64"
15
- },
16
- "adduct_mass_shift": {
17
- "dtype": "pl.Float64"
7
+ "feature_id": {
8
+ "dtype": "pl.Utf8"
18
9
  },
19
- "charge": {
10
+ "sample_uid": {
20
11
  "dtype": "pl.Int32"
21
12
  },
22
- "chrom": {
23
- "dtype": "pl.Object"
24
- },
25
- "chrom_area": {
13
+ "mz": {
26
14
  "dtype": "pl.Float64"
27
15
  },
28
- "chrom_coherence": {
16
+ "rt": {
29
17
  "dtype": "pl.Float64"
30
18
  },
31
- "chrom_height_scaled": {
19
+ "rt_original": {
32
20
  "dtype": "pl.Float64"
33
21
  },
34
- "chrom_prominence": {
22
+ "rt_start": {
35
23
  "dtype": "pl.Float64"
36
24
  },
37
- "chrom_prominence_scaled": {
25
+ "rt_end": {
38
26
  "dtype": "pl.Float64"
39
27
  },
40
- "feature_id": {
41
- "dtype": "pl.Utf8"
28
+ "rt_delta": {
29
+ "dtype": "pl.Float64"
42
30
  },
43
- "feature_uid": {
44
- "dtype": "pl.Int64"
31
+ "mz_start": {
32
+ "dtype": "pl.Float64"
45
33
  },
46
- "filled": {
47
- "dtype": "pl.Boolean"
34
+ "mz_end": {
35
+ "dtype": "pl.Float64"
48
36
  },
49
37
  "inty": {
50
38
  "dtype": "pl.Float64"
51
39
  },
40
+ "quality": {
41
+ "dtype": "pl.Float64"
42
+ },
43
+ "charge": {
44
+ "dtype": "pl.Int32"
45
+ },
52
46
  "iso": {
53
47
  "dtype": "pl.Int64"
54
48
  },
55
49
  "iso_of": {
56
50
  "dtype": "pl.Int64"
57
51
  },
58
- "ms2_scans": {
59
- "dtype": "pl.Object"
52
+ "adduct": {
53
+ "dtype": "pl.Utf8"
60
54
  },
61
- "ms2_specs": {
62
- "dtype": "pl.Object"
55
+ "adduct_charge": {
56
+ "dtype": "pl.Int64"
63
57
  },
64
- "mz": {
58
+ "adduct_mass_shift": {
65
59
  "dtype": "pl.Float64"
66
60
  },
67
- "mz_end": {
61
+ "adduct_mass_neutral": {
68
62
  "dtype": "pl.Float64"
69
63
  },
70
- "mz_start": {
71
- "dtype": "pl.Float64"
64
+ "adduct_group": {
65
+ "dtype": "pl.Int64"
72
66
  },
73
- "quality": {
74
- "dtype": "pl.Float64"
67
+ "chrom": {
68
+ "dtype": "pl.Object"
75
69
  },
76
- "rt": {
70
+ "filled": {
71
+ "dtype": "pl.Boolean"
72
+ },
73
+ "chrom_area": {
77
74
  "dtype": "pl.Float64"
78
75
  },
79
- "rt_delta": {
76
+ "chrom_coherence": {
80
77
  "dtype": "pl.Float64"
81
78
  },
82
- "rt_end": {
79
+ "chrom_prominence": {
83
80
  "dtype": "pl.Float64"
84
81
  },
85
- "rt_original": {
82
+ "chrom_prominence_scaled": {
86
83
  "dtype": "pl.Float64"
87
84
  },
88
- "rt_start": {
85
+ "chrom_height_scaled": {
89
86
  "dtype": "pl.Float64"
90
87
  },
91
- "sample_uid": {
92
- "dtype": "pl.Int32"
88
+ "ms2_scans": {
89
+ "dtype": "pl.Object"
90
+ },
91
+ "ms2_specs": {
92
+ "dtype": "pl.Object"
93
93
  }
94
94
  }
95
95
  },
masster/study/h5.py CHANGED
@@ -1686,19 +1686,6 @@ def _load_study5(self, filename=None):
1686
1686
  # Check if progress bar should be disabled based on log level
1687
1687
  tdqm_disable = self.log_level not in ["TRACE", "DEBUG", "INFO"]
1688
1688
 
1689
- # Define loading steps for progress tracking
1690
- loading_steps = [
1691
- "metadata",
1692
- "samples_df",
1693
- "features_df",
1694
- "consensus_df",
1695
- "consensus_mapping_df",
1696
- "consensus_ms2",
1697
- ]
1698
-
1699
- # Check if progress bar should be disabled based on log level
1700
- tdqm_disable = self.log_level not in ["TRACE", "DEBUG", "INFO"]
1701
-
1702
1689
  with h5py.File(filename, "r") as f:
1703
1690
  # Use progress bar to show loading progress
1704
1691
  with tqdm(
masster/study/helpers.py CHANGED
@@ -780,6 +780,7 @@ def _get_sample_uids(self, samples=None, seed=42):
780
780
  # choose a random sample of sample_uids
781
781
  if len(self.samples_df) > samples:
782
782
  np.random.seed(seed) # for reproducibility
783
+ self.logger.info(f"Randomly selected {samples} samples")
783
784
  return np.random.choice(
784
785
  self.samples_df["sample_uid"].to_list(),
785
786
  samples,
masster/study/plot.py CHANGED
@@ -226,8 +226,7 @@ def _isolated_show_panel_notebook(panel_obj):
226
226
 
227
227
  def plot_alignment(
228
228
  self,
229
- samples=None,
230
- maps: bool = True,
229
+ samples=50,
231
230
  filename: str | None = None,
232
231
  width: int = 450,
233
232
  height: int = 450,
@@ -235,322 +234,172 @@ def plot_alignment(
235
234
  ):
236
235
  """Visualize retention time alignment using two synchronized Bokeh scatter plots.
237
236
 
238
- - When ``maps=True`` the function reads ``self.features_maps`` (list of FeatureMap)
239
- and builds two side-by-side plots: Original RT (left) and Current/Aligned RT (right).
240
- - When ``maps=False`` the function uses ``self.features_df`` and expects an
241
- ``rt_original`` column (before) and ``rt`` column (after).
237
+ Uses ``features_df`` to create side-by-side plots showing Original RT (left)
238
+ and Current/Aligned RT (right). If no alignment has been performed yet,
239
+ both plots show the current RT values.
242
240
 
243
- Parameters
241
+ Parameters:
244
242
  - samples: List of sample identifiers (sample_uids or sample_names), or single int for random selection, or None for all samples.
245
- - maps: whether to use feature maps (default True).
246
243
  - filename: optional HTML file path to save the plot.
247
244
  - width/height: pixel size of each subplot.
248
245
  - markersize: base marker size.
249
246
 
250
- Returns
247
+ Returns:
251
248
  - Bokeh layout (row) containing the two synchronized plots.
252
249
  """
253
250
  # Local imports so the module can be used even if bokeh isn't needed elsewhere
254
251
  from bokeh.models import ColumnDataSource, HoverTool
255
- from bokeh.plotting import figure, show, output_file
252
+ from bokeh.plotting import figure
256
253
  import pandas as pd
257
254
 
258
- # Get sample_uids to filter by if specified
259
- sample_uids = self._get_sample_uids(samples) if samples is not None else None
255
+ # Check if features_df exists
256
+ if self.features_df is None or self.features_df.is_empty():
257
+ self.logger.error("No features_df found. Load features first.")
258
+ return
260
259
 
261
- # Build the before/after tabular data used for plotting
262
- before_data: list[dict[str, Any]] = []
263
- after_data: list[dict[str, Any]] = []
260
+ # Check required columns
261
+ required_cols = ["rt", "mz", "inty"]
262
+ missing = [c for c in required_cols if c not in self.features_df.columns]
263
+ if missing:
264
+ self.logger.error(f"Missing required columns in features_df: {missing}")
265
+ return
264
266
 
265
- if maps:
266
- # Ensure feature maps are loaded
267
- if self.features_maps is None or len(self.features_maps) == 0:
268
- self.load_features()
267
+ # Check if alignment has been performed
268
+ has_alignment = "rt_original" in self.features_df.columns
269
+ if not has_alignment:
270
+ self.logger.warning("Column 'rt_original' not found - alignment has not been performed yet.")
271
+ self.logger.info("Showing current RT values for both plots. Run align() first to see alignment comparison.")
272
+
273
+ # Get sample_uids to filter by if specified
274
+ sample_uids = self._get_sample_uids(samples) if samples is not None else None
269
275
 
270
- fmaps = self.features_maps or []
276
+ # Start with full features_df
277
+ features_df = self.features_df
271
278
 
272
- if not fmaps:
273
- self.logger.error("No feature maps available for plotting.")
279
+ # Filter by selected samples if specified
280
+ if sample_uids is not None:
281
+ features_df = features_df.filter(pl.col("sample_uid").is_in(sample_uids))
282
+ if features_df.is_empty():
283
+ self.logger.error("No features found for the selected samples.")
274
284
  return
275
285
 
276
- # Filter feature maps by selected samples if specified
277
- if sample_uids is not None:
278
- # Create mapping from sample_uid to map_id and filter accordingly
279
- if hasattr(self, "samples_df") and self.samples_df is not None and not self.samples_df.is_empty():
280
- samples_info = self.samples_df.to_pandas()
281
-
282
- # Filter samples_info to only selected sample_uids and get their map_ids
283
- selected_samples = samples_info[samples_info["sample_uid"].isin(sample_uids)]
284
- if selected_samples.empty:
285
- self.logger.error("No matching samples found for the provided sample_uids.")
286
- return
287
-
288
- # Get the map_ids for selected samples
289
- selected_map_ids = selected_samples["map_id"].tolist()
290
-
291
- # Filter feature maps based on map_ids
292
- filtered_maps = []
293
- for map_id in selected_map_ids:
294
- if 0 <= map_id < len(fmaps):
295
- filtered_maps.append(fmaps[map_id])
296
-
297
- fmaps = filtered_maps
298
- samples_info = selected_samples.reset_index(drop=True)
299
-
300
- if not fmaps:
301
- self.logger.error("No feature maps found for the selected samples.")
302
- return
303
- else:
304
- self.logger.warning("Cannot filter feature maps: no samples_df available")
286
+ # Determine sample column
287
+ sample_col = "sample_uid" if "sample_uid" in features_df.columns else "sample_name"
288
+ if sample_col not in features_df.columns:
289
+ self.logger.error("No sample identifier column found in features_df.")
290
+ return
305
291
 
306
- if not fmaps:
307
- self.logger.error("No feature maps available after filtering.")
308
- return
292
+ # Get unique samples
293
+ samples_list = features_df.select(pl.col(sample_col)).unique().to_series().to_list()
309
294
 
310
- # Reference (first) sample: use current RT for both before and after
311
- ref = fmaps[0]
312
- ref_rt = [f.getRT() for f in ref]
313
- ref_mz = [f.getMZ() for f in ref]
314
- ref_inty = [f.getIntensity() for f in ref]
315
- max_ref_inty = max(ref_inty) if ref_inty else 1
316
-
317
- # Get sample metadata for reference (first) sample
318
- if hasattr(self, "samples_df") and self.samples_df is not None and not self.samples_df.is_empty():
319
- if 'samples_info' not in locals():
320
- samples_info = self.samples_df.to_pandas()
321
- ref_sample_uid = (
322
- samples_info.iloc[0]["sample_uid"] if "sample_uid" in samples_info.columns else "Reference_UID"
323
- )
324
- ref_sample_name = (
325
- samples_info.iloc[0]["sample_name"] if "sample_name" in samples_info.columns else "Reference"
326
- )
327
- else:
328
- ref_sample_uid = "Reference_UID"
329
- ref_sample_name = "Reference"
295
+ # Build plotting data
296
+ before_data: list[dict[str, Any]] = []
297
+ after_data: list[dict[str, Any]] = []
298
+
299
+ for sample_idx, sample in enumerate(samples_list):
300
+ # Filter sample data
301
+ sample_data = features_df.filter(pl.col(sample_col) == sample)
302
+
303
+ # Sample data if too large for performance
304
+ max_points_per_sample = 10000
305
+ if sample_data.height > max_points_per_sample:
306
+ self.logger.info(f"Sample {sample}: Sampling {max_points_per_sample} points from {sample_data.height} features for performance")
307
+ sample_data = sample_data.sample(n=max_points_per_sample, seed=42)
308
+
309
+ # Calculate max intensity for alpha scaling
310
+ max_inty = sample_data.select(pl.col("inty").max()).item() or 1
311
+
312
+ # Get sample information
313
+ sample_name = str(sample)
314
+ sample_uid = sample if sample_col == "sample_uid" else sample_data.select(pl.col("sample_uid")).item() if "sample_uid" in sample_data.columns else sample
315
+
316
+ # Select columns to process
317
+ cols_to_select = ["rt", "mz", "inty"]
318
+ if has_alignment:
319
+ cols_to_select.append("rt_original")
320
+
321
+ sample_dict = sample_data.select(cols_to_select).to_dicts()
322
+
323
+ for row_dict in sample_dict:
324
+ rt_original = row_dict.get("rt_original", row_dict["rt"]) if has_alignment else row_dict["rt"]
325
+ rt_current = row_dict["rt"]
326
+ mz = row_dict["mz"]
327
+ inty = row_dict["inty"]
328
+ alpha = inty / max_inty
329
+ size = markersize + 2 if sample_idx == 0 else markersize
330
330
 
331
- for rt, mz, inty in zip(ref_rt, ref_mz, ref_inty):
332
331
  before_data.append({
333
- "rt": rt,
332
+ "rt": rt_original,
334
333
  "mz": mz,
335
334
  "inty": inty,
336
- "alpha": inty / max_ref_inty,
337
- "sample_idx": 0,
338
- "sample_name": ref_sample_name,
339
- "sample_uid": ref_sample_uid,
340
- "size": markersize + 2,
335
+ "alpha": alpha,
336
+ "sample_idx": sample_idx,
337
+ "sample_name": sample_name,
338
+ "sample_uid": sample_uid,
339
+ "size": size,
341
340
  })
342
341
  after_data.append({
343
- "rt": rt,
342
+ "rt": rt_current,
344
343
  "mz": mz,
345
344
  "inty": inty,
346
- "alpha": inty / max_ref_inty,
347
- "sample_idx": 0,
348
- "sample_name": ref_sample_name,
349
- "sample_uid": ref_sample_uid,
350
- "size": markersize + 2,
345
+ "alpha": alpha,
346
+ "sample_idx": sample_idx,
347
+ "sample_name": sample_name,
348
+ "sample_uid": sample_uid,
349
+ "size": size,
351
350
  })
352
351
 
353
- # Remaining samples - now using filtered feature maps and samples_info
354
- for sample_idx, fm in enumerate(fmaps[1:], start=1):
355
- mz_vals = []
356
- inty_vals = []
357
- original_rt = []
358
- aligned_rt = []
359
-
360
- for f in fm:
361
- try:
362
- orig = f.getMetaValue("original_RT")
363
- except Exception:
364
- orig = None
365
-
366
- if orig is None:
367
- original_rt.append(f.getRT())
368
- else:
369
- original_rt.append(orig)
370
-
371
- aligned_rt.append(f.getRT())
372
- mz_vals.append(f.getMZ())
373
- inty_vals.append(f.getIntensity())
374
-
375
- if not inty_vals:
376
- continue
377
-
378
- max_inty = max(inty_vals)
379
-
380
- # Get sample metadata from filtered samples_info
381
- if hasattr(self, "samples_df") and self.samples_df is not None and not self.samples_df.is_empty():
382
- # Use filtered samples_info if it exists from the filtering above
383
- if 'samples_info' in locals() and sample_idx < len(samples_info):
384
- sample_name = samples_info.iloc[sample_idx].get("sample_name", f"Sample {sample_idx}")
385
- sample_uid = samples_info.iloc[sample_idx].get("sample_uid", f"Sample_{sample_idx}_UID")
386
- else:
387
- # Fallback to original samples_df if filtered samples_info is not available
388
- all_samples_info = self.samples_df.to_pandas()
389
- if sample_idx < len(all_samples_info):
390
- sample_name = all_samples_info.iloc[sample_idx].get("sample_name", f"Sample {sample_idx}")
391
- sample_uid = all_samples_info.iloc[sample_idx].get("sample_uid", f"Sample_{sample_idx}_UID")
392
- else:
393
- sample_name = f"Sample {sample_idx}"
394
- sample_uid = f"Sample_{sample_idx}_UID"
395
- else:
396
- sample_name = f"Sample {sample_idx}"
397
- sample_uid = f"Sample_{sample_idx}_UID"
398
-
399
- for rt, mz, inty in zip(original_rt, mz_vals, inty_vals):
400
- before_data.append({
401
- "rt": rt,
402
- "mz": mz,
403
- "inty": inty,
404
- "alpha": inty / max_inty,
405
- "sample_idx": sample_idx,
406
- "sample_name": sample_name,
407
- "sample_uid": sample_uid,
408
- "size": markersize,
409
- })
410
-
411
- for rt, mz, inty in zip(aligned_rt, mz_vals, inty_vals):
412
- after_data.append({
413
- "rt": rt,
414
- "mz": mz,
415
- "inty": inty,
416
- "alpha": inty / max_inty,
417
- "sample_idx": sample_idx,
418
- "sample_name": sample_name,
419
- "sample_uid": sample_uid,
420
- "size": markersize,
421
- })
422
-
423
- else:
424
- # Use features_df
425
- if self.features_df is None or self.features_df.is_empty():
426
- self.logger.error("No features_df found. Load features first.")
427
- return
428
-
429
- required_cols = ["rt", "mz", "inty"]
430
- missing = [c for c in required_cols if c not in self.features_df.columns]
431
- if missing:
432
- self.logger.error(f"Missing required columns in features_df: {missing}")
433
- return
434
-
435
- if "rt_original" not in self.features_df.columns:
436
- self.logger.error("Column 'rt_original' not found in features_df. Alignment may not have been performed.")
437
- return
438
-
439
- # Use Polars instead of pandas
440
- features_df = self.features_df
441
-
442
- # Filter by selected samples if specified
443
- if sample_uids is not None:
444
- features_df = features_df.filter(pl.col("sample_uid").is_in(sample_uids))
445
- if features_df.is_empty():
446
- self.logger.error("No features found for the selected samples.")
447
- return
448
-
449
- sample_col = "sample_uid" if "sample_uid" in features_df.columns else "sample_name"
450
- if sample_col not in features_df.columns:
451
- self.logger.error("No sample identifier column found in features_df.")
452
- return
453
-
454
- # Get unique samples using Polars
455
- samples = features_df.select(pl.col(sample_col)).unique().to_series().to_list()
456
-
457
- for sample_idx, sample in enumerate(samples):
458
- # Filter sample data using Polars
459
- sample_data = features_df.filter(pl.col(sample_col) == sample)
460
-
461
- # Calculate max intensity using Polars
462
- max_inty = sample_data.select(pl.col("inty").max()).item()
463
- max_inty = max_inty if max_inty and max_inty > 0 else 1
352
+ # Check if we have any data to plot
353
+ if not before_data:
354
+ self.logger.error("No data to plot.")
355
+ return
464
356
 
465
- sample_name = str(sample)
466
- # Get sample_uid - if sample_col is 'sample_uid', use sample directly
467
- if sample_col == "sample_uid":
468
- sample_uid = sample
469
- else:
470
- # Try to get sample_uid from the first row if it exists
471
- if "sample_uid" in sample_data.columns:
472
- sample_uid = sample_data.select(pl.col("sample_uid")).item()
473
- else:
474
- sample_uid = sample
475
-
476
- # Convert to dict for iteration - more efficient than row-by-row processing
477
- sample_dict = sample_data.select(["rt_original", "rt", "mz", "inty"]).to_dicts()
478
-
479
- for row_dict in sample_dict:
480
- rt_original = row_dict["rt_original"]
481
- rt_current = row_dict["rt"]
482
- mz = row_dict["mz"]
483
- inty = row_dict["inty"]
484
- alpha = inty / max_inty
485
- size = markersize + 2 if sample_idx == 0 else markersize
486
-
487
- before_data.append({
488
- "rt": rt_original,
489
- "mz": mz,
490
- "inty": inty,
491
- "alpha": alpha,
492
- "sample_idx": sample_idx,
493
- "sample_name": sample_name,
494
- "sample_uid": sample_uid,
495
- "size": size,
496
- })
497
- after_data.append({
498
- "rt": rt_current,
499
- "mz": mz,
500
- "inty": inty,
501
- "alpha": alpha,
502
- "sample_idx": sample_idx,
503
- "sample_name": sample_name,
504
- "sample_uid": sample_uid,
505
- "size": size,
506
- })
507
-
508
- # Get sample colors from samples_df using sample indices
509
- # Extract unique sample information from the dictionaries we created
510
- if before_data:
511
- # Create mapping from sample_idx to sample_uid more efficiently
512
- sample_idx_to_uid = {}
513
- for item in before_data:
514
- if item["sample_idx"] not in sample_idx_to_uid:
515
- sample_idx_to_uid[item["sample_idx"]] = item["sample_uid"]
516
- else:
517
- sample_idx_to_uid = {}
357
+ # Get sample colors from samples_df
358
+ sample_idx_to_uid = {}
359
+ for item in before_data:
360
+ if item["sample_idx"] not in sample_idx_to_uid:
361
+ sample_idx_to_uid[item["sample_idx"]] = item["sample_uid"]
518
362
 
519
- # Get colors from samples_df
363
+ # Get colors from samples_df if available
520
364
  sample_uids_list = list(sample_idx_to_uid.values())
365
+ color_map: dict[int, str] = {}
366
+
521
367
  if sample_uids_list and hasattr(self, "samples_df") and self.samples_df is not None:
522
- sample_colors = (
523
- self.samples_df.filter(pl.col("sample_uid").is_in(sample_uids_list))
524
- .select(["sample_uid", "sample_color"])
525
- .to_dict(as_series=False)
526
- )
527
- uid_to_color = dict(zip(sample_colors["sample_uid"], sample_colors["sample_color"]))
368
+ try:
369
+ sample_colors = (
370
+ self.samples_df.filter(pl.col("sample_uid").is_in(sample_uids_list))
371
+ .select(["sample_uid", "sample_color"])
372
+ .to_dict(as_series=False)
373
+ )
374
+ uid_to_color = dict(zip(sample_colors["sample_uid"], sample_colors["sample_color"]))
375
+
376
+ for sample_idx, sample_uid in sample_idx_to_uid.items():
377
+ color_map[sample_idx] = uid_to_color.get(sample_uid, "#1f77b4")
378
+ except Exception:
379
+ # Fallback to default colors if sample colors not available
380
+ for sample_idx in sample_idx_to_uid.keys():
381
+ color_map[sample_idx] = "#1f77b4"
528
382
  else:
529
- uid_to_color = {}
530
-
531
- # Create color map for sample indices
532
- color_map: dict[int, str] = {}
533
- for sample_idx, sample_uid in sample_idx_to_uid.items():
534
- color_map[sample_idx] = uid_to_color.get(sample_uid, "#1f77b4") # fallback to blue
535
-
536
- # Add sample_color to data dictionaries before creating DataFrames
537
- if before_data:
538
- for item in before_data:
539
- item["sample_color"] = color_map.get(item["sample_idx"], "#1f77b4")
383
+ # Default colors
384
+ for sample_idx in sample_idx_to_uid.keys():
385
+ color_map[sample_idx] = "#1f77b4"
540
386
 
541
- if after_data:
542
- for item in after_data:
543
- item["sample_color"] = color_map.get(item["sample_idx"], "#1f77b4")
387
+ # Add sample_color to data
388
+ for item in before_data + after_data:
389
+ item["sample_color"] = color_map.get(item["sample_idx"], "#1f77b4")
544
390
 
545
- # Now create DataFrames with the sample_color already included
546
- before_df = pd.DataFrame(before_data) if before_data else pd.DataFrame()
547
- after_df = pd.DataFrame(after_data) if after_data else pd.DataFrame()
391
+ # Create DataFrames
392
+ before_df = pd.DataFrame(before_data)
393
+ after_df = pd.DataFrame(after_data)
548
394
 
549
395
  # Create Bokeh figures
396
+ title_before = "Original RT" if has_alignment else "Current RT (No Alignment)"
397
+ title_after = "Aligned RT" if has_alignment else "Current RT (Copy)"
398
+
550
399
  p1 = figure(
551
400
  width=width,
552
401
  height=height,
553
- title="Original RT",
402
+ title=title_before,
554
403
  x_axis_label="Retention Time (s)",
555
404
  y_axis_label="m/z",
556
405
  tools="pan,wheel_zoom,box_zoom,reset,save",
@@ -563,7 +412,7 @@ def plot_alignment(
563
412
  p2 = figure(
564
413
  width=width,
565
414
  height=height,
566
- title="Current RT",
415
+ title=title_after,
567
416
  x_axis_label="Retention Time (s)",
568
417
  y_axis_label="m/z",
569
418
  tools="pan,wheel_zoom,box_zoom,reset,save",
@@ -575,16 +424,15 @@ def plot_alignment(
575
424
  p2.border_fill_color = "white"
576
425
  p2.min_border = 0
577
426
 
578
- # Get unique sample indices for iteration
579
- unique_samples = sorted(list({item["sample_idx"] for item in before_data})) if before_data else []
580
-
427
+ # Plot data by sample
428
+ unique_samples = sorted(list({item["sample_idx"] for item in before_data}))
581
429
  renderers_before = []
582
430
  renderers_after = []
583
431
 
584
432
  for sample_idx in unique_samples:
585
433
  sb = before_df[before_df["sample_idx"] == sample_idx]
586
434
  sa = after_df[after_df["sample_idx"] == sample_idx]
587
- color = color_map.get(sample_idx, "#000000")
435
+ color = color_map.get(sample_idx, "#1f77b4")
588
436
 
589
437
  if not sb.empty:
590
438
  src = ColumnDataSource(sb)
@@ -623,8 +471,7 @@ def plot_alignment(
623
471
  )
624
472
  p2.add_tools(hover2)
625
473
 
626
- # Create layout with both plots side by side
627
- # Use the aliased bokeh_row and set sizing_mode, width and height to avoid validation warnings.
474
+ # Create layout
628
475
  layout = bokeh_row(p1, p2, sizing_mode="fixed", width=width, height=height)
629
476
 
630
477
  # Apply consistent save/display behavior
@@ -878,7 +725,7 @@ def plot_consensus_2d(
878
725
 
879
726
  def plot_samples_2d(
880
727
  self,
881
- samples=None,
728
+ samples=100,
882
729
  filename=None,
883
730
  markersize=2,
884
731
  size="dynamic",
@@ -1112,7 +959,7 @@ def plot_samples_2d(
1112
959
 
1113
960
  def plot_bpc(
1114
961
  self,
1115
- samples=None,
962
+ samples=100,
1116
963
  title: str | None = None,
1117
964
  filename: str | None = None,
1118
965
  width: int = 1000,
@@ -1288,7 +1135,7 @@ def plot_eic(
1288
1135
  self,
1289
1136
  mz,
1290
1137
  mz_tol=None,
1291
- samples=None,
1138
+ samples=100,
1292
1139
  title: str | None = None,
1293
1140
  filename: str | None = None,
1294
1141
  width: int = 1000,
@@ -1457,7 +1304,7 @@ def plot_eic(
1457
1304
 
1458
1305
  def plot_rt_correction(
1459
1306
  self,
1460
- samples=None,
1307
+ samples=200,
1461
1308
  title: str | None = None,
1462
1309
  filename: str | None = None,
1463
1310
  width: int = 1000,
@@ -1611,7 +1458,7 @@ def plot_rt_correction(
1611
1458
  def plot_chrom(
1612
1459
  self,
1613
1460
  uids=None,
1614
- samples=None,
1461
+ samples=100,
1615
1462
  filename=None,
1616
1463
  aligned=True,
1617
1464
  width=800,
@@ -2309,7 +2156,7 @@ def plot_pca(
2309
2156
 
2310
2157
  def plot_tic(
2311
2158
  self,
2312
- samples=None,
2159
+ samples=100,
2313
2160
  title: str | None = None,
2314
2161
  filename: str | None = None,
2315
2162
  width: int = 1000,
@@ -1,104 +1,104 @@
1
1
  {
2
2
  "consensus_df": {
3
3
  "columns": {
4
- "adduct_charge_top": {
4
+ "consensus_uid": {
5
5
  "dtype": "pl.Int64"
6
6
  },
7
- "adduct_group": {
7
+ "consensus_id": {
8
+ "dtype": "pl.Utf8"
9
+ },
10
+ "quality": {
11
+ "dtype": "pl.Float64"
12
+ },
13
+ "number_samples": {
8
14
  "dtype": "pl.Int64"
9
15
  },
10
- "adduct_mass_neutral_top": {
16
+ "rt": {
11
17
  "dtype": "pl.Float64"
12
18
  },
13
- "adduct_mass_shift_top": {
19
+ "mz": {
14
20
  "dtype": "pl.Float64"
15
21
  },
16
- "adduct_of": {
17
- "dtype": "pl.Int64"
22
+ "rt_min": {
23
+ "dtype": "pl.Float64"
18
24
  },
19
- "adduct_top": {
20
- "dtype": "pl.Utf8"
25
+ "rt_max": {
26
+ "dtype": "pl.Float64"
21
27
  },
22
- "adducts": {
23
- "dtype": "pl.Object"
28
+ "rt_mean": {
29
+ "dtype": "pl.Float64"
24
30
  },
25
- "bl": {
31
+ "rt_start_mean": {
26
32
  "dtype": "pl.Float64"
27
33
  },
28
- "charge_mean": {
34
+ "rt_end_mean": {
29
35
  "dtype": "pl.Float64"
30
36
  },
31
- "chrom_coherence_mean": {
37
+ "rt_delta_mean": {
32
38
  "dtype": "pl.Float64"
33
39
  },
34
- "chrom_height_scaled_mean": {
40
+ "mz_min": {
35
41
  "dtype": "pl.Float64"
36
42
  },
37
- "chrom_prominence_mean": {
43
+ "mz_max": {
38
44
  "dtype": "pl.Float64"
39
45
  },
40
- "chrom_prominence_scaled_mean": {
46
+ "mz_mean": {
41
47
  "dtype": "pl.Float64"
42
48
  },
43
- "consensus_id": {
44
- "dtype": "pl.Utf8"
49
+ "mz_start_mean": {
50
+ "dtype": "pl.Float64"
45
51
  },
46
- "consensus_uid": {
47
- "dtype": "pl.Int64"
52
+ "mz_end_mean": {
53
+ "dtype": "pl.Float64"
48
54
  },
49
55
  "inty_mean": {
50
56
  "dtype": "pl.Float64"
51
57
  },
52
- "iso_mean": {
58
+ "bl": {
53
59
  "dtype": "pl.Float64"
54
60
  },
55
- "mz": {
61
+ "chrom_coherence_mean": {
56
62
  "dtype": "pl.Float64"
57
63
  },
58
- "mz_end_mean": {
64
+ "chrom_prominence_mean": {
59
65
  "dtype": "pl.Float64"
60
66
  },
61
- "mz_max": {
67
+ "chrom_prominence_scaled_mean": {
62
68
  "dtype": "pl.Float64"
63
69
  },
64
- "mz_mean": {
70
+ "chrom_height_scaled_mean": {
65
71
  "dtype": "pl.Float64"
66
72
  },
67
- "mz_min": {
73
+ "iso_mean": {
68
74
  "dtype": "pl.Float64"
69
75
  },
70
- "mz_start_mean": {
76
+ "charge_mean": {
71
77
  "dtype": "pl.Float64"
72
78
  },
73
79
  "number_ms2": {
74
80
  "dtype": "pl.Int64"
75
81
  },
76
- "number_samples": {
77
- "dtype": "pl.Int64"
78
- },
79
- "quality": {
80
- "dtype": "pl.Float64"
81
- },
82
- "rt": {
83
- "dtype": "pl.Float64"
82
+ "adducts": {
83
+ "dtype": "pl.Object"
84
84
  },
85
- "rt_delta_mean": {
86
- "dtype": "pl.Float64"
85
+ "adduct_charge_top": {
86
+ "dtype": "pl.Int64"
87
87
  },
88
- "rt_end_mean": {
89
- "dtype": "pl.Float64"
88
+ "adduct_group": {
89
+ "dtype": "pl.Int64"
90
90
  },
91
- "rt_max": {
91
+ "adduct_mass_neutral_top": {
92
92
  "dtype": "pl.Float64"
93
93
  },
94
- "rt_mean": {
94
+ "adduct_mass_shift_top": {
95
95
  "dtype": "pl.Float64"
96
96
  },
97
- "rt_min": {
98
- "dtype": "pl.Float64"
97
+ "adduct_of": {
98
+ "dtype": "pl.Int64"
99
99
  },
100
- "rt_start_mean": {
101
- "dtype": "pl.Float64"
100
+ "adduct_top": {
101
+ "dtype": "pl.Utf8"
102
102
  }
103
103
  }
104
104
  },
@@ -151,135 +151,156 @@
151
151
  },
152
152
  "features_df": {
153
153
  "columns": {
154
- "adduct": {
155
- "dtype": "pl.Utf8"
156
- },
157
- "adduct_charge": {
158
- "dtype": "pl.Int64"
159
- },
160
- "adduct_group": {
154
+ "feature_uid": {
161
155
  "dtype": "pl.Int64"
162
156
  },
163
- "adduct_mass_neutral": {
164
- "dtype": "pl.Float64"
165
- },
166
- "adduct_mass_shift": {
167
- "dtype": "pl.Float64"
157
+ "feature_id": {
158
+ "dtype": "pl.Utf8"
168
159
  },
169
- "charge": {
160
+ "sample_uid": {
170
161
  "dtype": "pl.Int32"
171
162
  },
172
- "chrom": {
173
- "dtype": "pl.Object"
174
- },
175
- "chrom_area": {
163
+ "mz": {
176
164
  "dtype": "pl.Float64"
177
165
  },
178
- "chrom_coherence": {
166
+ "rt": {
179
167
  "dtype": "pl.Float64"
180
168
  },
181
- "chrom_height_scaled": {
169
+ "rt_original": {
182
170
  "dtype": "pl.Float64"
183
171
  },
184
- "chrom_prominence": {
172
+ "rt_start": {
185
173
  "dtype": "pl.Float64"
186
174
  },
187
- "chrom_prominence_scaled": {
175
+ "rt_end": {
188
176
  "dtype": "pl.Float64"
189
177
  },
190
- "feature_id": {
191
- "dtype": "pl.Utf8"
178
+ "rt_delta": {
179
+ "dtype": "pl.Float64"
192
180
  },
193
- "feature_uid": {
194
- "dtype": "pl.Int64"
181
+ "mz_start": {
182
+ "dtype": "pl.Float64"
195
183
  },
196
- "filled": {
197
- "dtype": "pl.Boolean"
184
+ "mz_end": {
185
+ "dtype": "pl.Float64"
198
186
  },
199
187
  "inty": {
200
188
  "dtype": "pl.Float64"
201
189
  },
190
+ "quality": {
191
+ "dtype": "pl.Float64"
192
+ },
193
+ "charge": {
194
+ "dtype": "pl.Int32"
195
+ },
202
196
  "iso": {
203
197
  "dtype": "pl.Int64"
204
198
  },
205
199
  "iso_of": {
206
200
  "dtype": "pl.Int64"
207
201
  },
208
- "ms2_scans": {
209
- "dtype": "pl.Object"
202
+ "adduct": {
203
+ "dtype": "pl.Utf8"
210
204
  },
211
- "ms2_specs": {
212
- "dtype": "pl.Object"
205
+ "adduct_charge": {
206
+ "dtype": "pl.Int64"
213
207
  },
214
- "mz": {
208
+ "adduct_mass_shift": {
215
209
  "dtype": "pl.Float64"
216
210
  },
217
- "mz_end": {
211
+ "adduct_mass_neutral": {
218
212
  "dtype": "pl.Float64"
219
213
  },
220
- "mz_start": {
221
- "dtype": "pl.Float64"
214
+ "adduct_group": {
215
+ "dtype": "pl.Int64"
222
216
  },
223
- "quality": {
224
- "dtype": "pl.Float64"
217
+ "chrom": {
218
+ "dtype": "pl.Object"
225
219
  },
226
- "rt": {
220
+ "filled": {
221
+ "dtype": "pl.Boolean"
222
+ },
223
+ "chrom_area": {
227
224
  "dtype": "pl.Float64"
228
225
  },
229
- "rt_delta": {
226
+ "chrom_coherence": {
230
227
  "dtype": "pl.Float64"
231
228
  },
232
- "rt_end": {
229
+ "chrom_prominence": {
233
230
  "dtype": "pl.Float64"
234
231
  },
235
- "rt_original": {
232
+ "chrom_prominence_scaled": {
236
233
  "dtype": "pl.Float64"
237
234
  },
238
- "rt_start": {
235
+ "chrom_height_scaled": {
239
236
  "dtype": "pl.Float64"
240
237
  },
241
- "sample_uid": {
242
- "dtype": "pl.Int32"
238
+ "ms2_scans": {
239
+ "dtype": "pl.Object"
240
+ },
241
+ "ms2_specs": {
242
+ "dtype": "pl.Object"
243
243
  }
244
244
  }
245
245
  },
246
- "id_df": {
246
+ "samples_df": {
247
247
  "columns": {
248
- "consensus_uid": {
248
+ "sample_uid": {
249
249
  "dtype": "pl.Int64"
250
250
  },
251
- "lib_uid": {
251
+ "map_id": {
252
252
  "dtype": "pl.Int64"
253
253
  },
254
- "matcher": {
255
- "dtype": "pl.String"
254
+ "sample_source": {
255
+ "dtype": "pl.Utf8"
256
256
  },
257
- "mz_delta": {
258
- "dtype": "pl.Float64"
257
+ "sample_name": {
258
+ "dtype": "pl.Utf8"
259
259
  },
260
- "rt_delta": {
261
- "dtype": "pl.Null"
260
+ "sample_path": {
261
+ "dtype": "pl.Utf8"
262
262
  },
263
- "score": {
264
- "dtype": "pl.Float64"
263
+ "sample_type": {
264
+ "dtype": "pl.Utf8"
265
+ },
266
+ "sample_group": {
267
+ "dtype": "pl.Utf8"
268
+ },
269
+ "sample_batch": {
270
+ "dtype": "pl.Int64"
271
+ },
272
+ "sample_sequence": {
273
+ "dtype": "pl.Int64"
274
+ },
275
+ "sample_color": {
276
+ "dtype": "pl.Utf8"
277
+ },
278
+ "num_features": {
279
+ "dtype": "pl.Int64"
280
+ },
281
+ "num_ms1": {
282
+ "dtype": "pl.Int64"
283
+ },
284
+ "num_ms2": {
285
+ "dtype": "pl.Int64"
265
286
  }
266
287
  }
267
288
  },
268
289
  "lib_df": {
269
290
  "columns": {
270
- "adduct": {
271
- "dtype": "pl.String"
291
+ "lib_uid": {
292
+ "dtype": "pl.Int64"
272
293
  },
273
294
  "cmpd_uid": {
274
295
  "dtype": "pl.Int64"
275
296
  },
276
- "db": {
277
- "dtype": "pl.String"
297
+ "source_id": {
298
+ "dtype": "pl.Null"
278
299
  },
279
- "db_id": {
300
+ "name": {
280
301
  "dtype": "pl.String"
281
302
  },
282
- "formula": {
303
+ "smiles": {
283
304
  "dtype": "pl.String"
284
305
  },
285
306
  "inchi": {
@@ -288,72 +309,51 @@
288
309
  "inchikey": {
289
310
  "dtype": "pl.String"
290
311
  },
291
- "lib_uid": {
292
- "dtype": "pl.Int64"
312
+ "formula": {
313
+ "dtype": "pl.String"
314
+ },
315
+ "adduct": {
316
+ "dtype": "pl.String"
293
317
  },
294
318
  "m": {
295
319
  "dtype": "pl.Float64"
296
320
  },
321
+ "z": {
322
+ "dtype": "pl.Int64"
323
+ },
297
324
  "mz": {
298
325
  "dtype": "pl.Float64"
299
326
  },
300
- "name": {
301
- "dtype": "pl.String"
302
- },
303
327
  "rt": {
304
328
  "dtype": "pl.Null"
305
329
  },
306
- "smiles": {
330
+ "db_id": {
307
331
  "dtype": "pl.String"
308
332
  },
309
- "source_id": {
310
- "dtype": "pl.Null"
311
- },
312
- "z": {
313
- "dtype": "pl.Int64"
333
+ "db": {
334
+ "dtype": "pl.String"
314
335
  }
315
336
  }
316
337
  },
317
- "samples_df": {
338
+ "id_df": {
318
339
  "columns": {
319
- "map_id": {
320
- "dtype": "pl.Int64"
321
- },
322
- "num_features": {
323
- "dtype": "pl.Int64"
324
- },
325
- "num_ms1": {
326
- "dtype": "pl.Int64"
327
- },
328
- "num_ms2": {
340
+ "consensus_uid": {
329
341
  "dtype": "pl.Int64"
330
342
  },
331
- "sample_batch": {
343
+ "lib_uid": {
332
344
  "dtype": "pl.Int64"
333
345
  },
334
- "sample_color": {
335
- "dtype": "pl.Utf8"
336
- },
337
- "sample_group": {
338
- "dtype": "pl.Utf8"
339
- },
340
- "sample_name": {
341
- "dtype": "pl.Utf8"
342
- },
343
- "sample_path": {
344
- "dtype": "pl.Utf8"
345
- },
346
- "sample_sequence": {
347
- "dtype": "pl.Int64"
346
+ "mz_delta": {
347
+ "dtype": "pl.Float64"
348
348
  },
349
- "sample_source": {
350
- "dtype": "pl.Utf8"
349
+ "rt_delta": {
350
+ "dtype": "pl.Null"
351
351
  },
352
- "sample_type": {
353
- "dtype": "pl.Utf8"
352
+ "matcher": {
353
+ "dtype": "pl.String"
354
354
  },
355
- "sample_uid": {
356
- "dtype": "pl.Int64"
355
+ "score": {
356
+ "dtype": "pl.Float64"
357
357
  }
358
358
  }
359
359
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: masster
3
- Version: 0.4.10
3
+ Version: 0.4.11
4
4
  Summary: Mass spectrometry data analysis package
5
5
  Project-URL: homepage, https://github.com/zamboni-lab/masster
6
6
  Project-URL: repository, https://github.com/zamboni-lab/masster
@@ -1,5 +1,5 @@
1
1
  masster/__init__.py,sha256=8U4cIteNlYyHDrxWSbB_MsDKCX9tds07SJG8-vh8Oa8,738
2
- masster/_version.py,sha256=WP_nHA1hNbPXkmS3tyAKOINq6RpCiQCXwQl13e8Jsb4,257
2
+ masster/_version.py,sha256=Ra822EfcCSSsug6aojKBn4P__-I2P5hLd9y2DnUcJqg,257
3
3
  masster/chromatogram.py,sha256=iYpdv8C17zVnlWvOFgAn9ns2uFGiF-GgoYf5QVVAbHs,19319
4
4
  masster/logger.py,sha256=W50V_uh8RSYwGxDrDFhOuj5jpu2tKJyt_16lMw9kQwA,14755
5
5
  masster/spectrum.py,sha256=_upC_g2N9gwTaflXAugs9pSXpKUmzbIehofDordk7WI,47718
@@ -27,7 +27,7 @@ masster/sample/plot.py,sha256=abLnG0Bk75vqSGQz6uA3uTK3IE9N-s687ZH-n8Mhdzg,82757
27
27
  masster/sample/processing.py,sha256=lCHRv290oAFOxe_zR5GMi4FdxodjJh1rj2uLWy_wHnc,49771
28
28
  masster/sample/quant.py,sha256=tHNjvUFTdehKR31BXBZnVsBxMD9XJHgaltITOjr71uE,7562
29
29
  masster/sample/sample.py,sha256=WH4G9tG2AjXAWv_tK08X4R2peaDlXTKqXTq2V4-P6rE,18353
30
- masster/sample/sample5_schema.json,sha256=EKHVKXhqMqsavO34A4AJLPpysW0s2iLuLwjeTJP9R_8,3916
30
+ masster/sample/sample5_schema.json,sha256=voVB6z0TaIJwU-_SPUEYWKH7mKC16ycTe1nW6gODYP8,3916
31
31
  masster/sample/save.py,sha256=XZl5ITYdOjojYFOoUZ-0ygVSPH1kT5Va6e8NyuTRNAI,32500
32
32
  masster/sample/sciex.py,sha256=vnbxsq_qnAQVuzcpziP1o3IC4kM5amGBcPmC2TAuDLw,46319
33
33
  masster/sample/defaults/__init__.py,sha256=A09AOP44cxD_oYohyt7XFUho0zndRcrzVD4DUaGnKH4,447
@@ -38,16 +38,16 @@ masster/sample/defaults/get_spectrum_def.py,sha256=o62p31PhGd-LiIkTOzKQhwPtnO2At
38
38
  masster/sample/defaults/sample_def.py,sha256=keoXyMyrm_iLgbYqfIbqCpJ3XHBVlNwCNmb5iMQL0iY,14579
39
39
  masster/study/__init__.py,sha256=Zspv6U8jFqjkHGYdNdDy1rfUnCSolCzUdgSSg98PRgE,166
40
40
  masster/study/export.py,sha256=L-YOUGSgVeTprYnrQxaN0qC8MRqUdDQ0D4o2h7HLi2Q,54813
41
- masster/study/h5.py,sha256=j9LJT_BtK_TIJB552r5Rhpw7Clg9mZxzp6vxJ4X44kE,84063
42
- masster/study/helpers.py,sha256=ggY97l-spkXFaceEYy4D6ndcWZaD4aPnPcKOb9T7R8I,160208
41
+ masster/study/h5.py,sha256=Sbde1cxAAIq0EjNiTxQgJgHHVKFw29q510YBJRa_egw,83691
42
+ masster/study/helpers.py,sha256=TS1x9sMlcUPhEqGcPgDnzd84XqbUkJkf770iAUcI8RQ,160278
43
43
  masster/study/id.py,sha256=EOw-2dM8nnx8QcQF1qAFfGqql75JusONuDBjmAuMU2w,44723
44
44
  masster/study/load.py,sha256=tK3ueWxrauyveZukyh1YaV8h8fSFDytLnTmrEpFvcwU,70458
45
45
  masster/study/parameters.py,sha256=0elaF7YspTsB7qyajWAbRNL2VfKlGz5GJLifmO8IGkk,3276
46
- masster/study/plot.py,sha256=VBj1seZGGDJ9KGw8pmjuitn5H_tck1IPWSduWk57m3s,93855
46
+ masster/study/plot.py,sha256=c_VxZxupGi7UYx2r4b2XR-SWRefLuo8s8zbIoVg0PgE,86876
47
47
  masster/study/processing.py,sha256=JlIstxo9mdqudl30yI-Wd-Ru9AfAeiwBPmqaW-dTl54,73867
48
48
  masster/study/save.py,sha256=F_H34zmvxV54Ds64ju90JJLy_F4hg6nRdHhJ9ssWKLA,6704
49
49
  masster/study/study.py,sha256=k097_YaYykhtkI6Ykcr5QCcFvo1eBLWXWLKycrid51w,34846
50
- masster/study/study5_schema.json,sha256=06cB473eo_IzzbsT1Q9W4-svNTdgNJhCS86NVpuyySI,7246
50
+ masster/study/study5_schema.json,sha256=vZIaGfcPJmhy_6pDEweKF7nEYrHwmV4_uxbGLcYfK30,7246
51
51
  masster/study/defaults/__init__.py,sha256=m3Z5KXGqsTdh7GjYzZoENERt39yRg0ceVRV1DeCt1P0,610
52
52
  masster/study/defaults/align_def.py,sha256=hHQbGgsOqMRHHr0Wn8Onr8XeaRz3-fFE0qGE-OMst80,20324
53
53
  masster/study/defaults/export_def.py,sha256=eXl3h4aoLX88XkHTpqahLd-QZ2gjUqrmjq8IJULXeWo,1203
@@ -60,8 +60,8 @@ masster/study/defaults/integrate_chrom_def.py,sha256=0MNIWGTjty-Zu-NTQsIweuj3UVq
60
60
  masster/study/defaults/integrate_def.py,sha256=Vf4SAzdBfnsSZ3IRaF0qZvWu3gMDPHdgPfMYoPKeWv8,7246
61
61
  masster/study/defaults/merge_def.py,sha256=EBsKE3hsAkTEzN9dpdRD5W3_suTKy_WZ_96rwS0uBuE,8572
62
62
  masster/study/defaults/study_def.py,sha256=h8dYbi9xv0sesCSQik49Z53IkskMmNtW6ixl7it5pL0,16033
63
- masster-0.4.10.dist-info/METADATA,sha256=xYmHFy0HHE1Ko8NTY_hM82xDuUK8OfsuJB8CkRQiHN4,44189
64
- masster-0.4.10.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
65
- masster-0.4.10.dist-info/entry_points.txt,sha256=ZHguQ_vPmdbpqq2uGtmEOLJfgP-DQ1T0c07Lxh30wc8,58
66
- masster-0.4.10.dist-info/licenses/LICENSE,sha256=bx5iLIKjgAdYQ7sISn7DsfHRKkoCUm1154sJJKhgqnU,35184
67
- masster-0.4.10.dist-info/RECORD,,
63
+ masster-0.4.11.dist-info/METADATA,sha256=d-0v4eIqBo_LJNbnSN-6FncgNRMX_a1enOjueLtPGTs,44189
64
+ masster-0.4.11.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
65
+ masster-0.4.11.dist-info/entry_points.txt,sha256=ZHguQ_vPmdbpqq2uGtmEOLJfgP-DQ1T0c07Lxh30wc8,58
66
+ masster-0.4.11.dist-info/licenses/LICENSE,sha256=bx5iLIKjgAdYQ7sISn7DsfHRKkoCUm1154sJJKhgqnU,35184
67
+ masster-0.4.11.dist-info/RECORD,,