我在 R 中有一个数据集,其中包含 3 个类别、10 个特征和 3 个实体。实体和类别与特征的关联性以 -1 到 1 之间的值给出。我的目标是用以下图形说明数据:
我使用 Inkscape 创建了它。我的问题是是否可以使用 latex 来实现,或者我应该尝试在 R 中实现它(并将这个问题转移到另一个论坛)?
编辑:按照以下输入并修改@guilherme-z-santos 示例,我能够创建下表:
\definecolor{notatall}{RGB}{0,0,255}
\definecolor{verymuch}{RGB}{255,0,0}
\newcommand*{\drawconnections}[3][west]{\draw (#2) foreach \i/\j in {#3}{ edge[verymuch!\j!notatall] (feat-\i.#1)};}
\usepackage{arrayjob}
\newarray\features
\readarray{features}{Feature-1&Feature-2&Feature-3&Feature-4&Feature-5&Feature-6&Feature-7&Feature-8&Feature-9&Feature-10}
\begin{document}
\sffamily
\begin{tikzpicture}[line width=1pt]
\begin{scope}[font=\itshape]
\node (feat-1) {\features(1)};
\foreach \i[remember=\i as \lasti (initially 1)] in {2,...,10}{\node[below=5mm of feat-\lasti] (feat-\i) {\features(\i)};};
\end{scope}
\node[left] (cat-2) at ([xshift=-3cm]$(feat-1)!.5!(feat-10)$) {Category 2};
\node[above=2cm of cat-2] (cat-1) {Category 1};
\node[below=2cm of cat-2] (cat-3) {Category 3};
\node[above right] (ent-1) at ([shift={(3cm,1.5cm)}]$(feat-1)!.5!(feat-10)$) {Entity 1};
\node[below=3cm of ent-1] (ent-2) {Entity 2};
\node[above=8mm of feat-1, left color=notatall,right color=verymuch, minimum width=6cm, minimum height=6pt, inner sep=0pt] (shade bar) {};
\begin{scope}[font=\scriptsize]
\node[above] at (shade bar.north west) {-1};
\node[below] at (shade bar.south west) {not at all};
\node[above] at (shade bar.north) {0};
\node[below] at (shade bar.south) {undecided};
\node[above] at (shade bar.north east) {1};
\node[below] at (shade bar.south east) {very much};
\end{scope}
\drawconnections{cat-1.east}{1/10,2/80,3/20,4/100,5/0,6/30,7/40,8/90,9/10,10/70};
\drawconnections{cat-2.east}{1/20,2/40,3/0,4/10,5/0,6/100,7/20,8/10,9/90,10/20};
\drawconnections{cat-3.east}{1/10,2/80,3/20,4/100,5/0,6/30,7/40,8/90,9/10,10/70};
\drawconnections[east]{ent-1.west}{1/10,2/80,3/20,4/100,5/0,6/30,7/40,8/90,9/10,10/70};
\drawconnections[east]{ent-2.west}{1/30,2/80,3/20,4/70,5/40,6/100,7/40,8/10,9/40,10/20};
\end{tikzpicture}
\end{document}
答案1
如果您可以将 -1 到 1 的比例转换为 0 到 100,那么您可以使用 将这些数字作为颜色混合百分比传递到列表中foreach
,以下内容由以下 MWE 生成:
\documentclass[tikz, border=2mm]{standalone}
\makeatletter
\newcommand*\ifnodedefined[3]{%
\@ifundefined{pgf@sh@ns@#1}{#3}{#2}%
}
\makeatother
\usetikzlibrary{positioning,calc}
\definecolor{notatall}{RGB}{0,0,255}
\definecolor{verymuch}{RGB}{255,0,0}
\newcommand*{\drawconnections}[3][west]{\draw (#2) foreach \j[count=\i from 1] in {#3}{\ifnodedefined{feat-\i}{edge[verymuch!\j!notatall] (feat-\i.#1)}{}};}
\newcommand{\drawfeatures}[1]{\foreach \feat[count=\i from 1, remember=\i as \lasti (initially 0)] in {#1}{\ifnum\i=1\node (feat-1) {\feat} \else \node[below=5mm of feat-\lasti] (feat-\i) {\feat}\fi;\global\let\totalfeat\i}}
\begin{document}
\sffamily
\begin{tikzpicture}[line width=1pt]
\begin{scope}[font=\itshape]
\drawfeatures{a feature, another feature, more feature, no more features, lied ;-), foo, bar}
\end{scope}
\node[left] (cat-2) at ([xshift=-3cm]$(feat-1)!.5!(feat-\totalfeat)$) {Category 2};
\path let \p1=($(feat-1)-(feat-\totalfeat)$), \n1={veclen(\x1,\y1)} in%
node[above=\n1/4 of cat-2] (cat-1) {Category 1}%
node[below=\n1/4 of cat-2] (cat-3) {Category 3}%
([xshift=3cm]$(feat-1)!.5!(feat-\totalfeat)$) coordinate (tmp)%
node[above right=\n1/6 and 0pt of tmp] (ent-1) {Entity 1}%
node[below=\n1/3 of ent-1] (ent-2) {Entity 2};
\node[above=8mm of feat-1, left color=notatall,right color=verymuch, minimum width=6cm, minimum height=6pt, inner sep=0pt] (shade bar) {};
\begin{scope}[font=\scriptsize]
\foreach \uptext/\bottomtext/\loc in {-1/not at all/ west,0/undecided/,1/very much/ east}{
\node[above] at (shade bar.north\loc) {\uptext};
\node[below] at (shade bar.south\loc) {\bottomtext};}
\end{scope}
\drawconnections{cat-1.east}{10,80,20,100,0,30,40,90,10,70};
\drawconnections{cat-2.east}{20,40,0,10,0,100,20,10,90,20};
\drawconnections{cat-3.east}{10,80,20,100,0,30,40,90,10,70};
\drawconnections[east]{ent-1.west}{10,80,20,100,0,30,40,90,10,70};
\drawconnections[east]{ent-2.west}{30,80,20,70,40,100,40,10,40,20};
\end{tikzpicture}
\end{document}
编辑:
OP 要求的第二种方法是使用两种以上颜色的色标,在这种情况下,颜色0
将是白色,但任何颜色都可以。由于手头有两种颜色,\ifnum
必须使用一个来分隔刻度,即(转换为百分比)从 0 到 50 将从蓝色变为白色,从 50 到 100 将从白色变为红色,转换为 TeX 即
\ifnum\j>50%
let \n1={int(2*(\j-50))} in% this is rescaling the 0-50 to be 0-100 or else there'd be no full red only 50/50
edge[verymuch!\n1!undecided] (feat-\i.#1)%
\else%
let \n1={int(2*(50-\j))} in% the same here
edge[notatall!\n1!undecided] (feat-\i.#1)%
\fi
用上面的代码片段替换 MWE 命令edge[verymuch!\j!notatall] (feat-\i.#1)
中的代码,并定义颜色,得到结果(可以尝试其他颜色):\drawconnections
undecided
\definecolor{undecided}{RGB}{255,255,255}
评论
或许更好的解决方案(对于白色中间色)是使用opacity
(同时设置line cap=round
产生更好看的结果):
\ifnum\j>50%
let \n1={2*(100-\j)/100} in% this is rescaling the 0-50 to be 0-100 or else there'd be no full red only 50/50
edge[verymuch, opacity=\n1, line cap=round] (feat-\i.#1)%
\else%
let \n1={2*(50-\j)/100} in% the same here
edge[notatall, opacity=\n1, line cap=round] (feat-\i.#1)%
\fi
答案2
这是开始元帖子使用luamplib
包。使用 进行编译lualatex
。Metapostboxes
库提供了boxit
函数;它的文档是这里。
\RequirePackage{luatex85}
\documentclass[border=5mm]{standalone}
\usepackage{luamplib}
\usepackage{fontspec}
\setmainfont{TeX Gyre Heros}
\begin{document}
\mplibtextextlabel{enable}
\begin{mplibcode}
input boxes;
beginfig(1);
boxit.c1("Category 1");
boxit.c2("Category 2");
boxit.c3("Category 3");
c1.c = c2.c + 100 up;
c3.c = c2.c + 100 down;
boxit.f1("\textit{feature 1}");
boxit.f2("\textit{feature 2}");
boxit.f3("\textit{feature 3}");
f2.c = c2.c + 100 right;
f1.c = f2.c + 40 up;
f3.c = f2.c + 40 down;
boxit.e1("Entity 1");
boxit.e2("Entity 2");
e1.c = f2.c + (100,30);
e2.c = f2.c + (100,-30);
drawunboxed(c1,c2,c3);
drawunboxed(f1,f2,f3);
drawunboxed(e1,e2);
vardef connect(suffix a, b)(expr strength) =
draw a.c -- b.c
cutbefore bpath a
cutafter bpath b
withpen pencircle scaled ((strength+2)/4)
withcolor ((strength+1)/2)[blue,red];
enddef;
connect(c1,f1,+1.0);
connect(c1,f2,-0.5);
connect(c1,f3,-0.2);
connect(c2,f1,+0.6);
connect(c2,f2,+0.3);
connect(c2,f3,-0.9);
% etc
endfig;
\end{mplibcode}
\end{document}
笔记
正如boxes
手册所解释的,该命令boxit.sss("Some text")
会创建一个名为“sss
以点为中心”的框sss.c
。然后,您可以指定框之间的关系,当您使用框名称列表调用drawunboxed
(或) 时,位置就会固定。drawboxed
然后我创建了一个connect
宏来以一致的方式绘制连接。
如果您希望所有连接从一个箱子的东边延伸到下一个箱子的西边,您可以替换draw a.c -- b.c
并draw a.e -- b.w
删除cutafter
和cutbefore
线。
我已经向您展示了如何通过强度改变线条的粗细以及如何改变颜色。