使用两个二分图生成关联图

使用两个二分图生成关联图

我在 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)中的代码,并定义颜色,得到结果(可以尝试其他颜色):\drawconnectionsundecided\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.cdraw a.e -- b.w删​​除cutaftercutbefore线。

我已经向您展示了如何通过强度改变线条的粗细以及如何改变颜色。

相关内容