@@ -348,17 +348,33 @@ def refit(matrix_file: Annotated[str, typer.Argument(help='Tab separated matrix
348348 start_time = time .time ()
349349 file_name , file_extension = os .path .splitext (matrix_file )
350350
351- # Handle VCF input
352- if file_extension == '.vcf' :
351+ # Handle VCF input (both .vcf and .vcf.gz)
352+ if file_extension == '.vcf' or ( file_extension == '.gz' and os . path . splitext ( file_name )[ 1 ] == '.vcf' ) :
353353 if not ref_genome and not genome_path :
354354 raise ValueError ("Either ref_genome or genome_path must be provided." )
355355 genome_path = download_reference_genome (ref_genome = ref_genome , genome_path = genome_path )
356356 logger .info (f"Reference genome path: { genome_path } " )
357- count_mutation (matrix_file , genome_path , f'{ output_folder } /matrix.csv' , numeric_chromosomes , genotyped )
358- matrix_file = f'{ output_folder } /matrix.csv'
357+ # Derive output csv path from input sample name
358+ sample_name = Path (matrix_file ).name
359+ if sample_name .endswith ('.vcf.gz' ):
360+ sample_name = sample_name [:- 7 ]
361+ elif sample_name .endswith ('.vcf' ):
362+ sample_name = sample_name [:- 4 ]
363+ out_csv = f"{ output_folder } /{ sample_name } .csv"
364+ os .makedirs (output_folder , exist_ok = True )
365+ count_mutation (matrix_file , genome_path , out_csv , numeric_chromosomes , genotyped )
366+ matrix_file = out_csv
359367
360368 # Read input data
361369 M = read_counts (matrix_file )
370+
371+ # Remove rows with all zeros (can occur with genotyped VCFs)
372+ row_sums = M .sum (axis = 1 )
373+ if (row_sums == 0 ).any ():
374+ n_zero_rows = (row_sums == 0 ).sum ()
375+ logger .warning (f"Removing { n_zero_rows } empty row(s) with zero mutation counts from the matrix" )
376+ M = M [row_sums > 0 ]
377+
362378 index_matrix = M .index .values .tolist ()
363379 S = read_signature (signature_file )
364380
@@ -376,7 +392,23 @@ def refit(matrix_file: Annotated[str, typer.Argument(help='Tab separated matrix
376392 S = signatures
377393
378394 if signature_names is not None :
379- S = filter_signatures (S , signature_names .split (',' ))
395+ requested_sigs = signature_names .split (',' )
396+ # Only keep signatures that are both requested and available after filtering
397+ available_requested = [sig for sig in requested_sigs if sig in S .index ]
398+
399+ if len (available_requested ) < 5 :
400+ missing_sigs = [sig for sig in requested_sigs if sig not in S .index ]
401+ logger .warning (f"Only { len (available_requested )} of the requested signatures are available after correlation filtering." )
402+ logger .warning (f"Missing signatures: { ', ' .join (missing_sigs )} " )
403+ logger .warning (f"Available signatures: { ', ' .join (S .index .tolist ())} " )
404+ raise ValueError (f"Only { len (available_requested )} requested signatures are available after filtering. At least 5 are required. Missing: { missing_sigs } " )
405+
406+ if len (available_requested ) < len (requested_sigs ):
407+ missing_sigs = [sig for sig in requested_sigs if sig not in S .index ]
408+ logger .warning (f"Some requested signatures were filtered out due to low correlation with the sample: { ', ' .join (missing_sigs )} " )
409+ logger .info (f"Using { len (available_requested )} available signatures: { ', ' .join (available_requested )} " )
410+
411+ S = filter_signatures (S , available_requested )
380412
381413 # Prepare data for analysis
382414 index_signature = S .index .values .tolist ()
@@ -496,7 +528,7 @@ def get_lambda(data_type: DataType) -> float:
496528 Returns:
497529 float: Lambda value for regularization
498530 """
499- return 100 if data_type == DataType .genome else 0.7
531+ return 1000 if data_type == DataType .genome else 0.7
500532
501533
502534def read_opportunity (M : np .ndarray , opportunity_file : Optional [str ] = None ) -> np .ndarray :
@@ -614,17 +646,33 @@ def denovo(matrix_file: Annotated[str, typer.Argument(help='Tab separated matrix
614646 logger .info (f'Starting de novo analysis for { run_name } ' )
615647 start_time = time .time ()
616648
617- # Handle VCF input
618- if matrix_file .endswith ('.vcf' ):
649+ # Handle VCF input (both .vcf and .vcf.gz)
650+ if matrix_file .endswith ('.vcf' ) or matrix_file . endswith ( '.vcf.gz' ) :
619651 if not ref_genome and not genome_path :
620652 raise ValueError ("Either ref_genome or genome_path must be provided." )
621653 genome_path = download_reference_genome (ref_genome = ref_genome , genome_path = genome_path )
622654 logger .info (f"Reference genome path: { genome_path } " )
623- count_mutation (matrix_file , genome_path , f'{ output_folder } /matrix.csv' , numeric_chromosomes , genotyped )
624- matrix_file = f'{ output_folder } /matrix.csv'
655+ # Derive output csv path from input sample name
656+ sample_name = Path (matrix_file ).name
657+ if sample_name .endswith ('.vcf.gz' ):
658+ sample_name = sample_name [:- 7 ]
659+ elif sample_name .endswith ('.vcf' ):
660+ sample_name = sample_name [:- 4 ]
661+ out_csv = f"{ output_folder } /{ sample_name } .csv"
662+ os .makedirs (output_folder , exist_ok = True )
663+ count_mutation (matrix_file , genome_path , out_csv , numeric_chromosomes , genotyped )
664+ matrix_file = out_csv
625665
626666 # Read and prepare data
627667 M = read_counts (matrix_file )
668+
669+ # Remove rows with all zeros (can occur with genotyped VCFs)
670+ row_sums = M .sum (axis = 1 )
671+ if (row_sums == 0 ).any ():
672+ n_zero_rows = (row_sums == 0 ).sum ()
673+ logger .warning (f"Removing { n_zero_rows } empty row(s) with zero mutation counts from the matrix" )
674+ M = M [row_sums > 0 ]
675+
628676 index_matrix = M .index .values .tolist ()
629677 desired_order = M .columns
630678 O = read_opportunity (M , opportunity_file )
0 commit comments