docstr: Creates 1-letter amino acid codes from DataFrame
  
  Non-canonical amino-acids are converted as follows:
  ASH (protonated ASP) => D
  CYX (disulfide-bonded CYS) => C
  GLH (protonated GLU) => E
  HID/HIE/HIP (different protonation states of HIS) = H
  HYP (hydroxyproline) => P
  MSE (selenomethionine) => M
  
  Parameters
  ----------
  record : str, default: 'ATOM'
      Specfies the record DataFrame.
  residue_col : str,  default: 'residue_name'
      Column in `record` DataFrame to look for 3-letter amino acid
      codes for the conversion.
  fillna : str, default: '?'
      Placeholder string to use for unknown amino acids.
  
  Returns
  ---------
  pandas.DataFrame : Pandas DataFrame object consisting of two columns,
      `'chain_id'` and `'residue_name'`, where the former contains
      the chain ID of the amino acid and the latter
      contains the 1-letter amino acid code, respectively.
code: def amino3to1(
      self, record="ATOM", residue_col="residue_name", fillna="?"
  ):
      """Creates 1-letter amino acid codes from DataFrame
  
      Non-canonical amino-acids are converted as follows:
      ASH (protonated ASP) => D
      CYX (disulfide-bonded CYS) => C
      GLH (protonated GLU) => E
      HID/HIE/HIP (different protonation states of HIS) = H
      HYP (hydroxyproline) => P
      MSE (selenomethionine) => M
  
      Parameters
      ----------
      record : str, default: 'ATOM'
          Specfies the record DataFrame.
      residue_col : str,  default: 'residue_name'
          Column in `record` DataFrame to look for 3-letter amino acid
          codes for the conversion.
      fillna : str, default: '?'
          Placeholder string to use for unknown amino acids.
  
      Returns
      ---------
      pandas.DataFrame : Pandas DataFrame object consisting of two columns,
          `'chain_id'` and `'residue_name'`, where the former contains
          the chain ID of the amino acid and the latter
          contains the 1-letter amino acid code, respectively.
  
      """
      tmp = self.df[record]
      cmp = "placeholder"
      indices = []
  
      residue_number_insertion = (
          tmp["residue_number"].astype(str) + tmp["insertion"]
      )
  
      for num, ind in zip(
          residue_number_insertion, np.arange(tmp.shape[0])
      ):
          if num != cmp:
              indices.append(ind)
          cmp = num
  
      transl = (
          tmp.iloc[indices][residue_col]
          .map(amino3to1dict)
          .fillna(fillna)
      )
  
      return pd.concat((tmp.iloc[indices]["chain_id"], transl), axis=1)
  
imports: from __future__ import annotations
  import os
  import copy
  import gzip
  import warnings
  from string import ascii_uppercase
  from typing import Any, Dict, List, Union
  from warnings import warn
  import numpy
  import pandas
  from looseversion import LooseVersion
  from mmtf import MMTFDecoder, MMTFEncoder, fetch, parse, parse_gzip
  from biopandas.constants import protein_letters_3to1_extended
  from ..pdb.engines import amino3to1dict, pdb_df_columns, pdb_records
label_desc: Use image node_id 15 for calling the PandasMmtf obj's underlying member method code with example usage: obj.amino3to1(record, residue_col, fillna) and returns: pd