
Estou escrevendo um relatório que inclui imagens de enzimas como esta:
Gostaria \caption
de incluir um guia de cores para que os principais componentes/átomos possam ser descritos em cores (este relatório não está sendo publicado, portanto, com relação ao daltonismo, isso não é um problema). Atualmente estou usando um comando como este:
\newcommand\ColourGuide{%
Colour code: \textcolor{violet}{metal ion}, \textcolor{Green3}{residue}, \textcolor{teal}{ligand}, \textcolor{Yellow3}{substrate}, \textcolor{DarkOrange1}{phosphorus}, \textcolor{red}{oxygen} and \textcolor{RoyalBlue4}{nitrogen}%
}
No entanto, em algumas imagens nem todos os componentes coloridos estão presentes, por isso não seria bom incluir códigos de cores redundantes. Como posso criar uma frase com base na entrada? Por exemplo:
\ColourGuide{M}{R}{S}{O}{N}
produziria:
Código de cores: íon metálico, resíduo, substrato, oxigênio e nitrogênio.
nas cores especificadas. Estou usando lualatex
e olhei usando lua
(o que seria legal), mas não sei como interagir os dois de maneira adequada (nem eficiente), como os argumentos poderiam ser extraídos, por exemplo, como em Python com input[0]
? Eu apreciaria qualquer conselho ou solução através de qualquer método, mas lua
seria bom para que eu pudesse começar a aprendê-lo e aplicá-lo a outros comandos que uso lualatex
com frequência.
MWE:
\documentclass{book}
\usepackage[x11names]{xcolor}
\newcommand\ColourGuide{%
Colour code: \textcolor{violet}{metal ion}, \textcolor{Green3}{residue}, \textcolor{teal}{ligand}, \textcolor{Yellow3}{substrate}, \textcolor{DarkOrange1}{phosphorus}, \textcolor{red}{oxygen} and \textcolor{RoyalBlue4}{nitrogen}%
}
\begin{document}
\ColourGuide{}
\end{document}
Como parece:
(Não tenho certeza de quais tags colocar nisso)
Responder1
Boa tentativa na sua resposta, mas…
\documentclass{book}
\usepackage[x11names]{xcolor}
\ExplSyntaxOn
\NewDocumentCommand{\ColourGuide}{m}
{
Color~code:~\jamest_colourguide:n { #1 }
}
\seq_new:N \l__jamest_colourguide_seq
\cs_new_protected:Nn \jamest_colourguide:n
{
\seq_clear:N \l__jamest_colourguide_seq
\tl_map_function:nN { #1 } \__jamest_colourguide_add:n
\seq_use:Nnnn \l__jamest_colourguide_seq { ~and~ } { ,~ } { ~and~}
}
\cs_new_protected:Nn \__jamest_colourguide_add:n
{
\seq_put_right:Nx \l__jamest_colourguide_seq
{
\str_case:nn { #1 }
{
{a}{\textcolor{red}{oxygen},~\textcolor{DarkOrange1}{phosphorus},~
\textcolor{Yellow3}{substrate},~\textcolor{Green3}{residue},~
\textcolor{RoyalBlue4}{nitrogen},~\textcolor{teal}{ligand}~
and~\textcolor{violet}{metal~ion}.}
{M}{\textcolor{violet}{metal~ion}}
{R}{\textcolor{Green3}{residue}}
{S}{\textcolor{Yellow3}{substrate}}
{O}{\textcolor{red}{oxygen}}
{N}{\textcolor{RoyalBlue4}{nitrogen}}
{L}{\textcolor{teal}{ligand}}
{P}{\textcolor{DarkOrange1}{phosphorus}}
}
}
}
\ExplSyntaxOff
\begin{document}
\noindent\ColourGuide{MRSON}
\noindent\ColourGuide{LPON}
\noindent\ColourGuide{a}
\end{document}
Nenhuma contagem é necessária: o argumento é mapeado caractere por caractere e o código relevante é adicionado à sequência que pode ser usada posteriormente com os separadores adequados.
Talvez seja melhor, para evitar duplicação de código, deixar o argumento vazio se quiser a lista completa.
\documentclass{book}
\usepackage[x11names]{xcolor}
\ExplSyntaxOn
\NewDocumentCommand{\ColourGuide}{m}
{
Color~code:~
\jamest_colourguide:n { #1 }
}
\seq_new:N \l__jamest_colourguide_seq
\cs_new_protected:Nn \jamest_colourguide:n
{
\tl_if_empty:nTF { #1 }
{
\jamest_colourguide:n { OPSRNLM }
}
{
\seq_clear:N \l__jamest_colourguide_seq
\tl_map_function:nN { #1 } \__jamest_colourguide_add:n
\seq_use:Nnnn \l__jamest_colourguide_seq { ~and~ } { ,~ } { ~and~}
}
}
\cs_new_protected:Nn \__jamest_colourguide_add:n
{
\seq_put_right:Nx \l__jamest_colourguide_seq
{
\str_case:nn { #1 }
{
{M}{\textcolor{violet}{metal~ion}}
{R}{\textcolor{Green3}{residue}}
{S}{\textcolor{Yellow3}{substrate}}
{O}{\textcolor{red}{oxygen}}
{N}{\textcolor{RoyalBlue4}{nitrogen}}
{L}{\textcolor{teal}{ligand}}
{P}{\textcolor{DarkOrange1}{phosphorus}}
}
}
}
\ExplSyntaxOff
\begin{document}
\noindent\ColourGuide{MRSON}
\noindent\ColourGuide{LPON}
\noindent\ColourGuide{}
\end{document}
A saída é a mesma.
Responder2
Graças aos comentários, consegui montar uma solução que não é bonita, mas funciona conforme necessário. Adicionando uma resposta de @egreg acomo determinar o número de caracteres no argumento de um comandoe a resposta vinculada @John Kormylocomentoudá isso:
\documentclass{book}
\usepackage[x11names]{xcolor}
\usepackage{xstring}
\usepackage{xparse} % loads expl3
\ExplSyntaxOn
\newcounter{Chars}
\newcounter{CharsConstant}
\def\CharsCount#1{%
\setcounter{Chars}{\tl_count:n { #1 }}%
\setcounter{CharsConstant}{\tl_count:n { #1 }}%
}
\NewDocumentCommand{\punctOrAnd}{mm}
{
\int_compare:nTF { #1 > 1 }
{
\int_compare:nTF { #1 = \value{CharsConstant} }
{
#2
}
{
,~#2
}
}
{
\space and~#2.
}
}
\def\ColourGuide#1{\CharsCount{#1}Colour~code:~\scanA#1\end}
\def\scanA#1{%
\ifx\end#1\else
\IfStrEq{#1}{a}{\textcolor{red}{oxygen},~\textcolor{DarkOrange1}{phosphorus},~\textcolor{Yellow3}{substrate},~\textcolor{Green3}{residue},~\textcolor{RoyalBlue4}{nitrogen},~\textcolor{teal}{ligand}~and~\textcolor{violet}{metal~ion}.}{}%
%
\IfStrEq{#1}{M}{\punctOrAnd{\value{Chars}}{\textcolor{violet}{metal~ion}}}{}%
\IfStrEq{#1}{R}{\punctOrAnd{\value{Chars}}{\textcolor{Green3}{residue}}}{}%
\IfStrEq{#1}{S}{\punctOrAnd{\value{Chars}}{\textcolor{Yellow3}{substrate}}}{}%
\IfStrEq{#1}{O}{\punctOrAnd{\value{Chars}}{\textcolor{red}{oxygen}}}{}%
\IfStrEq{#1}{N}{\punctOrAnd{\value{Chars}}{\textcolor{RoyalBlue4}{nitrogen}}}{}%
\IfStrEq{#1}{L}{\punctOrAnd{\value{Chars}}{\textcolor{teal}{ligand}}}{}%
\IfStrEq{#1}{P}{\punctOrAnd{\value{Chars}}{\textcolor{DarkOrange1}{phosphorus}}}{}%
%
\addtocounter{Chars}{-1}%
\expandafter \scanA \fi
}
\ExplSyntaxOff
\begin{document}
\noindent\ColourGuide{MRSON}
\noindent\ColourGuide{LPON}
\noindent\ColourGuide{a}
\end{document}
Responder3
Isso usa um ponto e vírgula como terminador. \def\CGparse#1#2;
colocará o primeiro token (letra) #1
e tudo antes do ponto e vírgula em #2
. Ele se autodenomina recursivamente até #2
is \empty
.
\documentclass{book}
\usepackage[x11names]{xcolor}
\newcommand\ColourGuide[1]{Colour code:{\count1=0\relax\CGparse#1;}}
\def\CGparse#1#2;{\def\A{#1}%
\def\B{#2}%
\ifnum\count1=0\relax
\space
\else
\ifx\B\empty\relax
{ and }%
\else
{, }%
\fi
\fi
\advance\count1 by 1
\def\C{M}\ifx\A\C\relax\textcolor{violet}{metal ion}\fi
\def\C{R}\ifx\A\C\relax\textcolor{Green3}{residue}\fi
\def\C{L}\ifx\A\C\relax\textcolor{teal}{ligand}\fi
\def\C{S}\ifx\A\C\relax\textcolor{Yellow3}{substrate}\fi
\def\C{P}\ifx\A\C\relax\textcolor{DarkOrange1}{phosphorus}\fi
\def\C{O}\ifx\A\C\relax\textcolor{red}{oxygen}\fi
\def\C{N}\ifx\A\C\relax\textcolor{RoyalBlue4}{nitrogen}\fi
\ifx\B\empty\relax
{. }%
\else
\CGparse#2;
\fi}
\begin{document}
\ColourGuide{MRSON}
\end{document}
Responder4
Já existem muitas respostas boas e provavelmente o meu uso pgfkeys
é muito complicado e complicado, mas foi isso que eu descobri.
- Não há necessidade
lualatex
(que foi solicitado explicitamente aqui, mas talvez alguém possa usar isso em outro lugar). - Os átomos sempre serão listados na mesma ordem, não importa se você escreve
\ColourGuide[ligand,residue]
ou\ColourGuide[residue,ligand]
. Isso pode ser desejado ou não, mas acho que é um bom estilo manter a mesma ordem.
É claro que os argumentos/chaves opcionais poderiam ser reduzidos para, por exemplo, \ColourGuide[L,R]
quase sem esforço.
\documentclass{article}
% create 'if's for each atom
\newif\ifmetalion
\newif\ifresidue
\newif\ifligand
\newif\ifsubstrate
\newif\ifphosphorus
\newif\ifoxygen
\newif\ifnitrogen
% create two counters
\newcounter{numtrue} % total number of 'if's which are true
\newcounter{currval} % counter (for correctly putting 'and' at the last atom)
% colors
\usepackage[x11names]{xcolor}
% create pgfkeys
\usepackage{pgfkeys,xcolor}
\pgfkeys{
/colourguide/.is family, /colourguide/.cd,
default/.style={
metalion=false,
residue=false,
ligand=false,
substrate=false,
phosphorus=false,
oxygen=false,
nitrogen=false,
},
metalion/.is if=metalion,
residue/.is if=residue,
ligand/.is if=ligand,
substrate/.is if=substrate,
phosphorus/.is if=phosphorus,
oxygen/.is if=oxygen,
nitrogen/.is if=nitrogen
}
% this will produce the adequate delimiter between different atoms
\def\chooseDelimiter{%
\stepcounter{currval}% increment counter
\ifnum\value{currval}<\value{numtrue}\relax% if more than one atom remains ...
,\ % ... put ',' ...
\else%
\ifnum\value{currval}=\value{numtrue}\relax% ... if only one atom remains ...
\ and\ % ... put 'and' ...
\else% ... if no atom remains ...
.% ... put '.'
\fi%
\fi%
}
% main command: \ColorGuide
\newcommand\ColourGuide[1][]{%
% do pgfkeys magic
\pgfkeys{/colourguide, default, #1}%
% get number of requested atoms
\setcounter{currval}{1}%
\setcounter{numtrue}{0}%
\ifmetalion \stepcounter{numtrue}\fi%
\ifresidue \stepcounter{numtrue}\fi%
\ifligand \stepcounter{numtrue}\fi%
\ifsubstrate \stepcounter{numtrue}\fi%
\ifphosphorus\stepcounter{numtrue}\fi%
\ifoxygen \stepcounter{numtrue}\fi%
\ifnitrogen \stepcounter{numtrue}\fi%
% build sentence
Colour code:\ %
\ifmetalion\textcolor{violet}{metal ion}\chooseDelimiter\fi%
\ifresidue\textcolor{Green3}{residue}\chooseDelimiter\fi%
\ifligand\textcolor{teal}{ligand}\chooseDelimiter\fi%
\ifsubstrate\textcolor{Yellow3}{substrate}\chooseDelimiter\fi%
\ifphosphorus\textcolor{DarkOrange1}{phosphorus}\chooseDelimiter\fi%
\ifoxygen\textcolor{red}{oxygen}\chooseDelimiter\fi%
\ifnitrogen\textcolor{RoyalBlue4}{nitrogen}\chooseDelimiter\fi%
}
\begin{document}
\paragraph{Works with one atom:}
\ColourGuide[metalion]
\paragraph{Works with two atoms:}
\noindent\ColourGuide[residue,ligand]\\ % two atoms
\paragraph{Works with many atoms:}
\ColourGuide[metalion,residue,ligand,substrate,phosphorus,oxygen,nitrogen]\\ % many atoms
\paragraph{Keeps the given order, no matter what is the order in brackets:}
\ColourGuide[ligand, residue]
\end{document}