PyEvoMotion 0.1.0__py3-none-any.whl → 0.1.2__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.
PyEvoMotion/cli.py CHANGED
@@ -248,6 +248,13 @@ def _parse_arguments() -> argparse.Namespace:
248
248
  action="store_true",
249
249
  help="Export the plots of the analysis."
250
250
  )
251
+ parser.add_argument(
252
+ "-cl",
253
+ "--confidence_level",
254
+ type=float,
255
+ default=0.95,
256
+ help="Confidence level for parameter confidence intervals (default 0.95 for 95%% CI). Must be between 0 and 1."
257
+ )
251
258
  parser.add_argument(
252
259
  "-l",
253
260
  "--length_filter",
@@ -255,13 +262,6 @@ def _parse_arguments() -> argparse.Namespace:
255
262
  default=0,
256
263
  help="Length filter for the sequences (removes sequences with length less than the specified value). Default is 0."
257
264
  )
258
- parser.add_argument(
259
- "-n",
260
- "--n_threshold",
261
- type=int,
262
- default=2,
263
- help="Minimum number of sequences required in a time interval to compute statistics. Default is 2."
264
- )
265
265
  parser.add_argument(
266
266
  "-xj",
267
267
  "--export_json",
@@ -364,6 +364,73 @@ def _simple_serializer(k: str, v: any) -> any:
364
364
  return "..".join(map(lambda x: x.strftime("%Y-%m-%d") if x else "", v))
365
365
  return v
366
366
 
367
+ def _remove_model_functions(obj):
368
+ """Recursively remove 'model' keys containing lambda functions from nested dictionaries.
369
+
370
+ :param obj: Dictionary or other object to clean
371
+ :type obj: any
372
+ :return: Cleaned object with model functions removed
373
+ :rtype: any
374
+ """
375
+ if isinstance(obj, dict):
376
+ # Create a copy to avoid modifying during iteration
377
+ cleaned_obj = {}
378
+ for key, value in obj.items():
379
+ if key == "model":
380
+ # Skip lambda model functions - they can't be serialized to JSON
381
+ continue
382
+ elif isinstance(value, dict):
383
+ # Recursively clean nested dictionaries
384
+ cleaned_obj[key] = _remove_model_functions(value)
385
+ else:
386
+ # Keep all other values
387
+ cleaned_obj[key] = value
388
+ return cleaned_obj
389
+ else:
390
+ return obj
391
+
392
+ def _restructure_regression_results(reg_results):
393
+ """Restructure regression results for cleaner JSON export format.
394
+
395
+ :param reg_results: Raw regression results from analysis
396
+ :type reg_results: dict
397
+ :return: Restructured results with cleaner format
398
+ :rtype: dict
399
+ """
400
+ restructured = {}
401
+
402
+ for key, value in reg_results.items():
403
+ if key.endswith("_full_results"):
404
+ # Extract the base name (remove _full_results suffix)
405
+ base_name = key.replace("_full_results", "")
406
+
407
+ # Create the new structure with only essential fields
408
+ restructured[base_name] = {
409
+ "linear_model": {
410
+ "parameters": value["linear_model"]["parameters"],
411
+ "confidence_intervals": value["linear_model"]["confidence_intervals"],
412
+ "expression": value["linear_model"]["expression"],
413
+ "r2": value["linear_model"]["r2"],
414
+ "confidence_level": value["linear_model"]["confidence_level"]
415
+ },
416
+ "power_law_model": {
417
+ "parameters": value["power_law_model"]["parameters"],
418
+ "confidence_intervals": value["power_law_model"]["confidence_intervals"],
419
+ "expression": value["power_law_model"]["expression"],
420
+ "r2": value["power_law_model"]["r2"],
421
+ "confidence_level": value["power_law_model"]["confidence_level"]
422
+ },
423
+ "model_selection": value["model_selection"]
424
+ }
425
+ else:
426
+ # Keep non-full-results entries as-is (backward compatibility models)
427
+ # But skip them if there's a corresponding _full_results entry
428
+ full_results_key = f"{key}_full_results"
429
+ if full_results_key not in reg_results:
430
+ restructured[key] = value
431
+
432
+ return restructured
433
+
367
434
  def _main():
368
435
  check_and_install_mafft()
369
436
  """
@@ -374,6 +441,11 @@ def _main():
374
441
  print(BANNER)
375
442
  args = _parse_arguments()
376
443
 
444
+ # Validate confidence level
445
+ if not (0 < args.confidence_level < 1):
446
+ parser = _ArgumentParserWithHelpOnError(description=PACKAGE_DESCRIPTION)
447
+ parser.error("Confidence level must be between 0 and 1 (exclusive)")
448
+
377
449
  # If the -xj argument is passed, the arguments are exported to a JSON file before running the analysis altogether
378
450
  if args.export_json:
379
451
  with open(f"{args.out}_run_args.json", "w") as file:
@@ -407,20 +479,24 @@ def _main():
407
479
  # Runs the analysis
408
480
  stats, reg = instance.analysis(
409
481
  length=args.length_filter,
410
- n_threshold=args.n_threshold,
411
482
  show=args.show,
412
483
  mutation_kind=args.kind,
413
484
  export_plots_filename=(
414
485
  f"{args.out}_plots"
415
486
  if args.export_plots
416
487
  else None
417
- )
488
+ ),
489
+ confidence_level=args.confidence_level
418
490
  )
419
491
 
420
492
  _reg = reg.copy()
421
493
 
422
- for k in _reg.keys():
423
- del _reg[k]["model"]
494
+ # First restructure the results to the desired export format
495
+ _reg = _restructure_regression_results(_reg)
496
+
497
+ # Then apply the cleaning function to remove lambda functions
498
+ for k in list(_reg.keys()):
499
+ _reg[k] = _remove_model_functions(_reg[k])
424
500
 
425
501
  # Exports the statistic results to TSV file
426
502
  stats.to_csv(
@@ -432,6 +508,7 @@ def _main():
432
508
  # Exports the regression models to a JSON file
433
509
  with open(f"{args.out}_regression_results.json", "w") as file:
434
510
  json.dump(_reg, file, indent=4)
511
+ print(f"Regression results saved to {args.out}_regression_results.json")
435
512
 
436
513
  # Exits the program with code 0 (success)
437
514
  exit(0)