Answers.Body: <p>As you suggest one way of solving your problem would be by selecting all atoms that don't have backbone atoms names. In a pdb file I believe backbone atoms would be named 'CA', 'HA', 'N', 'HN' or 'H', 'C' and 'O'. Beware of the N-terminal (where the hydrogens would be named either 'H1', 'H2' &amp; 'H3'; or 'HN1', 'HN2' and 'HN3') and the C-terminal (the other oxygen would be named 'OXT').</p>
  <p>One way of doing it is by using the handy selections from pandas dataframes. It's probably a more elegant way than making a list of dataframes.</p>
  <pre class="lang-py prettyprint-override"><code>from biopandas.pdb import PandasPdb
  
  bpdf_1 = PandasPdb().fetch_pdb('1t48').df['ATOM']
  bpdf_2 = PandasPdb().fetch_pdb('1t49').df['ATOM']
  
  # Function returns a list of boolean. True when it's not a backbone atom.
  sel = lambda df: df['atom_name'].str.contains('[^(CA|HA|N|C|O|HN|H)]$')
  
  # The number of atom is not the same, so I only align the first 200
  sidechain_rmsd = PandasPdb.rmsd(bpdf_1[sel][:200], bpdf_2[sel][:200])
  </code></pre>
  <p>The regex says something like &quot;(not (CA or HA or …)) end of line&quot;. The end of line is important, otherwise any atom containing N, C, O or H in their name would be excluded (so most of them).</p>
  <p>Note that with this method it's still possible to use the PandasPdb selectors. For example, to only consider heavy atoms (no hydrogen):</p>
  <pre class="lang-py prettyprint-override"><code>sidechain_rmsd = PandasPdb.rmsd(bpdf_1[sel][:200],
                                  bpdf_2[sel][:200],
                                  s='heavy')
  </code></pre>
  <p><strong>EDIT:</strong></p>
  <p>Another way to do it would be:</p>
  <pre class="lang-py prettyprint-override"><code>sidechain_rmsd = PandasPdb.rmsd(bpdf_1[:200],
                                  bpdf_2[:200],
                                  s='main chain',
                                  invert=True)
  </code></pre>
  <p>You don't need any selection in this case, <strong>BUT</strong> this is a bad idea if you have hydrogens, as it will also align them (including the backbone ones).</p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-03-01T12:53:21.173Z
Answers.Text: If you want to align each residue one by one instead: I'm sure this gives you the tools to do it, though it would be a pretty bad idea. In this very case I'd advise to try comparing side-chains using dihedral angles (hence rotamers). You can have a look at pyrosetta for this.
Answers.UserDisplayName: O.Laprevote
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-03-01T13:40:42.610Z
Answers.Text: Thanks for your detailed response! To check that I understood right: the H[0-9]* and HN[0-9]* are the names of the hydrogen atoms in the amino group? So I need to filter them out.
Answers.UserDisplayName: CubeHead
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-03-01T15:55:18.770Z
Answers.Text: Yes, although you can get away by just filtering out H[1-3] and HN[1-3]. More hydrogen atoms would be disturbing.
Answers.UserDisplayName: O.Laprevote
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-03-01T16:19:49.890Z
Answers.Text: My bad: H[1-3]? and HN[1-3]?, otherwise you don't cover cases where there is only H or only HN. Remember to keep the $ at the end, otherwise you'd end up matching all H.
Answers.UserDisplayName: O.Laprevote
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-03-01T20:49:54.353Z
Answers.Text: Thanks for your help!
Answers.UserDisplayName: CubeHead
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-03-01T12:18:35.537Z
Answers.LastActivityDate: 2022-03-01T12:44:55.907Z
Answers.LastEditDate: 2022-03-01T12:44:55.907Z
Answers.UserDisplayName: O.Laprevote
Body: <p>I am currently implementing some metrics I could use for comparing two conformations of the same protein in Python.</p>
  <p>For example, I know I could use the RMSD of all protein ATOMS in BioPandas using this:</p>
  <pre><code>biopandas.pdb.PandasPdb.rmsd(conformation1.df['ATOM'], conformation2.df['ATOM'])
  </code></pre>
  <p>Are there some out-of-the-box tools in Python for measuring the RMSD between the side chains of the two conformations? When trying to do this manually, the main issue is how to identify side chain atoms, which is not clear for me. I know how to get all atoms from a residue using BioPandas:</p>
  <pre><code>aminoacids = list(PandasPdb().read_pdb(my_pdb_filename).df['ATOM'].groupby(['chain_id', 'residue_number', 'residue_name']))
  </code></pre>
  <p>Now <code>aminoacids[i]</code> is a dataframe containing all the atoms of the i-th aminoacid, like this:</p>
  <p><a href="https://i.sstatic.net/9RnK2.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/9RnK2.png" alt="enter image description here" /></a></p>
  <p>From here, it's not clear how to separate back bone atoms from side chain atoms. It's clear that the one with atom_number 'CA' will be the alpha-Carbon, but I am not sure how to identify the others. But once the separation is done, the side chain RMSD could be measure for example using <code>Bio.SVDSuperimposer.SVDSuperimposer</code> which works directly on the array of 3D coordinates of the atoms.</p>
  <p>Thanks!</p>
  
