如同这个问题,我想根据从表中读取的某一列的值来设置散点的样式(颜色/形状)。
\documentclass[tikz,border=3mm]{standalone}
\usepackage{pgfplots}
\pgfplotsset{width=7cm,compat=1.15}
\begin{document}
\begin{tikzpicture}
\begin{axis}[
scatter, only marks,
scatter src=explicit symbolic,
z buffer=sort
]
\addplot3+[
%scatter/classes={ a={mark=square*, red}, b={mark=square*, blue}}, % this line fails
visualization depends on={\thisrow{x}\as\x},
visualization depends on={\thisrow{y}\as\y},
visualization depends on={\thisrow{z}\as\z},
visualization depends on={value \thisrowno{4} \as \label},
scatter/@pre marker code/.code={
\def\markopts{
mark size=(\x+\y)/3+2,%
% color=red if \label == a else blue, % I don't know how to handle this
opacity=\z
}
\expandafter\scope\expandafter[\markopts]
},
scatter/@post marker code/.code={
\endscope
},
] table[x=x, y=y, z=z, meta=label, col sep=space] {
x y z label
0 0 0.1 a
0 1 0.5 b
1.2 0 1.0 a
2 5 0.7 a
};
\end{axis}
\end{tikzpicture}
\end{document}
我认为该scatter/classes={}
行无法工作是因为宏@pre
和@post
被重新定义,但是,如何处理每个类的字符串比较?
答案1
你的\thisrowno{4}
做法是错误的,因为表输入中的列索引pgfplots
从 0 开始。因此,\thisrowno{3}
可以工作,但我更喜欢使用,\thisrow{label}
因为它更具可读性,并且允许您稍后在表中插入列而不会破坏代码。
除此之外,一旦在宏中有了标签\myLabel
,您就可以使用expl3
诸如\str_case_e:nnF
实现带回退的 switch-case字符串比较的函数:
\ExplSyntaxOn
% Like \let, but errors out if \strCase is already defined
\cs_new_eq:NN \strCase \str_case_e:nnF
\ExplSyntaxOff
...
\def\markopts{
mark size=(\x+\y)/3+2,
color/.expanded={\strCase{\myLabel}{{a}{red}
{b}{blue}}{green}},
...
}
这里,green
是当点的标签既不是a
也不是时使用的后备值b
。您可以根据需要添加任意数量的案例。请注意,\strCase
在里面起作用,因为它是函数的color/.expanded={...}
别名,即expl3
\str_case_e:nnF
完全可扩展(这一事实记录在界面3.pdf,其中在边缘处的宏名称旁边有一颗完整的星号)。
第一个例子
以下是以标签相关方式通过编程设置标记颜色的完整代码。如果您需要为每种标签类型设置多个样式元素,我建议使用略有不同的技术以提高可读性 - 请参阅下面的第二个示例。
\documentclass[tikz, border=3mm]{standalone}
\usepackage{expl3}
\usepackage{pgfplots}
\pgfplotsset{width=7cm, compat=1.15}
\ExplSyntaxOn
% Like \let, but errors out if \strCase is already defined
\cs_new_eq:NN \strCase \str_case_e:nnF
\ExplSyntaxOff
\begin{document}
\begin{tikzpicture}
\begin{axis}[z buffer=sort]
\addplot3+[
scatter, only marks,
scatter src=explicit symbolic,
visualization depends on={\thisrow{x}\as\x},
visualization depends on={\thisrow{y}\as\y},
visualization depends on={\thisrow{z}\as\z},
visualization depends on={value \thisrow{label} \as \myLabel},
scatter/@pre marker code/.code={%
\def\markopts{%
mark size=(\x+\y)/3+2,
color/.expanded={\strCase{\myLabel}{{a}{red}
{b}{blue}}{green}},
opacity=\z,
}%
\expandafter\scope\expandafter[\markopts]
},
scatter/@post marker code/.code={
\endscope
},
] table[x=x, y=y, z=z, meta=label, col sep=space] {
x y z label
0 0 0.1 a
0 1 0.5 b
1.2 0 1.0 a
2 5 0.7 a
};
\end{axis}
\end{tikzpicture}
\end{document}
注意:在这种特殊情况下,如果expl3
您的系统上的版本太旧\str_case_e:nnF
,则\cs_new_eq:NN \strCase \str_case_e:nnF
可以将该行替换为:
\cs_generate_variant:Nn \str_case:nnF { V }
\cs_new_eq:NN \strCase \str_case:VnF
(\str_case:VnF
是不是相当于\str_case_e:nnF
,但它已经足以满足我们的需要)。
第二个例子
在第二个示例中,我们想要以标签相关的方式设置多个标记样式属性(PGF 键)。使用之前的技术可以实现这一点,但会导致大量冗余:
\def\markopts{
mark size=(\x+\y)/3+2,
color/.expanded={\strCase{\myLabel}{{a}{red}
{b}{blue}}{green}},
mark/.expanded={\strCase{\myLabel}{{a}{triangle*}
{b}{square*}}{x}},
...,
}
因此,我提出了一种略有不同的技术,允许人们在处理每种情况时一次设置多个 PGF 键:
\documentclass[tikz, border=3mm]{standalone}
\usepackage{expl3}
\usepackage{pgfplots}
\pgfplotsset{width=7cm, compat=1.15}
\ExplSyntaxOn
\cs_generate_variant:Nn \str_case:nnF { V }
\cs_new_eq:NN \strCase \str_case:VnF
\ExplSyntaxOff
\begin{document}
\begin{tikzpicture}
\begin{axis}[z buffer=sort]
\addplot3+[
scatter, only marks,
scatter src=explicit symbolic,
visualization depends on={\thisrow{x}\as\x},
visualization depends on={\thisrow{y}\as\y},
visualization depends on={\thisrow{z}\as\z},
visualization depends on={value \thisrow{label} \as \myLabel},
scatter/@pre marker code/.code={%
\edef\markopts{%
\strCase{\myLabel}
{
{a}{mark=triangle*, color=red}
{b}{mark=square*, color=blue}
}
{mark=x, color=green}, % fallback
mark size=(\x+\y)/3+2,
opacity=\z,
}%
\expandafter\scope\expandafter[\markopts]
},
scatter/@post marker code/.code={
\endscope
},
] table[x=x, y=y, z=z, meta=label, col sep=space] {
x y z label
0 0 0.1 a
0 1 0.5 b
1.2 0 1.0 a
2 5 0.7 a
};
\end{axis}
\end{tikzpicture}
\end{document}
如果标签相关代码中存在不能过早扩展的宏(“敏感材料”)(即,在\strCase
扩展时),则可以\edef
使用或\noexpand
来保护敏感材料免受扩展的\unexpanded
影响,例如:
\strCase{\myLabel}
{
{a}{mark=triangle*, \unexpanded{〈sensitive balanced text〉}}
{b}{mark=square*, foo=\noexpand〈sensitiveToken〉}
}
{mark=x, color=green},
\unexpanded{%
foo=bar,
baz=quux,
}%
这里,〈sensitiveToken〉 可以是一个宏或者一个活动字符,而 〈sensitive equippedtext〉 可以由任意多个标记组成。