
Estoy escribiendo un informe que incluye imágenes de enzimas como esta:
En el \caption
Me gustaría incluir una guía de colores para que los componentes/átomos clave se puedan describir en color (este informe no se publica, por lo que con respecto al daltonismo esto no es un problema). Actualmente estoy usando un 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}%
}
Sin embargo, en algunas imágenes no todos los componentes coloreados están presentes, por lo que no sería bueno incluir códigos de color redundantes. ¿Cómo puedo crear una oración basada en la entrada? Por ejemplo:
\ColourGuide{M}{R}{S}{O}{N}
produciría:
Código de colores: ion metálico, residuo, sustrato, oxígeno y nitrógeno.
en los colores especificados. Estoy usando lualatex
y miré el uso lua
(lo cual sería bueno) pero no sé cómo interactuar los dos correctamente (ni eficientemente), ¿cómo podrían extraerse los argumentos, por ejemplo, como en Python con input[0]
? Agradecería cualquier consejo o solución a través de cualquier método, pero lua
sería bueno poder comenzar a aprenderlo y aplicarlo a otros comandos que uso lualatex
con frecuencia.
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 luce:
(No estoy seguro de qué etiquetas ponerle a esto)
Respuesta1
Buen intento en tu respuesta, pero...
\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}
No es necesario contar: el argumento se asigna carácter por carácter y el código relevante se agrega a la secuencia que luego se puede usar con los separadores adecuados.
Quizás sea mejor, para evitar la duplicación de código, dejar el argumento vacío si desea la 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}
La salida es la misma.
Respuesta2
Gracias a los comentarios, pude encontrar una solución que no es bonita pero que funciona según lo requerido. Agregando una respuesta de @egreg acómo determinar el número de caracteres en el argumento de un comandoy la respuesta vinculada @John Kormylocomentóda esto:
\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}
Respuesta3
Esto utiliza un punto y coma como terminador. \def\CGparse#1#2;
Pondrá la primera ficha (letra) #1
y todo lo que esté antes del punto y coma #2
. Se llama a sí mismo de forma recursiva hasta que #2
sea \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}
Respuesta4
Ya hay muchas buenas respuestas, y probablemente mi uso pgfkeys
sea demasiado complicado y engorroso, pero esto es lo que se me ocurrió.
- No es necesario
lualatex
(lo cual se solicitó explícitamente aquí, pero tal vez alguien pueda usarlo en otro lugar). - Los átomos siempre aparecerán en el mismo orden, sin importar si escribes
\ColourGuide[ligand,residue]
o\ColourGuide[residue,ligand]
. Esto se puede querer o no, pero creo que es un buen estilo mantener el mismo orden.
Por supuesto, los argumentos/claves opcionales podrían acortarse a, por ejemplo, \ColourGuide[L,R]
casi sin esfuerzo.
\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}