![Chemfig 亚分子接受一个参数](https://linux22.com/image/346003/Chemfig%20%E4%BA%9A%E5%88%86%E5%AD%90%E6%8E%A5%E5%8F%97%E4%B8%80%E4%B8%AA%E5%8F%82%E6%95%B0.png)
我正在尝试重新创建一个具有许多分子的图形,它们中的大多数都像下面的结构:
只改变“X”和“Y”。因此,普通的子分子实际上没有帮助,因为我想改变 X 和 Y。然后我定义:
\newcommand*{\HOOC}[2]{HOOC-[1]-[2]-[1]*6(=-=(-#1)-(-#2)=-)}
效果很好如果的参数中只有“正常”文本\HOOC
。如果我使用,比如说
\chemfig*{!{\HOOC{OH}{OSO_3}}}
它给了我Missing $ inserted
。我该如何克服这个问题?如果有更正确或更聪明的方法,我愿意接受建议。
M(N)WE:
\documentclass{standalone}
\usepackage{chemfig,tikz}
\renewcommand*\printatom[1]{\ensuremath{\mathsf{#1}}}
\newcommand*{\HOOC}[2]{HOOC-[1]-[2]-[1]*6(=-=(-#1)-(-#2)=-)}
\setatomsep{2em}
\usetikzlibrary{positioning}
\begin{document}
\begin{tikzpicture}[label position={below}]
\node[label={Dihydrocaffeic acid-3-O-glucuronide}] (DA3OG) {\chemfig*{!{\HOOC{OH}{O-[:30](-[::25](-[:190]OH)-[:-15](-[:75]OH)-[:15]?-[:-15]OH)(-[::-15]O-[::-30]?-[0]COOH)}}}};
\node[label={Dihydroferulic acid-4-O-sulfate}, below left=-1.5cm and 3cm of DA3OG] {5
\chemfig*{%
!{\HOOC{OCH_3}{OSO_3^{-}}}%
}%
};
\end{tikzpicture}
\end{document}
期望输出
以上内容是通过复制/粘贴M(N)WE的内容\HOOC
并用其对应的值替换#1
和而获得的。#2
答案1
这里涉及两个问题,第一是如何得到分子中可变的部分,第二是如何在分子中使用公式tikzpicture
。
据我所知,分子中存在变量有两种可能性。
定义亚分子。
\definesubmol{X}{OCH_3} \definesubmol{Y}{OSO_3^{-}} \newcommand*\HOOC{HOOC-[1]-[2]-[1]*6(=-=(-!{X})-(-!{Y})=-)} \chemfig*{!\HOOC}
您可以使用
\redefinesubmol{X}{...}
将名称设置为新的子分子,这样\chemfig*{!\HOOC}
将产生不同的分子。定义
\HOOC
命令包括\chemfig
。\newcommand*{\cfHOOC}[2]{\chemfig*{HOOC-[1]-[2]-[1]*6(=-=(-#1)-(-#2)=-)}} \cfHOOC{OCH_3}{OSO_3^{-}}
似乎不可能有宏带有参数后!
。
第二个问题与以下事实有关:\chemfig
s 是 tikz 图片,并且 tikz 图片的嵌套可能不起作用。一种解决方案是将 tikz 图片外部的公式排版到一个框中,并在 tikz 图片内部使用此框。
\newsavebox\formulaA
\savebox\formulaA{\cfHOOC{OH}{O-[:30](-[::25](-[:190]OH)-[:-15](-[:75]OH)-[:15]?-[:-15]OH)(-[::-15]O-[::-30]?-[0]COOH)}}
\newsavebox\formulaB
\savebox\formulaB{\cfHOOC{OCH_3}{OSO_3^{-}}}
\begin{tikzpicture}
... \usebox\formulaA ... \usebox\formulaB ...
\end{tikzpicture}
这是文档和相应的代码。
\documentclass[border=1mm]{standalone}
\usepackage{chemfig}
\renewcommand*\printatom[1]{\ensuremath{\mathsf{#1}}}
\setatomsep{2em}
\usetikzlibrary{positioning}
\begin{document}
\newcommand*{\cfHOOC}[2]{\chemfig*{HOOC-[1]-[2]-[1]*6(=-=(-#1)-(-#2)=-)}}
\newsavebox\formulaA
\savebox\formulaA{\cfHOOC{OH}{O-[:30](-[::25](-[:190]OH)-[:-15](-[:75]OH)-[:15]?-[:-15]OH)(-[::-15]O-[::-30]?-[0]COOH)}}
\newsavebox\formulaB
\savebox\formulaB{\cfHOOC{OCH_3}{OSO_3^{-}}}
\begin{tikzpicture}[label position={below}]
\node[label={Dihydrocaffeic acid-3-O-glucuronide}] (DA3OG) {\usebox\formulaA};
\node[label={Dihydroferulic acid-4-O-sulfate}, below left=-1.5cm and 3cm of DA3OG] {5\usebox\formulaB};
\end{tikzpicture}
\end{document}
编辑:看起来,这些特定的\chemfig
s 在直接在 tikz-picture 中使用时也可以工作。请记住,遇到错误时,这可能是由于嵌套的 tikz-pictures 造成的。
答案2
我曾向 chemfig 软件包的作者 Christian Tellechea 提出过类似的问题,他很好心地为我提供了一些自定义代码来解决它。我将这段代码粘贴在下面的示例中。希望您不介意我使用我自己的一些示例分子,而不是您的分子。
\documentclass{article}
\usepackage{chemfig,xstring}
\makeatletter
% he sent me this later ... it seems this is simply a slight refactoring.
\newcommand*\if@csfirst[1]{%
\csname @\ifcat\relax\expandafter\noexpand\@car#1\@nil first\else second\fi oftwo\endcsname
}
\newcommand*\derivesubmol[4]{%
\saveexpandmode\saveexploremode\expandarg\exploregroups
\if@csfirst{#2}
{\expandafter\StrSubstitute\@car#2\@nil}
{\expandafter\StrSubstitute\csname CF@@#2\endcsname}
{\@empty#3}{\@empty#4}[\temp@]%
\if@csfirst{#1}
{\expandafter\let\@car#1\@nil}
{\expandafter\let\csname CF@@#1\endcsname}\temp@
\restoreexpandmode\restoreexploremode
}
\newcommand*\showsubmol[1]{%
\if@csfirst{#1}%
{\begingroup submol "\expandafter\showsubmol@i\string#1" = \ttfamily
\expandafter\expandafter\expandafter\def\expandafter\expandafter\expandafter#1%
\expandafter\expandafter\expandafter{\expandafter\@gobble#1}%
\expandafter\expandafter\expandafter\strip@prefix\expandafter\meaning\@car#1\@nil
\endgroup}%
{\expandafter\showsubmol\csname CF@@#1\endcsname}%
}
\def\showsubmol@i#1#2#3#4#5{}
\newcommand*\exp@addtomacro[2]{\expandafter\@xs@addtomacro\expandafter#1\expandafter{#2}}
\newcommand*\expandsubmol[1]{%
\if@csfirst{#1}%
{\saveexpandmode\saveexploremode\expandarg\noexploregroups
\let\parsed@mol\@empty\let\remain@mol#1%
\IfSubStr#1!%
{\expandsubmol@i
\let#1\parsed@mol
}%
\relax
}%
{\expandafter\expandsubmol\csname CF@@#1\endcsname}%
}
\newcommand*\expandsubmol@i{%
\StrBefore\remain@mol![\temp@]%
\exp@addtomacro\parsed@mol\temp@
\StrBehind\remain@mol![\remain@mol]%
\StrSplit\remain@mol\@ne\remain@mol\temp@
\StrRemoveBraces\remain@mol[\remain@mol]%
\expandafter\if@csfirst\expandafter{\remain@mol}%
{\expandafter\let\expandafter\remain@mol\remain@mol}%
{\expandafter\let\expandafter\remain@mol\csname CF@@\remain@mol\endcsname}%
\StrGobbleLeft\remain@mol\@ne[\remain@mol]%
\exp@addtomacro\remain@mol\temp@
\IfSubStr\remain@mol!%
\expandsubmol@i
{\exp@addtomacro\parsed@mol\remain@mol
\restoreexpandmode\restoreexploremode
}%
}
\makeatother
% cosmetic enhancements for the example
\setcrambond{1.75pt}{0.4pt}{1.0pt} % previously too crammed for print.
\setatomsep{18pt}
\renewcommand*\printatom[1]{\ensuremath{\mathsf{#1}}}
\tikzset{ % bond in the foreground
fgbond/.style={% foreground bond - connecting two cram bonds.
line width=1.6pt,
shorten <=-.6pt,
shorten >=-.6pt
}
}
% define named substituent dummies. Not strictly necessary, but useful for
% visual display of the template that contains them.
\definesubmol{rt1}{-[:90]rt1}
\definesubmol{rt2}{-[:-90,0.6]rt2}
% define a template that contains named dummy substituents that can be replaced
\definesubmol{ribosetemplate}{%
(
-[:28,1.508]O
-[:-28,1.508]
)
<[:-45]
(
-[0,1.25,,,fgbond]
(!{rt2})
>[:45]
(!{rt1})
)
}
% partially specialize the template by supplying a substituent for the ribose
\derivesubmol{ribonucleoside}{ribosetemplate}{!{rt2}}{-[6,0.9]OH}
\derivesubmol{deoxyribonucleoside}{ribosetemplate}{!{rt2}}{}
% define some more submols
\definesubmol{adenine}{N*5([::-18]-*6(-N=-N=(-NH_2)-)=-N=-)}
\redefinesubmol{guanine}{N*5([::-18]-*6(-N=(-NH_2)-NH-(=O)-)=-N=-)}
% put those into the second position
\derivesubmol{guanosine}{ribonucleoside}{!{rt1}}{-[2]!{guanine}}
\derivesubmol{deoxyadenosine}{deoxyribonucleoside}{!{rt1}}{-[2]!{adenine}}
\begin{document}
% display the template, so that we know what is where
\chemfig{entry-[6]!{ribosetemplate}-[6]exit}
\hspace{1in}
% put it all together
\chemfig{X-[6,2]!{guanosine}-[6,2]{stuff}-[6,2]!{deoxyadenosine}-[6,2]B}
\end{document}
这产生了
\makeatletter
和之间的代码\makeatother
由 Christian 编写,在我看来就像楔形文字一样清晰;不要问我。这取决于xstring
同样由 Christian 编写的包。但是,它很容易使用。其想法是定义一个带有字符串占位符的模板分子,然后可以使用宏将其替换为不同的替代物\derivesubmol
。我认为这个宏对(已经很棒的)包来说是一个有用的补充chemfig
。
答案3
按照@gernot 提出的方法(现在已知是手册的内容),但使用不带 es 的方法\savebox
- 这可能会暗示未来的问题,但到目前为止还没有遇到过 - 可以定义依赖于其他子分子的子分子(宏形式):
\definesubmol{hooc}{HOOC-[1]-[2]-[1]*6(=-=(-!{\X})-(-!{\Y})=-)}
然后我们发出命令来根据需要更新这些\X
宏\Y
:
\newcommand*{\radicals}[2]{\edef\X{#1}\edef\Y{#2}}
对独立子分子使用宏(而\edef
不是)的原因是,这样我们就可以定义几个其他子分子并使用它们,例如,这个例子很愚蠢,但在下面的 MWE 中有一个更有说服力:\def
\def\metil{CH_3}
\documentclass{standalone}
\usepackage{tikz,chemfig}
\renewcommand*\printatom[1]{\ensuremath{\mathsf{#1}}} % Uses sf font
\setatomsep{2em} % Sets atom separation
\usetikzlibrary{positioning}
\newcommand*{\radicals}[2]{\edef\X{#1}\edef\Y{#2}} % Macro that renews the radicals
\definesubmol{hooc}{HOOC-[1]-[2]-[1]*6(=-=(-!{\X})-(-!{\Y})=-)} % Dependent submol
\def\glucuronide{% Complex independent submol
O-[:30](-[::25](-[:190]OH)-[:-15](-[:75]OH)-[:15]?-[:-15]OH)(-[::-15]O-[::-30]?-[0]COOH)
}
\begin{document}
\begin{tikzpicture}[label position={below}]
\node[label={Dihydrocaffeic acid-3-O-glucuronide}] (DA3OG)
{\radicals{OH}{\glucuronide}\chemfig*{!{hooc}}};
\node[label={Dihydroferulic acid-4-O-sulfate}, below left=-1.5cm and 3cm of DA3OG]
{\radicals{OCH_3}{OSO_3^{-}}\chemfig*{!{hooc}}};
\end{tikzpicture}
\end{document}