Tags: <python><proteins><protein-structure>
Title: Identify side chain atoms in BioPandas dataframe
ThreadText: # Identify side chain atoms in BioPandas dataframe
  
  (Asked by: username_0 on 2022-02-28)
  
  I am currently implementing some metrics I could use for comparing two conformations of the same protein in Python.
  
  For example, I know I could use the RMSD of all protein ATOMS in BioPandas using this:
  
  ```
  biopandas.pdb.PandasPdb.rmsd(conformation1.df['ATOM'], conformation2.df['ATOM'])
  
  ```
  
  Are there some out-of-the-box tools in Python for measuring the RMSD between the side chains of the two conformations? When trying to do this manually, the main issue is how to identify side chain atoms, which is not clear for me. I know how to get all atoms from a residue using BioPandas:
  
  ```
  aminoacids = list(PandasPdb().read_pdb(my_pdb_filename).df['ATOM'].groupby(['chain_id', 'residue_number', 'residue_name']))
  
  ```
  
  Now `aminoacids[i]` is a dataframe containing all the atoms of the i-th aminoacid, like this:
  
  [![enter image description here](https://i.sstatic.net/9RnK2.png)](https://i.sstatic.net/9RnK2.png)
  
  From here, it's not clear how to separate back bone atoms from side chain atoms. It's clear that the one with atom\_number 'CA' will be the alpha-Carbon, but I am not sure how to identify the others. But once the separation is done, the side chain RMSD could be measure for example using `Bio.SVDSuperimposer.SVDSuperimposer` which works directly on the array of 3D coordinates of the atoms.
  
  Thanks!
  
  **Tags:** python, proteins, protein-structure
  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_1 on 2022-03-01. Score: 3 | Accepted answer
  
  As you suggest one way of solving your problem would be by selecting all atoms that don't have backbone atoms names. In a pdb file I believe backbone atoms would be named 'CA', 'HA', 'N', 'HN' or 'H', 'C' and 'O'. Beware of the N-terminal (where the hydrogens would be named either 'H1', 'H2' & 'H3'; or 'HN1', 'HN2' and 'HN3') and the C-terminal (the other oxygen would be named 'OXT').
  
  One way of doing it is by using the handy selections from pandas dataframes. It's probably a more elegant way than making a list of dataframes.
  
  ```py
  from biopandas.pdb import PandasPdb
  
  bpdf_1 = PandasPdb().fetch_pdb('1t48').df['ATOM']
  bpdf_2 = PandasPdb().fetch_pdb('1t49').df['ATOM']
  
  # Function returns a list of boolean. True when it's not a backbone atom.
  sel = lambda df: df['atom_name'].str.contains('[^(CA|HA|N|C|O|HN|H)]$')
  
  # The number of atom is not the same, so I only align the first 200
  sidechain_rmsd = PandasPdb.rmsd(bpdf_1[sel][:200], bpdf_2[sel][:200])
  
  ```
  
  The regex says something like "(not (CA or HA or …)) end of line". The end of line is important, otherwise any atom containing N, C, O or H in their name would be excluded (so most of them).
  
  Note that with this method it's still possible to use the PandasPdb selectors. For example, to only consider heavy atoms (no hydrogen):
  
  ```py
  sidechain_rmsd = PandasPdb.rmsd(bpdf_1[sel][:200],
                                  bpdf_2[sel][:200],
                                  s='heavy')
  
  ```
  
  **EDIT:**
  
  Another way to do it would be:
  
  ```py
  sidechain_rmsd = PandasPdb.rmsd(bpdf_1[:200],
                                  bpdf_2[:200],
                                  s='main chain',
                                  invert=True)
  
  ```
  
  You don't need any selection in this case, **BUT** this is a bad idea if you have hydrogens, as it will also align them (including the backbone ones).
  
  > **Comments:**
  > **username_1**: If you want to align each residue one by one instead: I'm sure this gives you the tools to do it, though it would be a pretty bad idea. In this very case I'd advise to try comparing side-chains using dihedral angles (hence rotamers). You can have a look at pyrosetta for this.  
  > **username_0**: Thanks for your detailed response! To check that I understood right: the H[0-9]* and HN[0-9]* are the names of the hydrogen atoms in the amino group? So I need to filter them out.  
  > **username_1**: Yes, although you can get away by just filtering out H[1-3] and HN[1-3]. More hydrogen atoms would be disturbing.  
  > **username_1**: My bad: H[1-3]? and HN[1-3]?, otherwise you don't cover cases where there is only H or only HN. Remember to keep the $ at the end, otherwise you'd end up matching all H.  
  > **username_0**: Thanks for your help!  
  
  ---
  
  