docs: def get_atlas_summary_df(self):
          """Create a single data frame which summarizes all genes per row.
  
          Returns:
              DataFrame: Pandas DataFrame of the results
  
          """
          all_info = []
          for g in self.reference_gempro.genes_with_a_representative_sequence:
              info = {}
              info['Gene_ID'] = g.id
              info['Gene_name'] = g.name
  
              # Protein object
              p = g.protein
              info['Protein_sequences'] = len(p.sequences)
              info['Protein_structures'] = len(p.structures)
  
              # SeqProp
              rseq = p.representative_sequence
              info['RepSeq_ID'] = rseq.id
              info['RepSeq_sequence_length'] = rseq.seq_len
              info['RepSeq_num_sequence_alignments'] = len([x for x in p.sequence_alignments if x.annotations['ssbio_type'] == 'seqalign'])
              info['RepSeq_num_structure_alignments'] = len([x for x in p.sequence_alignments if x.annotations['ssbio_type'] == 'structalign'])
  
              # SeqRecord annotations (properties calculated that summarize the whole sequence)
              for annotation_name, annotation in rseq.annotations.items():
                  info['RepSeq_' + annotation_name] = annotation
  
              # SeqRecord alignment annotations
              all_num_mutations = []
              all_num_deletions = []
              all_len_deletions = []
              all_num_insertions = []
              all_len_insertions = []
              all_percent_identity = []
              all_percent_similarity = []
              for aln in p.sequence_alignments:
                  # Gather the strain speicific stuff
                  if '{}_'.format(p.id) not in aln.annotations['b_seq']:
                      continue
                  info[aln.annotations['b_seq'].split('{}_'.format(p.id))[1]] = aln.annotations['percent_identity']
  
                  # Gather the percent identities/similarities
                  all_percent_identity.append(aln.annotations['percent_identity'])
                  all_percent_similarity.append(aln.annotations['percent_similarity'])
  
                  # Gather the number of residues that are mutated (filter for different mutations of same residue)
                  num_mutations = len(list(set([x[1] for x in aln.annotations['mutations']])))
                  all_num_mutations.append(num_mutations)
  
                  # Gather the number of deletions as well as the length of the deletion
                  if not aln.annotations['deletions']:
                      num_deletions = 0
                      len_deletions = [0]
                  else:
                      num_deletions = len(aln.annotations['deletions'])
                      len_deletions = [x[1] for x in aln.annotations['deletions']]
                  all_num_deletions.append(num_deletions)
                  # Get the total length of the deletion for this one strain
                  avg_len_deletions = np.sum(len_deletions)
                  all_len_deletions.append(avg_len_deletions)
  
                  # Gather the number of insertions as well as the length of the insertion
                  if not aln.annotations['insertions']:
                      num_insertions = 0
                      len_insertions = [0]
                  else:
                      num_insertions = len(aln.annotations['insertions'])
                      len_insertions = [x[1] for x in aln.annotations['insertions']]
                  all_num_insertions.append(num_insertions)
                  # Get the total length of insertion for this one strain
                  avg_len_insertions = np.sum(len_insertions)
                  all_len_insertions.append(avg_len_insertions)
  
              info['ATLAS_mean_num_mutations'] = np.mean(all_num_mutations)
              info['ATLAS_mean_num_deletions'] = np.mean(all_num_deletions)
              info['ATLAS_mean_len_deletions'] = np.mean(all_len_deletions)
              info['ATLAS_mean_num_insertions'] = np.mean(all_num_insertions)
              info['ATLAS_mean_len_insertions'] = np.mean(all_len_insertions)
              info['ATLAS_mean_percent_identity'] = np.mean(all_percent_identity)
              info['ATLAS_mean_percent_similarity'] = np.mean(all_percent_similarity)
  
              # Other mutation analysis
              single, fingerprint = p.sequence_mutation_summary()
  
              # Mutations that show up in more than 10% of strains
              singles = []
              for k, v in single.items():
                  k = [str(x) for x in k]
                  if len(v) / len(p.sequence_alignments) >= 0.01:
                      singles.append(''.join(k))  # len(v) is the number of strains which have this mutation
              info['ATLAS_popular_mutations'] = ';'.join(singles)
  
              # Mutation groups that show up in more than 10% of strains
              allfingerprints = []
              for k, v in fingerprint.items():
                  if len(v) / len(p.sequence_alignments) >= 0.01:
                      fingerprints = []
                      for m in k:
                          y = [str(x) for x in m]
                          fingerprints.append(''.join(y))
                      allfingerprints.append('-'.join(fingerprints))
              info['ATLAS_popular_mutation_groups'] = ';'.join(allfingerprints)
  
              # StructProp
              rstruct = p.representative_structure
              if rstruct:
                  if rstruct.structure_file:
                      info['RepStruct_ID'] = rstruct.id
                      info['RepStruct_is_experimental'] = rstruct.is_experimental
                      info['RepStruct_description'] = rstruct.description
                      info['RepStruct_repseq_coverage'] = p.representative_chain_seq_coverage
  
                      # ChainProp
                      rchain = p.representative_chain
                      info['RepChain_ID'] = rchain
  
                      # ChainProp SeqRecord annotations
                      rchain_sr = rstruct.chains.get_by_id(rchain).seq_record
                      for annotation_name, annotation in rchain_sr.annotations.items():
                          info['RepChain_' + annotation_name] = annotation
  
              all_info.append(info)
  
          cols = ['Gene_ID', 'Gene_name', 'Protein_sequences', 'Protein_structures',
                  'RepSeq_ID', 'RepSeq_sequence_length',
                  'RepSeq_num_sequence_alignments', 'RepSeq_num_structure_alignments',
                  'RepStruct_ID', 'RepChain_ID', 'RepStruct_description',
                  'RepStruct_is_experimental', 'RepStruct_repseq_coverage',
                  'ATLAS_mean_percent_identity', 'ATLAS_mean_percent_similarity', 'ATLAS_mean_num_mutations',
                  'ATLAS_popular_mutations', 'ATLAS_popular_mutation_groups', 'ATLAS_mean_num_deletions',
                  'ATLAS_mean_num_insertions', 'ATLAS_mean_len_deletions', 'ATLAS_mean_len_insertions',
                  'RepSeq_aromaticity', 'RepSeq_instability_index', 'RepSeq_isoelectric_point', 'RepSeq_molecular_weight',
                  'RepSeq_monoisotopic', 'RepSeq_num_tm_helix-tmhmm', 'RepSeq_percent_acidic', 'RepSeq_percent_aliphatic',
                  'RepSeq_percent_aromatic', 'RepSeq_percent_B-sspro8', 'RepSeq_percent_basic',
                  'RepSeq_percent_buried-accpro', 'RepSeq_percent_buried-accpro20', 'RepSeq_percent_C-sspro',
                  'RepSeq_percent_C-sspro8', 'RepSeq_percent_charged', 'RepSeq_percent_E-sspro',
                  'RepSeq_percent_E-sspro8', 'RepSeq_percent_exposed-accpro', 'RepSeq_percent_exposed-accpro20',
                  'RepSeq_percent_G-sspro8', 'RepSeq_percent_H-sspro', 'RepSeq_percent_H-sspro8',
                  'RepSeq_percent_helix_naive', 'RepSeq_percent_I-sspro8', 'RepSeq_percent_non-polar',
                  'RepSeq_percent_polar', 'RepSeq_percent_S-sspro8', 'RepSeq_percent_small',
                  'RepSeq_percent_strand_naive', 'RepSeq_percent_T-sspro8', 'RepSeq_percent_tiny',
                  'RepSeq_percent_turn_naive', 'RepChain_percent_B-dssp', 'RepChain_percent_C-dssp',
                  'RepChain_percent_E-dssp', 'RepChain_percent_G-dssp', 'RepChain_percent_H-dssp',
                  'RepChain_percent_I-dssp', 'RepChain_percent_S-dssp', 'RepChain_percent_T-dssp',
                  'RepChain_SSBOND-biopython']
          cols.extend([x.id for x in self.strains])
  
          df_atlas_summary = pd.DataFrame(all_info, columns=cols)
          # Drop columns that don't have anything in them
          df_atlas_summary.dropna(axis=1, how='all', inplace=True)
  
          return df_atlas_summary