21

Many biochemical molecules, such as nucleic acids for example, are composed by nature in a hierarchical fashion from a limited number of building blocks. It would be nice to replicate this approach when typesetting these molecules. In the case of DNA and RNA, a natural approach would be:

  1. Define separate structures for ribose, phosphate and the bases (A,C,G,T,U)
  2. Derive deoxyribose from ribose
  3. Create nucleosides by combining ribose or deoxyribose with each of the bases
  4. Write DNA and RNA molecules as alternations of nucleosides and phosphate.

The chemfig package provides a \definesubmol command that allows for the definition of sub-molecules, which can then be substituted into other molecules. However, the package does not provide a built-in mechanism for making the results of such substitutions available as new sub-molecules. So, the question is how to define a command with the following behavior:

% "\derivesubmol" defines the new #1 submol, obtained by replacing all the
%  occurrences of "#3" by "#4" in the code of #2 submol

% arguments: #1 = new submol name, #2 = old submol name,
%            #3 = old substring, #4 = new substring
\newcommand*\derivesubmol[4]{% ...

This description is taken from the code that the package author of chemfig has provided to me by email. An example of his code in action is provided in the answer that I supply below.

To indicate that this question is, indeed, a question, let me add: ???

6
  • 3
    Why have you re-worded the entire question to no longer ask anything. Coming to it now I can't understand the answers here because I don't know what the question was. Please revert it to the most relevant version so future generation can benefit form your question, and you may be heaped up with upvotes. Jan 13, 2012 at 21:13
  • The question has been reworded because 1. the original version was unclear, and 2. it has been answered by the package author in private, and he has indicated to me that he did not intend to post his answer himself. It was precisely with the intention to "benefit future generations" that I updated the question to include the answer that the package author kindly provided to me; if this approach cost me your upvote, that is really too, too bad. Jan 13, 2012 at 21:25
  • That's not really how Stack Exchange is meant to work. The best solution is to roll back this question and submit your own answer echoing what the package author said. I don't know if you used Marc van Dongen's answer or not, and anyway your question is no longer a question. Jan 13, 2012 at 21:56
  • 6
    @MichaelPalmer The best way to provide this kind of information in a Q&A format is to post an answer, not edit the answer into the question. There is nothing wrong with a self-answer, which you can then accept after a suitable delay. However, a 'question' which is a guide is not really what is intended here.
    – Joseph Wright
    Jan 13, 2012 at 22:16
  • Don't see what difference it makes but it if makes anyone happy ... Jan 13, 2012 at 22:29

3 Answers 3

21

This answer was provided to me by Christian Tellechea in private correspondence; I post it here for the benefit of other people who may be interested.

\documentclass{minimal}
\usepackage{chemfig,xstring}
\makeatletter

% "\derivesubmol" defines the new #1 submol, obtained by replacing all the
%  occurrences of "#3" by "#4" in the code of #2 submol

% arguments: #1 = new submol name, #2 = old submol name,
%            #3 = old substring, #4 = new substring
\newcommand*\derivesubmol[4]{%
    \saveexpandmode\saveexploremode\expandarg\exploregroups
    \csname @\ifcat\relax\noexpand#2first\else second\fi oftwo\endcsname
        {\expandafter\StrSubstitute\@car#2\@nil}
        {\expandafter\StrSubstitute\csname CF@@#2\endcsname}
    {\@empty#3}{\@empty#4}[\temp@]%
    \csname @\ifcat\relax\noexpand#1first\else second\fi oftwo\endcsname
        {\expandafter\let\@car#1\@nil}
        {\expandafter\let\csname CF@@#1\endcsname}\temp@
    \restoreexpandmode\restoreexploremode
}
\makeatother

\setatomsep{2.5em}
\setcrambond{2pt}{}{}

\definesubmol{rt1}{-[2]rt1}
\definesubmol{rt2}{-[6,.6]rt2}

\definesubmol{ribose}{%
    -[:-90,2]%
        (%
            -[:25,1.176]O%
            -[:-25,1.176]%
        )%
    <[:-45,0.8]%
        (%
          -[0,,,,line width=2pt,shorten <=-.5pt,shorten >=-.5pt]%
              (!{rt2})%
          >[:45,0.8]%
              (!{rt1})%
         )%
}

\definesubmol{phosphate}{-[6,.6]O-[6,1.5]P(-[4,.8]HO)(=[6,0.8]O)-[,1.5]O}

\definesubmol{adenine}{N*5([::-18]-*6(-N=-N=(-NH_2)-)=-N=-)}

\definesubmol{uracil}{N*6(-(=O)-NH-(=O)-=-)}

\def\drawhline{\medbreak\hrulefill\medbreak}
\begin{document}

\chemfig{!{ribose}} \quad\quad The ribose template

\drawhline%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\derivesubmol{deoxyribose}{ribose}{(!{rt2})}{}% replace "(!{rt2})" by nothing
\chemfig{!{deoxyribose}} \quad\quad In deoxyribose, substituent rt2 is replaced by nothing

\drawhline

\derivesubmol{deoxyadenosine}{deoxyribose}{!{rt1}}{-[2,0.8]!{adenine}}
\chemfig{!{deoxyadenosine}} \quad\quad \parbox{4in}{Deoxyadenosine is derived from deoxyribose by substituting rt1 with adenine}

\drawhline%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% other method: locally redefine "rt1" submol and display "deoxyribose"
\begingroup
    \derivesubmol{rt1}{rt1}{rt1}{!{adenine}}
    \chemfig{!{deoxyribose}}
\endgroup
%
\quad\quad \parbox{4in}{Local redefinition of the rt 1 substituent in deoxyribose works, too}


\drawhline%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\derivesubmol{deoxyuridine}{deoxyribose}{!{rt1}}{-[2]!{uracil}}
\chemfig{
         !{deoxyuridine}
         !{phosphate}
         !{deoxyadenosine}
         !{phosphate}
         !{deoxyuridine}
        }
%
\quad\quad \parbox{2.5in}{Using the previously derived dU and dA templates, we can now easily write a DNA molecule}
\end{document}

The figure shows the result of the last \chemfig command:

enter image description here

Needless to say that I'm extremely happy with this solution. In case someone isn't, the chemfig package allows them to tweak all aspects of the structures with little effort. I recommend it highly.

8
  • This is awesome. It significantly shortens the typing and the time for creating complex molecules. I will borrow the \derivesubmol command for my costum chemistry preamble. Did Christian say anything about adding this command to chemfig? I think it would be a great feature.
    – cgnieder
    Jan 14, 2012 at 12:52
  • I agree that it would be very useful to include this macro in chemfig, but Christian did not mention whether or not he intended to do so. Jan 14, 2012 at 13:29
  • 1
    This "feature" is a simple use of \StrSubstitute from the xstring package (replace all occurences of a string by an other string). xstring is not loaded by chemfig and must not because, for a reason I don't understand, xstring is not compatible with conTeXt and chemfig is. Therefore, I can't add this macro to chemfig. Even without this compatiblility issue, I would not have added it! Indeed, for special use, isn't it the user's job to create his own macros with the help of other packages?
    – unbonpetit
    Jan 14, 2012 at 15:49
  • 1
    @unbonpetit I agree that creating macros for special use is something that normally the user does. However, I am not quite sure that most users would have been able to create this specific macro. But as I said before: I'll borrow the code for my custom chemistry preamble, so I don't mind too much :)
    – cgnieder
    Jan 14, 2012 at 18:52
  • Christian, thanks for the explanation. However, let me add, from my perspective as a Latex pedestrian, I could not solve this problem myself, and Jan 14, 2012 at 18:53
3

It's not entirely clear what you mean, but the following seems a bit easier to use. Please note that I'm not a chemist and it's ages ago since I studied chemistry (at secondary school level).

\documentclass{minimal}
\usepackage{chemfig}   

\setatomsep{2.0em}
\setcrambond{2.0pt}{}{}
\setbondoffset{0.5pt}  

\definesubmol{OH}[HO]{OH} % let OH groups figure out which way to point

\definesubmol{phosphonate}{%
                 P          
     (=[::90,0.7]O)         
    (-[::-90,0.7]!{OH})     
       -[::0,0.7]!{OH}      
}                           

\definesubmol{sub1}{A}
\definesubmol{sub6}{B}

\definesubmol{fructose}{
      {}?[a]            
         (-[:90,0.6]    
          -[:30,0.7]O   
          -[:0,0.7]!{sub1}
         )
      <[:225,0.8]
         (-[:-90,0.6]OH)
         (-[:180,0.5,,,draw=none]          % note the devlishly clever trick
          -[:90,1.26,,,draw=none]O?[a]?[b] % to position the oxigen in the ring
         )
      -[:180,1,,,line width=2pt]
         (-[:90,0.6]OH)
      >[:135,0.8]?[b]
      -[:90,0.6]
      -[:150,0.7]O
      -[:180,0.7]!{sub6}
}

\begin{document}

\tikzset{sub1/.code=\redefinesubmol{sub1}{#1},
         sub6/.code=\redefinesubmol{sub6}{#1}}

\begin{tikzpicture}[x=0.8in,y=0.8in]
    \node[anchor=south west] at (0,2) {\chemfig{!{fructose}}};
    \begin{scope}[sub1=H,sub6=H]
        \node[anchor=south west,sub1=H,sub6=H] at (2.5,2) {\chemfig{!{fructose}}};
    \end{scope}
    \begin{scope}[sub1=!{phosphonate},sub6=H]
        \node[anchor=south west] at (5,2) {\chemfig{!{fructose}}};
    \end{scope}
    \begin{scope}[sub1=H,sub6=!{phosphonate}]
        \node[anchor=south west] at (0,0) {\chemfig{!{fructose}}};
    \end{scope}
    \begin{scope}[sub1=!{phosphonate},sub6=!{phosphonate}]
        \node[anchor=south west] at (2.5,0) {\chemfig{!{fructose}}};
    \end{scope}
\end{tikzpicture}

\end{document}

Of course you can also use the options sub1 and sub6 in the node options.

Perhaps you could explain again what you want? (Sorry about the ignorance.)

2
  • This is a very nice simplification of the code I got to work, but not quite what I intend to do as the next step. I will edit the question for clarity. Jan 12, 2012 at 15:28
  • This answer relates to a previous version of my question, which was lacking in clarity and which I have since deleted. If this answer falls short, it is only because my original question was poorly posed. Jan 13, 2012 at 20:51
3

I wrote a short application of the answer provided by Christian Tellechea via @MichaelPalmer above, adding all nucleosides and making a doublestranded picture. The full code can be found here.

    \documentclass[11pt]{standalone}
\usepackage{chemfig,xstring}    %Draw molecules with easy syntax
\usepackage{times}
\frenchspacing
\makeatletter


% "\derivesubmol" defines the new #1 submol, obtained by replacing all the
%  occurrences of "#3" by "#4" in the code of #2 submol

% arguments: #1 = new submol name, #2 = old submol name,
%            #3 = old substring, #4 = new substring
\newcommand*\derivesubmol[4]{%
    \saveexpandmode\saveexploremode\expandarg\exploregroups
    \csname @\ifcat\relax\noexpand#2first\else second\fi oftwo\endcsname
        {\expandafter\StrSubstitute\@car#2\@nil}
        {\expandafter\StrSubstitute\csname CF@@#2\endcsname}
    {\@empty#3}{\@empty#4}[\temp@]%
    \csname @\ifcat\relax\noexpand#1first\else second\fi oftwo\endcsname
        {\expandafter\let\@car#1\@nil}
        {\expandafter\let\csname CF@@#1\endcsname}\temp@
    \restoreexpandmode\restoreexploremode
}
\makeatother

\setatomsep{2.5em}
\setcrambond{2pt}{}{}

\definesubmol{rt1}{-[2]rt1}
\definesubmol{rt2}{-[6,.6]rt2}

\definesubmol{ribose}{%
    -[::-90,2]%
        (%
            -[::115,1.176]O%
            -[::-50,1.176]%
        )%
    <[::45,0.8]%
        (%
          -[::45,,,,line width=2pt,shorten <=-.5pt,shorten >=-.5pt]%
              (!{rt2})%
          >[::45,0.8]%
              (!{rt1})%
         )%
}

\definesubmol{phosphate}{-[::-45,.6]O-[::0,1.5]P(-[::-90,1]O{^-})(=[::0,0.8]O)-[::90,1.5]O}

\definesubmol{adenine}{N*5([::-18]-*6(-N=-N(<:[::-83,1.6,,,red])=(-N(-[::66]H)-[::-66]H<:[::-18,1.5,,,red])-)=-N=-)}
\definesubmol{adenineR}{N*5([::-18]-=N-*6(-(-N(-[::66]H<:[::-25,1.5,,,red])-[::-66]H)=N(<:[::-76,1.5,,,red])-=N-)=-)}

\definesubmol{guanine}{N*5([::-18]-*6(-N=(-N(-[::66]H<:[::-25,1.6,,,red])-[::-66]H)-N(-H<:[::-17,1.7,,,red])-(=O<:[::-75,1.7,,,red])-)=-N=-)}
\definesubmol{guanineR}{N*5([::-18]-=N-*6(-(=O<:[::45,1.5,,,red])-N(-H<:[::-16,1.5,,,red])-(-N(-[::66]H)-[::-66]H<:[::-9,1.5,,,red])=N-)=-)}

\definesubmol{uracil}{N*6(-(=O)-N(-H)-(=O)-=-)}

\definesubmol{cytosine}{N*6(-(=O<:[::50,1.7,,,red])-N(<:[::-73,1.6,,,red])=(-N(-[::66]H)-[::-66]H<:[::-3,1.5,,,red])-=-)}
\definesubmol{cytosineR}{N*6(-=-(-N(-[::66]H<:[::-19,1.7,,,red])-[::-66]H)=N(<:[::-72,1.6,,,red])-(=O<:[::-75,1.6,,,red])-)}

\definesubmol{thymine}{N*6(-(=O)-N(-H<:[::-10,1.6,,,red])-(=O<:[::-75,1.5,,,red])-(-H_3C)=-)}
\definesubmol{thymineR}{N*6(-=(-H_3C)-(=O<:[::32,1.6,,,red])-N(-H<:[::-33,1.7,,,red])-(=O)-)}



\def\drawhline{\medbreak\hrulefill\medbreak}
\begin{document}

\derivesubmol{deoxyribose}{ribose}{(!{rt2})}{}% replace "(!{rt2})" by nothing
\derivesubmol{deoxyadenosine}{deoxyribose}{!{rt1}}{-[::65,0.8]!{adenine}}
\derivesubmol{deoxyguanosine}{deoxyribose}{!{rt1}}{-[::65,0.8]!{guanine}}
\derivesubmol{deoxyuridine}{deoxyribose}{!{rt1}}{-[::45,0.8]!{uracil}}
\derivesubmol{deoxycytidine}{deoxyribose}{!{rt1}}{-[::45,0.8]!{cytosine}}
\derivesubmol{thymidine}{deoxyribose}{!{rt1}}{-[::45,0.8]!{thymine}}

\derivesubmol{deoxyadenosineR}{deoxyribose}{!{rt1}}{-[::-35,0.8]!{adenineR}}
\derivesubmol{deoxyguanosineR}{deoxyribose}{!{rt1}}{-[::-35,0.8]!{guanineR}}
\derivesubmol{deoxycytidineR}{deoxyribose}{!{rt1}}{-[::-60,0.8]!{cytosineR}}
\derivesubmol{thymidineR}{deoxyribose}{!{rt1}}{-[::-50,0.8]!{thymineR}}

\begin{tikzpicture}
\scriptsize
\node at (1,3) {\chemfig{ [:-65]
         !{phosphate}!{deoxyadenosine}!{phosphate}!{deoxyguanosine}!{phosphate}!{thymidine}!{phosphate}!{deoxycytidine}}};
\node at (6.4,2.5) {\chemfig{ [:115]
         !{phosphate}!{deoxyguanosineR}!{phosphate}!{deoxyadenosineR}!{phosphate}!{deoxycytidineR}!{phosphate}!{thymidineR}}};   

\end{tikzpicture} 

\end{document}
2
  • 1
    Hello! It indeed looks nice, but I don't think it is suitable as an answer to the question. It doesn't really answer the question, rather it builds upon one of the other answers.
    – yo'
    May 14, 2015 at 10:28
  • I included the code in full for future reference. May 14, 2015 at 10:51

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .