masster 0.3.1__py3-none-any.whl → 0.3.3__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/sample/plot.py CHANGED
@@ -283,9 +283,12 @@ def plot_2d(
283
283
  cmap=None,
284
284
  marker="circle",
285
285
  markersize=10,
286
+ size="dynamic",
286
287
  raster_dynamic=True,
287
288
  raster_max_px=8,
288
289
  raster_threshold=0.8,
290
+ height=600,
291
+ width=800,
289
292
  mz_range=None,
290
293
  rt_range=None,
291
294
  ):
@@ -318,6 +321,11 @@ def plot_2d(
318
321
  Marker type to use for feature and MS2 points.
319
322
  markersize (int, default 10):
320
323
  Base size of the markers used for plotting points.
324
+ size (str, default 'dynamic'):
325
+ Controls marker sizing behavior. Options: 'dynamic', 'static', or 'slider'.
326
+ - 'dynamic': Uses coordinate-based sizing that scales with zoom level (markers get larger when zooming in)
327
+ - 'static': Uses screen-based sizing that remains constant regardless of zoom level
328
+ - 'slider': Provides an interactive slider to dynamically adjust marker size
321
329
  raster_dynamic (bool, default True):
322
330
  Whether to use dynamic rasterization for the background point cloud.
323
331
  raster_max_px (int, default 8):
@@ -357,9 +365,9 @@ def plot_2d(
357
365
  # keep only rt, mz, and inty
358
366
  spectradf = spectradf.select(["rt", "mz", "inty"])
359
367
  if mz_range is not None:
360
- spectradf = spectradf[(spectradf["mz"] >= mz_range[0]) & (spectradf["mz"] <= mz_range[1])]
368
+ spectradf = spectradf.filter((pl.col("mz") >= mz_range[0]) & (pl.col("mz") <= mz_range[1]))
361
369
  if rt_range is not None:
362
- spectradf = spectradf[(spectradf["rt"] >= rt_range[0]) & (spectradf["rt"] <= rt_range[1])]
370
+ spectradf = spectradf.filter((pl.col("rt") >= rt_range[0]) & (pl.col("rt") <= rt_range[1]))
363
371
  maxrt = spectradf["rt"].max()
364
372
  minrt = spectradf["rt"].min()
365
373
  maxmz = spectradf["mz"].max()
@@ -384,19 +392,81 @@ def plot_2d(
384
392
  tools=["hover"],
385
393
  )
386
394
 
387
- size_1 = 1 * markersize
395
+ # Configure marker and size behavior based on size parameter
396
+ use_dynamic_sizing = size.lower() in ["dyn", "dynamic"]
397
+ use_slider_sizing = size.lower() == "slider"
398
+
399
+ def dynamic_sizing_hook(plot, element):
400
+ """Hook to convert size-based markers to radius-based for dynamic behavior"""
401
+ try:
402
+ if use_dynamic_sizing and hasattr(plot, 'state') and hasattr(plot.state, 'renderers'):
403
+ from bokeh.models import Circle
404
+ for renderer in plot.state.renderers:
405
+ if hasattr(renderer, 'glyph'):
406
+ glyph = renderer.glyph
407
+ # Check if it's a circle/scatter glyph that we can convert
408
+ if hasattr(glyph, 'size') and marker_type == "circle":
409
+ # Create a new Circle glyph with radius instead of size
410
+ new_glyph = Circle(
411
+ x=glyph.x,
412
+ y=glyph.y,
413
+ radius=base_radius,
414
+ fill_color=glyph.fill_color,
415
+ line_color=glyph.line_color,
416
+ fill_alpha=glyph.fill_alpha,
417
+ line_alpha=glyph.line_alpha,
418
+ )
419
+ renderer.glyph = new_glyph
420
+ except Exception:
421
+ # Silently fail and use regular sizing if hook doesn't work
422
+ pass
423
+
424
+ if use_dynamic_sizing:
425
+ # Dynamic sizing: use coordinate-based sizing that scales with zoom
426
+ marker_type = "circle"
427
+ # Calculate radius based on data range for coordinate-based sizing
428
+ rtrange = maxrt - minrt
429
+ mzrange = maxmz - minmz
430
+ # Use a fraction of the smaller dimension for radius
431
+ base_radius = min(rtrange, mzrange) * 0.0005 * markersize
432
+ size_1 = markersize # Use regular size initially, hook will convert to radius
433
+ size_2 = markersize
434
+ hooks = [dynamic_sizing_hook]
435
+ elif use_slider_sizing:
436
+ # Slider sizing: create an interactive slider for marker size
437
+ marker_type = marker # Use the original marker parameter
438
+ size_1 = markersize # Use markersize initially, will be updated by slider
439
+ size_2 = markersize
440
+ base_radius = None # Not used in slider mode
441
+ hooks = []
442
+ else:
443
+ # Static sizing: use pixel-based sizing that stays fixed
444
+ marker_type = marker # Use the original marker parameter
445
+ size_1 = markersize
446
+ size_2 = markersize
447
+ base_radius = None # Not used in static mode
448
+ hooks = []
449
+
388
450
  color_1 = "forestgreen"
389
- size_2 = 1 * markersize
390
451
  color_2 = "darkorange"
391
452
  if filename is not None:
392
453
  dyn = False
393
454
  if not filename.endswith(".html"):
394
- size_1 = 2
455
+ if use_dynamic_sizing:
456
+ # For exported files, use smaller coordinate-based size
457
+ size_1 = 2
458
+ size_2 = 2
459
+ else:
460
+ size_1 = 2
461
+ size_2 = 2
395
462
  color_1 = "forestgreen"
396
- size_2 = 2
397
463
  color_2 = "darkorange"
398
464
  raster_dynamic = False
399
465
 
466
+ # For slider functionality, disable raster dynamic to avoid DynamicMap nesting
467
+ if use_slider_sizing:
468
+ raster_dynamic = False
469
+
400
470
  dyn = raster_dynamic
401
471
  raster = hd.rasterize(
402
472
  points,
@@ -408,8 +478,8 @@ def plot_2d(
408
478
  cmap=process_cmap(cmap, provider="bokeh"), # blues
409
479
  tools=["hover"],
410
480
  hooks=[new_bounds_hook],
411
- width=1000,
412
- height=1000,
481
+ width=width,
482
+ height=height,
413
483
  cnorm="log",
414
484
  xlabel="Retention time (s)",
415
485
  ylabel="m/z",
@@ -448,6 +518,7 @@ def plot_2d(
448
518
  feats = feats[feats["iso"] == 0]
449
519
  # find features with ms2_scans not None and iso==0
450
520
  features_df = feats[feats["ms2_scans"].notnull()]
521
+ # Create feature points with proper sizing method
451
522
  feature_points_1 = hv.Points(
452
523
  features_df,
453
524
  kdims=["rt", "mz"],
@@ -463,9 +534,10 @@ def plot_2d(
463
534
  label="Features with MS2 data",
464
535
  ).options(
465
536
  color=color_1,
466
- marker=marker,
537
+ marker=marker_type,
467
538
  size=size_1,
468
539
  tools=["hover"],
540
+ hooks=hooks,
469
541
  )
470
542
  # find features without MS2 data
471
543
  features_df = feats[feats["ms2_scans"].isnull()]
@@ -483,9 +555,10 @@ def plot_2d(
483
555
  label="Features without MS2 data",
484
556
  ).options(
485
557
  color="red",
558
+ marker=marker_type,
486
559
  size=size_2,
487
- marker=marker,
488
560
  tools=["hover"],
561
+ hooks=hooks,
489
562
  )
490
563
 
491
564
  if show_isotopes:
@@ -510,9 +583,10 @@ def plot_2d(
510
583
  label="Isotopes",
511
584
  ).options(
512
585
  color="violet",
513
- marker=marker,
586
+ marker=marker_type,
514
587
  size=size_1,
515
588
  tools=["hover"],
589
+ hooks=hooks,
516
590
  )
517
591
  if show_ms2:
518
592
  # find all self.scans_df with mslevel 2 that are not linked to a feature
@@ -569,8 +643,119 @@ def plot_2d(
569
643
  if title is not None:
570
644
  overlay = overlay.opts(title=title)
571
645
 
572
- # Create a panel layout
573
- layout = panel.Column(overlay)
646
+ # Handle slider functionality
647
+ if use_slider_sizing:
648
+ # For slider functionality, we need to work with the feature points directly
649
+ # and not nest DynamicMaps. We'll create the slider using param and panel.
650
+ import param
651
+ import panel as pn
652
+
653
+ class MarkerSizeController(param.Parameterized):
654
+ size_slider = param.Number(default=markersize, bounds=(1, 20), step=0.5)
655
+
656
+ controller = MarkerSizeController()
657
+
658
+ # Create a function that generates just the feature overlays with different sizes
659
+ def create_feature_overlay(size_val):
660
+ feature_overlay = None
661
+
662
+ if feature_points_4 is not None:
663
+ updated_points_4 = feature_points_4.opts(size=size_val)
664
+ feature_overlay = updated_points_4 if feature_overlay is None else feature_overlay * updated_points_4
665
+ if feature_points_3 is not None:
666
+ updated_points_3 = feature_points_3.opts(size=size_val)
667
+ feature_overlay = updated_points_3 if feature_overlay is None else feature_overlay * updated_points_3
668
+ if feature_points_1 is not None:
669
+ updated_points_1 = feature_points_1.opts(size=size_val)
670
+ feature_overlay = updated_points_1 if feature_overlay is None else feature_overlay * updated_points_1
671
+ if not show_only_features_with_ms2 and feature_points_2 is not None:
672
+ updated_points_2 = feature_points_2.opts(size=size_val)
673
+ feature_overlay = updated_points_2 if feature_overlay is None else feature_overlay * updated_points_2
674
+ if feature_points_iso is not None:
675
+ updated_points_iso = feature_points_iso.opts(size=size_val)
676
+ feature_overlay = updated_points_iso if feature_overlay is None else feature_overlay * updated_points_iso
677
+
678
+ # Combine with the static raster background
679
+ if feature_overlay is not None:
680
+ combined_overlay = raster * feature_overlay
681
+ else:
682
+ combined_overlay = raster
683
+
684
+ if title is not None:
685
+ combined_overlay = combined_overlay.opts(title=title)
686
+
687
+ return combined_overlay
688
+
689
+ # Create a horizontal control widget on top of the plot
690
+ # Create the slider widget with explicit visibility
691
+ size_slider = pn.widgets.FloatSlider(
692
+ name="Marker Size",
693
+ start=1.0,
694
+ end=20.0,
695
+ step=0.5,
696
+ value=markersize,
697
+ width=300,
698
+ height=40,
699
+ margin=(5, 5),
700
+ show_value=True
701
+ )
702
+
703
+ # Create the slider widget row with clear styling
704
+ slider_widget = pn.Row(
705
+ pn.pane.HTML("<b>Marker Size Control:</b>", width=150, height=40, margin=(5, 10)),
706
+ size_slider,
707
+ height=60,
708
+ margin=10
709
+ )
710
+
711
+ # Create slider widget
712
+ size_slider = pn.widgets.FloatSlider(
713
+ name="Marker Size",
714
+ start=1.0,
715
+ end=20.0,
716
+ step=0.5,
717
+ value=markersize,
718
+ width=300,
719
+ height=40,
720
+ margin=(5, 5),
721
+ show_value=True
722
+ )
723
+
724
+ slider_widget = pn.Row(
725
+ pn.pane.HTML("<b>Marker Size:</b>", width=100, height=40, margin=(5, 10)),
726
+ size_slider,
727
+ height=60,
728
+ margin=10
729
+ )
730
+
731
+ # Simple reactive plot - slider mode doesn't use dynamic rasterization
732
+ @pn.depends(size_slider.param.value)
733
+ def reactive_plot(size_val):
734
+ overlay = create_feature_overlay(float(size_val))
735
+ # Apply static rasterization for slider mode
736
+ if raster_dynamic:
737
+ return hd.rasterize(
738
+ overlay,
739
+ aggregator=ds.count(),
740
+ width=raster_max_px,
741
+ height=raster_max_px,
742
+ dynamic=False # Static raster for slider mode
743
+ ).opts(
744
+ cnorm='eq_hist',
745
+ tools=['hover'],
746
+ width=width,
747
+ height=height
748
+ )
749
+ else:
750
+ return overlay
751
+
752
+ # Create layout
753
+ layout = pn.Column(slider_widget, reactive_plot, sizing_mode='stretch_width')
754
+
755
+ return layout
756
+ else:
757
+ # Create a panel layout without slider
758
+ layout = panel.Column(overlay)
574
759
 
575
760
  if filename is not None:
576
761
  # if filename includes .html, save the panel layout to an HTML file
@@ -578,10 +763,17 @@ def plot_2d(
578
763
  layout.save(filename, embed=True)
579
764
  else:
580
765
  # save the panel layout as a png
581
- hv.save(overlay, filename, fmt="png")
766
+ if use_slider_sizing:
767
+ # For slider plots, save the current state of the param_plot
768
+ hv.save(create_feature_overlay(markersize), filename, fmt="png")
769
+ else:
770
+ hv.save(overlay, filename, fmt="png")
582
771
  else:
583
772
  # Check if we're in a notebook environment and display appropriately
584
- return _display_plot(overlay, layout)
773
+ if use_slider_sizing:
774
+ return _display_plot(layout, layout)
775
+ else:
776
+ return _display_plot(overlay, layout)
585
777
 
586
778
 
587
779
  def plot_2d_oracle(
masster/sample/sample.py CHANGED
@@ -287,7 +287,7 @@ class Sample:
287
287
  """
288
288
  # Reset logger configuration flags to allow proper reconfiguration after reload
289
289
  try:
290
- import masster.sample.logger as logger_module
290
+ import masster.logger as logger_module
291
291
 
292
292
  if hasattr(logger_module, "_SAMPLE_LOGGER_CONFIGURED"):
293
293
  logger_module._SAMPLE_LOGGER_CONFIGURED = False
masster/study/plot.py CHANGED
@@ -157,13 +157,43 @@ def plot_consensus_2d(
157
157
  colorby="number_samples",
158
158
  sizeby="inty_mean",
159
159
  markersize=6,
160
+ size="dynamic",
160
161
  alpha=0.7,
161
162
  cmap=None,
163
+ width=900,
164
+ height=900,
165
+ mz_range=None,
166
+ rt_range=None
162
167
  ):
168
+ """
169
+ Plot consensus features in a 2D scatter plot with retention time vs m/z.
170
+
171
+ Parameters:
172
+ filename (str, optional): Path to save the plot
173
+ colorby (str): Column name to use for color mapping (default: "number_samples")
174
+ sizeby (str): Column name to use for size mapping (default: "inty_mean")
175
+ markersize (int): Base marker size (default: 6)
176
+ size (str): Controls whether points scale with zoom. Options:
177
+ 'dynamic' - points use circle() and scale with zoom
178
+ 'static' - points use scatter() and maintain fixed pixel size
179
+ alpha (float): Transparency level (default: 0.7)
180
+ cmap (str, optional): Color map name
181
+ width (int): Plot width in pixels (default: 900)
182
+ height (int): Plot height in pixels (default: 900)
183
+ mz_range (tuple, optional): m/z range for filtering consensus features (min_mz, max_mz)
184
+ rt_range (tuple, optional): Retention time range for filtering consensus features (min_rt, max_rt)
185
+ """
163
186
  if self.consensus_df is None:
164
187
  self.logger.error("No consensus map found.")
165
188
  return
166
189
  data = self.consensus_df.clone()
190
+
191
+ # Filter by mz_range and rt_range if provided
192
+ if mz_range is not None:
193
+ data = data.filter((pl.col("mz") >= mz_range[0]) & (pl.col("mz") <= mz_range[1]))
194
+ if rt_range is not None:
195
+ data = data.filter((pl.col("rt") >= rt_range[0]) & (pl.col("rt") <= rt_range[1]))
196
+
167
197
  if colorby not in data.columns:
168
198
  self.logger.error(f"Column {colorby} not found in consensus_df.")
169
199
  return
@@ -238,21 +268,33 @@ def plot_consensus_2d(
238
268
  )
239
269
  # scatter plot rt vs mz
240
270
  p = bp.figure(
241
- width=800,
242
- height=600,
271
+ width=width,
272
+ height=height,
243
273
  title="Consensus map",
244
274
  )
245
275
  p.xaxis.axis_label = "Retention Time (min)"
246
276
  p.yaxis.axis_label = "m/z"
247
- scatter_renderer = p.scatter(
248
- x="rt",
249
- y="mz",
250
- size="markersize",
251
- fill_color={"field": colorby, "transform": color_mapper},
252
- line_color=None,
253
- alpha=alpha,
254
- source=source,
255
- )
277
+ scatter_renderer: Any = None
278
+ if size.lower() in ["dyn", "dynamic"]:
279
+ scatter_renderer = p.circle(
280
+ x="rt",
281
+ y="mz",
282
+ radius=markersize / 10,
283
+ fill_color={"field": colorby, "transform": color_mapper},
284
+ line_color=None,
285
+ alpha=alpha,
286
+ source=source,
287
+ )
288
+ else:
289
+ scatter_renderer = p.scatter(
290
+ x="rt",
291
+ y="mz",
292
+ size="markersize",
293
+ fill_color={"field": colorby, "transform": color_mapper},
294
+ line_color=None,
295
+ alpha=alpha,
296
+ source=source,
297
+ )
256
298
  # add hover tool
257
299
  hover = HoverTool(
258
300
  tooltips=[
@@ -292,16 +334,36 @@ def plot_samples_2d(
292
334
  samples=None,
293
335
  filename=None,
294
336
  markersize=2,
295
- size="const",
337
+ size="dynamic",
296
338
  alpha_max=0.8,
297
339
  alpha="inty",
298
340
  cmap="Turbo256",
299
- max_features=50000, # Reduced default for better performance with many samples
341
+ max_features=50000,
342
+ width=900,
343
+ height=900,
344
+ mz_range=None,
345
+ rt_range=None
300
346
  ):
301
347
  """
302
348
  Plot all feature maps for sample_uid in parameter uids in an overlaid scatter plot.
303
349
  Each sample is a different color. Alpha scales with intensity.
304
350
  OPTIMIZED VERSION: Uses vectorized operations and batch processing.
351
+
352
+ Parameters:
353
+ samples: Sample UIDs to plot
354
+ filename (str, optional): Path to save the plot
355
+ markersize (int): Base marker size (default: 2)
356
+ size (str): Controls whether points scale with zoom. Options:
357
+ 'dynamic' or 'dyn' - points use circle() and scale with zoom
358
+ 'const', 'static' or other - points use scatter() and maintain fixed pixel size
359
+ alpha_max (float): Maximum transparency level (default: 0.8)
360
+ alpha (str): Column name to use for alpha mapping (default: "inty")
361
+ cmap (str): Color map name (default: "Turbo256")
362
+ max_features (int): Maximum number of features to plot (default: 50000)
363
+ width (int): Plot width in pixels (default: 900)
364
+ height (int): Plot height in pixels (default: 900)
365
+ mz_range (tuple, optional): m/z range for filtering features (min_mz, max_mz)
366
+ rt_range (tuple, optional): Retention time range for filtering features (min_rt, max_rt)
305
367
  """
306
368
 
307
369
  sample_uids = self._get_sample_uids(samples)
@@ -314,8 +376,8 @@ def plot_samples_2d(
314
376
  color_map = {uid: colors[i * (256 // max(1, len(sample_uids)))] for i, uid in enumerate(sample_uids)}
315
377
 
316
378
  p = figure(
317
- width=600,
318
- height=600,
379
+ width=width,
380
+ height=height,
319
381
  title="Sample Features",
320
382
  )
321
383
  p.xaxis.axis_label = "Retention Time (RT)"
@@ -323,6 +385,12 @@ def plot_samples_2d(
323
385
 
324
386
  # OPTIMIZATION 1: Batch filter all features for selected samples at once
325
387
  features_batch = self.features_df.filter(pl.col("sample_uid").is_in(sample_uids))
388
+
389
+ # Filter by mz_range and rt_range if provided
390
+ if mz_range is not None:
391
+ features_batch = features_batch.filter((pl.col("mz") >= mz_range[0]) & (pl.col("mz") <= mz_range[1]))
392
+ if rt_range is not None:
393
+ features_batch = features_batch.filter((pl.col("rt") >= rt_range[0]) & (pl.col("rt") <= rt_range[1]))
326
394
 
327
395
  if features_batch.is_empty():
328
396
  self.logger.error("No features found for the selected samples.")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: masster
3
- Version: 0.3.1
3
+ Version: 0.3.3
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
@@ -16,10 +16,10 @@ masster/sample/helpers.py,sha256=OEgvR3bptA-tEqHAFVPjWpbagKXAU1h0bePPi9ttHa4,348
16
16
  masster/sample/lib.py,sha256=9r2XlF_BaJ4WNAsQo8hElieRLwsAv0yrbYq4DJ0iVOM,33496
17
17
  masster/sample/load.py,sha256=y-KUJ2nCFX_06FHPUOh-CzRRvaTx14xNcXoL19bU8qY,47562
18
18
  masster/sample/parameters.py,sha256=Gg2KcuNbV_wZ_Wwv93QlM5J19ji0oSIvZLPV1NoBmq0,4456
19
- masster/sample/plot.py,sha256=wd-4OosFT8MoO0fM8PSMskZK_yg8i8vfbiTieAzgrv4,62831
19
+ masster/sample/plot.py,sha256=uUJAd2qxhVG6Ev2hLuU406zFA2TDkkBz2MG12P9fLik,71449
20
20
  masster/sample/processing.py,sha256=NjNLt47Fy0UF3Xs35NBhADg57qTC6Lfa4Xz8Y30v83A,58250
21
21
  masster/sample/quant.py,sha256=tHNjvUFTdehKR31BXBZnVsBxMD9XJHgaltITOjr71uE,7562
22
- masster/sample/sample.py,sha256=UlyA7cZtV_IMO8PRaYaUqf8cfAGfavVVfNDo0g_6OJw,16185
22
+ masster/sample/sample.py,sha256=7ivuAMb3JlFikLOxZjTGwYmuqGehLz9d47gQxfSRtf4,16178
23
23
  masster/sample/sample5_schema.json,sha256=3SPFQZH4SooLYUt_lW-PCOE9rHnl56Vhc2XG-r1nyEQ,3586
24
24
  masster/sample/save.py,sha256=o9eFSqqr7KYwvCD3gOJt_nZ4h3pkflWqs0n0oSLM-sU,31970
25
25
  masster/sample/sciex.py,sha256=q6PdcjCtV2PWnJiXuvfISu09zjkaTR_fvHvWN9OvOcM,46870
@@ -36,7 +36,7 @@ masster/study/helpers.py,sha256=SeW17rA3BIM2I2Whiye6wegRRSCabIpQoCsjOCafjKw,7488
36
36
  masster/study/helpers_optimized.py,sha256=EgOgPaL3c2LA8jDhnlEHvzb7O9Um-vnMIcnNaoH90gA,13620
37
37
  masster/study/load.py,sha256=TLxVhXu0HHb51lGggXitQLtfNxz2JJfKMkAXJbxhvhM,46880
38
38
  masster/study/parameters.py,sha256=0elaF7YspTsB7qyajWAbRNL2VfKlGz5GJLifmO8IGkk,3276
39
- masster/study/plot.py,sha256=hOG8bBT3mYV63FieEk-gYKtOyIXWppkTu21VeGbRnGk,21918
39
+ masster/study/plot.py,sha256=NW31XdM9Bf5wNvIAs-56AIoPA8VLTqBzr6qJInfZmhc,25159
40
40
  masster/study/processing.py,sha256=BQuSBO7O8iTlCjXenECyg0_PAsPF1NNiUllypuemPZI,46101
41
41
  masster/study/save.py,sha256=bcRADWTvhTER9WRkT9zNU5mDUPQZkZB2cuJwpRsYmrM,6589
42
42
  masster/study/study.py,sha256=5TZgG7tr7mzqHh1tm48V8SEcvRcWiFYG9iDqz0U9ACc,27073
@@ -52,8 +52,8 @@ masster/study/defaults/integrate_chrom_def.py,sha256=Rih3-vat7fHGVfIvRitjNJJI3zL
52
52
  masster/study/defaults/integrate_def.py,sha256=Vf4SAzdBfnsSZ3IRaF0qZvWu3gMDPHdgPfMYoPKeWv8,7246
53
53
  masster/study/defaults/merge_def.py,sha256=EBsKE3hsAkTEzN9dpdRD5W3_suTKy_WZ_96rwS0uBuE,8572
54
54
  masster/study/defaults/study_def.py,sha256=hj8bYtEPwzdowC95yfyoCFt6fZkQePLjpJtmpNz9Z5M,9533
55
- masster-0.3.1.dist-info/METADATA,sha256=VLzNZSby0weoT9QUfjleppVOtuvt_GtZu6AfLRM9MSg,44356
56
- masster-0.3.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
57
- masster-0.3.1.dist-info/entry_points.txt,sha256=ZHguQ_vPmdbpqq2uGtmEOLJfgP-DQ1T0c07Lxh30wc8,58
58
- masster-0.3.1.dist-info/licenses/LICENSE,sha256=bx5iLIKjgAdYQ7sISn7DsfHRKkoCUm1154sJJKhgqnU,35184
59
- masster-0.3.1.dist-info/RECORD,,
55
+ masster-0.3.3.dist-info/METADATA,sha256=LL4pM_FKHDM6RiOTBMI7fOeSnqVwZy0MX_ahftH3iFw,44356
56
+ masster-0.3.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
57
+ masster-0.3.3.dist-info/entry_points.txt,sha256=ZHguQ_vPmdbpqq2uGtmEOLJfgP-DQ1T0c07Lxh30wc8,58
58
+ masster-0.3.3.dist-info/licenses/LICENSE,sha256=bx5iLIKjgAdYQ7sISn7DsfHRKkoCUm1154sJJKhgqnU,35184
59
+ masster-0.3.3.dist-info/RECORD,,