Centralize a legenda, mas ignore certas partes da imagem TikZ

Centralize a legenda, mas ignore certas partes da imagem TikZ

Considere o seguinte MWE:

\documentclass[a4paper]{scrartcl}

\usepackage{mathtools}
\usepackage{amssymb}

\usepackage[compatibility=false]{caption}
\usepackage[list]{subcaption}

\usepackage{fancyvrb}

\usepackage{tikz}
\usetikzlibrary{patterns, fit, positioning, calc, shapes.arrows}

\usepackage[active, tightpage, floats, displaymath]{preview}

\mathtoolsset{%
  mathic=true
}

% Vectors and matrices
\renewcommand*{\vec}[1]{\mathbf{#1}}
\newcommand{\mat}[1]{\mathbf{#1}}
\newcommand{\trans}{\intercal}

% Operators
\DeclareMathOperator{\rank}{rank}
\DeclareMathOperator*{\argmin}{arg\,min}
\DeclareMathOperator*{\argmax}{arg\,max}

\begin{document}
\begin{figure}
  \centering
  \captionsetup[subfigure]{margin={2.5cm, 0cm}}
  \begin{subfigure}[b]{0.60\textwidth}
    \centering
    \begin{tikzpicture}[>=latex, shorten >=2pt, shorten <=2pt]
      \node[draw, rectangle, label=below:the] (the) {\(\mat W\)};
      \node[draw, rectangle, right=of the, label=below:cat] (cat) {\(\mat W\)};
      \node[draw, rectangle, right=of cat, label=below:sat] (sat) {\(\mat W\)};

      \node[draw, rectangle, fit=(the.west) (the.east), pattern=vertical lines, above=of the] (in_the) {};
      \node[draw, rectangle, fit=(cat.west) (cat.east), pattern=vertical lines, above=of cat] (in_cat) {};
      \node[draw, rectangle, fit=(sat.west) (sat.east), pattern=vertical lines, above=of sat] (in_sat) {};

      \node[draw, rectangle, fit={($(cat.west) + (-8pt,0pt)$) ($(cat.east) + (8pt,0pt)$)}, pattern=vertical lines, above=2cm of cat] (in) {};
      \node[draw, rectangle, above=of in, label=above:mat] (out) {\(\vec b\), \(\mat U\)};

      \node[left=of the, outer sep=0] (embed) {embed};
      \node[above=2cm of embed, outer sep=0] (concatenate) {concatenate};
      \node[above=1cm of concatenate, outer sep=0] {softmax};

      \foreach \word in {the, cat, sat}{%
        \draw[->] (\word) -- (in_\word);
        \draw[->] (in_\word) -- (in);
      }

      \draw[->] (in) -- (out);
    \end{tikzpicture}
    \caption{CBOW model}\label{fig:cbow}
  \end{subfigure}
  \captionsetup[subfigure]{margin={0cm,0cm}}
  \begin{subfigure}[b]{0.35\textwidth}
    \centering
    \begin{tikzpicture}[>=latex, shorten >=2pt, shorten <=2pt]
      \node[draw, rectangle, label=below:cat] (cat) {\(\mat W\)};
      \node[draw, rectangle, fit=(cat.west) (cat.east), pattern=vertical lines, above=of cat] (in) {};
      \node[draw, rectangle, above=2cmof in, label=above:on] (on) {\(\vec b\), \(\mat U\)};
      \node[draw, rectangle, left=of on, label=above:sat] (sat) {\(\vec b\), \(\mat U\)};
      \node[draw, rectangle, right=of on, label=above:the] (the) {\(\vec b\), \(\mat U\)};

      \draw[->] (cat) -- (in);
      \foreach \word in {sat, on, the}{%
        \draw[->] (in) -- (\word);
      }
    \end{tikzpicture}
    \caption{Skip\=/gram model}\label{fig:sg}
  \end{subfigure}
  \caption{\protect\Verb+Word2Vec+ with vocabulary size \(V\), context
    size \(C\), and embedding size \(N\)}
\end{figure}
\end{document}

%%% Local Variables:
%%% mode: latex
%%% TeX-master: t
%%% End:

Em que tipografia:

Ilustração Word2Vec

Como você pode ver, eu "centrei" a legenda "(a) modelo CBOW" usando \captionsetup[subfigure]{margin={2.5cm, 0cm}}. Minha pergunta é: é possível não ter que fazer isso? Ou pelo menos calcular de alguma forma a largura correta pela qual preciso compensar a legenda?

Responder1

Você pode usar \useasboundingboxno TikZ para definir a dimensão da imagem. O TikZ irá então ignorar tudo após esse comando para calcular o tamanho da imagem. Com (current bounding box)você pode fazer referência ao tamanho da imagem até agora. Desde que você desenhe tudo, o que deve contar para o tamanho do papel, antes da linha \useasboundingbox (current bounding box)a imagem terá o tamanho desejado.

Além disso, é necessário um espaço vazio subfigurepara permitir a sobreposição à esquerda. Então tem que ser o primeiro. É claro que a largura da subfigura esquerda (bem, agora do meio) deve ser ajustada.

\documentclass[a4paper]{scrartcl}

\usepackage{mathtools}
\usepackage{amssymb}

\usepackage[compatibility=false]{caption}
\usepackage[list]{subcaption}

\usepackage{fancyvrb}

\usepackage{tikz}
\usetikzlibrary{patterns, fit, positioning, calc, shapes.arrows}

\usepackage[active, tightpage, floats, displaymath]{preview}

\mathtoolsset{%
  mathic=true
}

% Vectors and matrices
\renewcommand*{\vec}[1]{\mathbf{#1}}
\newcommand{\mat}[1]{\mathbf{#1}}
\newcommand{\trans}{\intercal}

% Operators
\DeclareMathOperator{\rank}{rank}
\DeclareMathOperator*{\argmin}{arg\,min}
\DeclareMathOperator*{\argmax}{arg\,max}

\begin{document}
\begin{figure}
  \centering
% no longer needed
%  \captionsetup[subfigure]{margin={2.5cm, 0cm}}
  %empty subfugure to allow for overlap to the left
  \begin{subfigure}[b]{0.15\textwidth}
  \mbox{}
  \end{subfigure}
  \begin{subfigure}[b]{0.40\textwidth}
    \centering
    \begin{tikzpicture}[>=latex, shorten >=2pt, shorten <=2pt]
      \node[draw, rectangle, label=below:the] (the) {\(\mat W\)};
      \node[draw, rectangle, right=of the, label=below:cat] (cat) {\(\mat W\)};
      \node[draw, rectangle, right=of cat, label=below:sat] (sat) {\(\mat W\)};

      \node[draw, rectangle, fit=(the.west) (the.east), pattern=vertical lines, above=of the] (in_the) {};
      \node[draw, rectangle, fit=(cat.west) (cat.east), pattern=vertical lines, above=of cat] (in_cat) {};
      \node[draw, rectangle, fit=(sat.west) (sat.east), pattern=vertical lines, above=of sat] (in_sat) {};

      \node[draw, rectangle, fit={($(cat.west) + (-8pt,0pt)$) ($(cat.east) + (8pt,0pt)$)}, pattern=vertical lines, above=2cm of cat] (in) {};
      \node[draw, rectangle, above=of in, label=above:mat] (out) {\(\vec b\), \(\mat U\)};

      % set the picture size to everything drawn so far
      \useasboundingbox (current bounding box);

      % not taken into account for the picture size
      \node[left=of the, outer sep=0] (embed) {embed};
      \node[above=2cm of embed, outer sep=0] (concatenate) {concatenate};
      \node[above=1cm of concatenate, outer sep=0] {softmax};

      % this belongs to the main part, but it doesn't increase its size
      % otherwise it must be moved before \useasboundingbox
      \foreach \word in {the, cat, sat}{%
        \draw[->] (\word) -- (in_\word);
        \draw[->] (in_\word) -- (in);
      }

      \draw[->] (in) -- (out);
    \end{tikzpicture}
    \caption{CBOW model}\label{fig:cbow}
  \end{subfigure}
% no longer needed
%  \captionsetup[subfigure]{margin={0cm,0cm}}
  \begin{subfigure}[b]{0.35\textwidth}
    \centering
    \begin{tikzpicture}[>=latex, shorten >=2pt, shorten <=2pt]
      \node[draw, rectangle, label=below:cat] (cat) {\(\mat W\)};
      \node[draw, rectangle, fit=(cat.west) (cat.east), pattern=vertical lines, above=of cat] (in) {};
      \node[draw, rectangle, above=2cmof in, label=above:on] (on) {\(\vec b\), \(\mat U\)};
      \node[draw, rectangle, left=of on, label=above:sat] (sat) {\(\vec b\), \(\mat U\)};
      \node[draw, rectangle, right=of on, label=above:the] (the) {\(\vec b\), \(\mat U\)};

      \draw[->] (cat) -- (in);
      \foreach \word in {sat, on, the}{%
        \draw[->] (in) -- (\word);
      }
    \end{tikzpicture}
    \caption{Skip\=/gram model}\label{fig:sg}
  \end{subfigure}
  \caption{\protect\Verb+Word2Vec+ with vocabulary size \(V\), context
    size \(C\), and embedding size \(N\)}
\end{figure}
\end{document}

Responder2

Este é um método (relativamente) menos simples do que minha resposta original (relativamente) simples, que é um pouco mais flexível e um pouco melhor testada. Requer etoolboxe xparse. (Você poderia facilmente dispensar este último, se desejar, mas é conveniente.)

  • Conforme configurei as coisas, isso modifica todos tikzpictureos ambientes.

    • Poderia ser ampliado para incluir \tikzmacros, se necessário.

    • Se o impacto global for indesejável, remova a every picturedefinição e simplesmente use mark outno argumento opcional para tikzpicture.

  • Permite ajuste para material à esquerda, direita, ambos ou nenhum.

O único requisito para o caso simples baseado no MWE é inserir \tikzmarkerwestno ponto da imagem onde se deseja marcar a esquerda da parte da imagem que \captiondeverá ser utilizada para colocar a legenda. Se você não usar a macro na imagem, o código simplesmente retornará à esquerda da caixa delimitadora da imagem, quando a imagem estiver completa. Isso acontece no segundo subfigureexemplo.

O código da primeira subfigureé reorganizado, de modo que tudo o que \captiondeveria ser ignorado venha depois da primeira parte da imagem. \tikzmarkerwesté então inserido para marcar o lado esquerdo neste ponto.

...
      \foreach \word in {the, cat, sat}{%
        \draw[->] (\word) -- (in_\word);
        \draw[->] (in_\word) -- (in);
      }
      \draw[->] (in) -- (out);

Isso é tudo que queremos \captionusar para posicionamento, então marque agora à esquerda da imagem.

      \tikzmarkerwest

Agora colocamos as coisas à esquerda desse ponto, que \captiondevemos ignorar.

      \node[left=of the, outer sep=0] (embed) {embed};
      \node[above=2cm of embed, outer sep=0] (concatenate) {concatenate};
      \node[above=1cm of concatenate, outer sep=0] {softmax};

Agora terminamos a imagem e adicionamos a legenda e o rótulo como de costume.

    \end{tikzpicture}
    \caption{CBOW model}\label{fig:cbow}

legenda ajustada

Para o material à direita, \tikzmarkereastpode ser usado em vez de, ou também, \tikzmarkerwest.

Em alguns casos, é inconveniente ou impossível reorganizar o código numa imagem desta forma. Simplesmente não pode ser desenhado facilmente, se é que pode ser desenhado, na ordem exigida. Por esta razão, \tikzmarkereaste \tikzmarkerwestapoie um argumento opcional. Se especificado, deve ser uma coordenada entre colchetes, como de costume para coordenadas. Neste caso, tudo à direita ou à esquerda da coordenada especificada será ignorado ao colocar a legenda.

O código que suporta isso define a macro \tikzmarkerwestda seguinte maneira.

\NewDocumentCommand \tikzmarkerwest { D () {current bounding box.west} } {%
  \coordinate (tikz marker west) at (#1);
  \let\tikzmarkerwestdefault\relax
}

Isso cria uma coordenada (tikz marker west)no local apropriado. Em seguida, garante que \tikzmarkerwestdefaultnada seja feito com sucesso.

\tikzmarkereasté definido da mesma maneira.

\NewDocumentCommand \tikzmarkereast { D () {current bounding box.east} } {%
  \coordinate (tikz marker east) at (#1);
  \let\tikzmarkereastdefault\relax
}

Nós garantimos \tikzmarkerwestdefaulte \tikzmarkereastestamos definidos. Por padrão, eles não fazem nada.

\NewDocumentCommand \tikzmarkerwestdefault {} {}
\NewDocumentCommand \tikzmarkereastdefault {} {}

Agora para o TikCódigo Z.

\tikzset{%

O estilo mark outadiciona código a ser executado no início e no final da imagem atual, se fornecido no argumento opcional do ambiente, ou de todas as imagens, se configurado conforme abaixo.

  mark out/.style={%
    execute at begin picture={%
      \RenewDocumentCommand \tikzmarkerwestdefault {}
      {%
        \coordinate (tikz marker west) at (current bounding box.west);
      }%
      \RenewDocumentCommand \tikzmarkereastdefault {}
      {%
        \coordinate (tikz marker east) at (current bounding box.east);
      }%
    },

Isso redefine nossas macros \tikzmarkerwestdefaulte \tikzmarkereastdefaultpara criar coordenadas à esquerda e (tikz marker west)à (tikz marker east)direita da caixa delimitadora atual. Estas são apenas definições, substituindo as vazias padrão. Na verdade, eles ainda não criam nenhuma coordenada.

    execute at end picture={%
      \tikzmarkerwestdefault
      \tikzmarkereastdefault

No final da imagem, executamos \tikzmarkerwestdefault. Se \tikzmarkerwesttiver sido chamado dentro da imagem, isso não fará nada com sucesso. Caso contrário, criará o marcador à esquerda da caixa delimitadora atual, que é a caixa delimitadora final da imagem. Da mesma forma para \tikzmarkereastdefault.

      \path let \p1=(tikz marker west), \p2=(current bounding box.west), \n1={\x1-\x2} in \pgfextra{\xdef\myadjustwest{\n1}} ;

Isto calcula a diferença entre a xparte da (tikz marker west)coordenada e a xparte da coordenada à esquerda da caixa delimitadora atual. Normalmente, será 0pt. Mas, se \tikzmarkerwesttiver sido chamado, a distância do nó marcador à esquerda da caixa delimitadora atual pode ser diferente de zero. (Na verdade, se a macro tiver sido chamada, presumivelmente será esse o caso, pois essa é a única razão para usar a macro.)

Agora fazemos o mesmo à (tikz marker east)direita da caixa delimitadora atual.

      \path let \p1=(tikz marker east), \p2=(current bounding box.east), \n1={\x2-\x1} in \pgfextra{\xdef\myadjusteast{\n1}} ;
    },
  },


  every picture/.style={mark out},

Esta linha aplica o mark outestilo a todos os TikFotos Z. Se isso causar problemas, remova-o e adicione-o mark outàs fotos desejadas.

}
\newlength\myadjustwest
\newlength\myadjusteast

Certifique-se \myadjustweste \myadjusteastesteja disponível de qualquer maneira.

\AfterEndEnvironment{tikzpicture}{%
  \captionsetup{margin={\myadjustwest,\myadjusteast}}%
}{\typeout{OK!}}{\typeout{Oh, no!}}

Isso adapta o final de todos tikzpictureos ambientes para modificá-los \captioncorretamente. Você deve substituir mensagens significativas por si mesmo no lugar de OK!e Oh, no!, se usar isso.

O conjunto de exemplos a seguir ilustra as possibilidades básicas. Se você deseja colocar a legenda em relação a, digamos, um retângulo sombreado, você não pode (com facilidade) sombrear parte dela, depois outra parte e depois outra parte, marcando a caixa delimitadora entre os estágios de forma adequada. Portanto, para este caso, usamos os argumentos opcionais para \tikzmarkerweste/ou \tikzmarkereast, para obter posições para legendas com foco na extremidade vermelha do espectro de luz visível, na extremidade azul e em um bit intermediário à esquerda do centro.

Para os tintos ...

...
      \shade [shading=wave, shading angle=90] (0,0) rectangle ++(\linewidth,1) coordinate [pos=.4] (r);
      \tikzmarkereast(r)
...

Para o azul ...

...
      \shade [shading=wave, shading angle=90] (0,0) rectangle ++(\linewidth,1) coordinate [pos=.6] (b);
      \tikzmarkerwest(b)
...

Para as entranhas ...

...
      \shade [shading=wave, shading angle=90] (0,0) rectangle ++(\linewidth,1) coordinate [pos=.1] (a) coordinate [pos=.5] (b);
      \tikzmarkereast(b)
      \tikzmarkerwest(a)
...

legendas ajustadas para espectro de luz visível

Código completo:

% arara: pdflatex
\pdfminorversion=7
% ateb: https://tex.stackexchange.com/a/377652/ addaswyd o gwestiwn d125q: https://tex.stackexchange.com/q/377476/
\documentclass[a4paper]{scrartcl}
\usepackage{mathtools,amssymb}
\usepackage[compatibility=false]{caption}
\usepackage[list]{subcaption}
\usepackage{fancyvrb,tikz,etoolbox,xparse}
\usetikzlibrary{patterns, fit, positioning, calc}
\usepackage[active, tightpage, floats, displaymath]{preview}
\mathtoolsset{%
  mathic=true
}
\NewDocumentCommand \tikzmarkerwest { D () {current bounding box.west} } {%
  \coordinate (tikz marker west) at (#1);
  \let\tikzmarkerwestdefault\relax
}
\NewDocumentCommand \tikzmarkerwestdefault {} {}
\NewDocumentCommand \tikzmarkereast { D () {current bounding box.east} } {%
  \coordinate (tikz marker east) at (#1);
  \let\tikzmarkereastdefault\relax
}
\NewDocumentCommand \tikzmarkereastdefault {} {}
\tikzset{%
  mark out/.style={%
    execute at begin picture={%
      \RenewDocumentCommand \tikzmarkerwestdefault {}
      {%
        \coordinate (tikz marker west) at (current bounding box.west);
      }%
      \RenewDocumentCommand \tikzmarkereastdefault {}
      {%
        \coordinate (tikz marker east) at (current bounding box.east);
      }%
    },
    execute at end picture={%
      \tikzmarkerwestdefault
      \tikzmarkereastdefault
      \path let \p1=(tikz marker west), \p2=(current bounding box.west), \n1={\x1-\x2} in \pgfextra{\xdef\myadjustwest{\n1}} ;
      \path let \p1=(tikz marker east), \p2=(current bounding box.east), \n1={\x2-\x1} in \pgfextra{\xdef\myadjusteast{\n1}} ;
    },
  },
  every picture/.style={mark out},
}
\newlength\myadjustwest
\newlength\myadjusteast
\AfterEndEnvironment{tikzpicture}{%
  \captionsetup{margin={\myadjustwest,\myadjusteast}}%
}{\typeout{OK!}}{\typeout{Oh, no!}}

% for the examples
\definecolor{wave start}{wave}{380}
\definecolor{wave violet}{wave}{400}
\definecolor{wave indigo}{wave}{445}
\definecolor{wave blue}{wave}{475}
\definecolor{wave green}{wave}{510}
\definecolor{wave yellow}{wave}{570}
\definecolor{wave orange}{wave}{590}
\definecolor{wave red}{wave}{650}
\definecolor{wave end}{wave}{780}
\pgfdeclareverticalshading{wave}{100bp}{% manual 1088; xcolor manual; does not work to use wave model directly (?); https://science-edu.larc.nasa.gov/EDDOCS/Wavelengths_for_Colors.html
  color(0bp)=(wave start);
  color(25bp)=(wave start);
  color(27bp)=(wave violet);% 400 nm
  color(33bp)=(wave indigo);% 445nm
  color(37bp)=(wave blue);% 475nm
  color(41bp)=(wave green);% 510nm
  color(49bp)=(wave yellow);% 570nm
  color(51bp)=(wave orange);% 590nm
  color(59bp)=(wave red);% 650nm
  color(75bp)=(wave end);% 780nm
  color(100bp)=(wave end)
}
\begin{document}
\begin{figure}
  \centering
  \begin{subfigure}[b]{0.60\textwidth}
    \centering
    \begin{tikzpicture}[>=latex, shorten >=2pt, shorten <=2pt]
      \node[draw, label=below:the] (the) {\(\mathbf{W}\)};
      \node[draw, right=of the, label=below:cat] (cat) {\(\mathbf{W}\)};
      \node[draw, right=of cat, label=below:sat] (sat) {\(\mathbf{W}\)};
      \node[draw, fit=(the.west) (the.east), pattern=vertical lines, above=of the] (in_the) {};
      \node[draw, fit=(cat.west) (cat.east), pattern=vertical lines, above=of cat] (in_cat) {};
      \node[draw, fit=(sat.west) (sat.east), pattern=vertical lines, above=of sat] (in_sat) {};
      \node[draw, fit={($(cat.west) + (-8pt,0pt)$) ($(cat.east) + (8pt,0pt)$)}, pattern=vertical lines, above=2cm of cat] (in) {};
      \node[draw, above=of in, label=above:mat] (out) {\(\mathbf{b}\), \(\mathbf{U}\)};
      \foreach \word in {the, cat, sat}{%
        \draw[->] (\word) -- (in_\word);
        \draw[->] (in_\word) -- (in);
      }
      \draw[->] (in) -- (out);
      \tikzmarkerwest
      \node[left=of the, outer sep=0] (embed) {embed};
      \node[above=2cm of embed, outer sep=0] (concatenate) {concatenate};
      \node[above=1cm of concatenate, outer sep=0] {softmax};
    \end{tikzpicture}
    \caption{CBOW model}\label{fig:cbow}
  \end{subfigure}
  \begin{subfigure}[b]{0.35\textwidth}
    \centering
    \begin{tikzpicture}[>=latex, shorten >=2pt, shorten <=2pt]
      \node[draw, label=below:cat] (cat) {\(\mathbf{W}\)};
      \node[draw, fit=(cat.west) (cat.east), pattern=vertical lines, above=of cat] (in) {};
      \node[draw, above=2cmof in, label=above:on] (on) {\(\mathbf{b}\), \(\mathbf{U}\)};
      \node[draw, left=of on, label=above:sat] (sat) {\(\mathbf{b}\), \(\mathbf{U}\)};
      \node[draw, right=of on, label=above:the] (the) {\(\mathbf{b}\), \(\mathbf{U}\)};
      \draw[->] (cat) -- (in);
      \foreach \word in {sat, on, the}{%
        \draw[->] (in) -- (\word);
      }
    \end{tikzpicture}
    \caption{Skip\=/gram model}\label{fig:sg}
  \end{subfigure}
  \caption{\protect\Verb+Word2Vec+ with vocabulary size \(V\), context size \(C\), and embedding size \(N\)}
\end{figure}

\begin{figure}
  \centering
  \begin{subfigure}{.33\linewidth}
    \centering
    \begin{tikzpicture}
      \shade [shading=wave, shading angle=90] (0,0) rectangle ++(\linewidth,1) coordinate [pos=.4] (r);
      \tikzmarkereast(r)
    \end{tikzpicture}
    \caption{Reds.}
  \end{subfigure}\hfill
  \begin{subfigure}{.33\linewidth}
    \centering
    \begin{tikzpicture}
      \shade [shading=wave, shading angle=90] (0,0) rectangle ++(\linewidth,1) coordinate [pos=.6] (b);
      \tikzmarkerwest(b)
    \end{tikzpicture}
    \caption{Blues.}
  \end{subfigure}\hfill
  \begin{subfigure}{.33\linewidth}
    \centering
    \begin{tikzpicture}
      \shade [shading=wave, shading angle=90] (0,0) rectangle ++(\linewidth,1) coordinate [pos=.1] (a) coordinate [pos=.5] (b);
      \tikzmarkereast(b)
      \tikzmarkerwest(a)
    \end{tikzpicture}
    \caption{Innards.}
  \end{subfigure}\par
  \caption{Main figure}
\end{figure}
\end{document}

Responder3

Primeiro, não editei minha primeira resposta, porque ela pode ser útil para algumas pessoas do jeito que está.

Esta nova resposta calcula as margens da legenda. Para isso existem algumas macros no preâmbulo. E então três comandos devem ser colocados. Eles estão todos sem argumentos.

Na imagem a parte principal (ou seja, a parte sob a qual a legenda deve ser centralizada) deve ser desenhada primeiro. Então \pgfremembermainxtem que ser inserido. Ele definiu coordenadas para lembrar as posições x mais externas até agora. Depois disso, as partes que se sobrepõem à parte principal à esquerda e à direita devem ser desenhadas.

Logo no final, um pouco antes \end{tikzpicture}, o comando \pgfgetoverlapdeve ser colocado. Calcula a sobreposição (relativa à parte principal) para ambos os lados e armazena-as nos registros de dimensão \overlaplefte \overlapright. Ambos são definidos como globais, portanto podem ser usados ​​após o arquivo tikzpicture. Nota: tudo o que for desenhado a seguir \pgfgetoverlapnão será levado em consideração para o cálculo da sobreposição.

E finalmente entre o tikzpicturee a legenda as margens são definidas com \captionsetmargins. Seu efeito é local, pois está no subfiguremeio ambiente. Não deve ser utilizado fora do ambiente, pois definiria as margens para todas as legendas, já que o argumento opcional ( [subfigure]) não pode ser utilizado aqui. É claro que isso só funciona depois da imagem, pois as sobreposições não são conhecidas antes dela.

\documentclass[a4paper]{scrartcl}

\usepackage{mathtools}
\usepackage{amssymb}

\usepackage[compatibility=false]{caption}
\usepackage[list]{subcaption}

\usepackage{fancyvrb}

\usepackage{tikz}
\usetikzlibrary{patterns, fit, positioning, calc, shapes.arrows}

\usepackage[active, tightpage, floats, displaymath]{preview}

\mathtoolsset{%
  mathic=true
}

% Vectors and matrices
\renewcommand*{\vec}[1]{\mathbf{#1}}
\newcommand{\mat}[1]{\mathbf{#1}}
\newcommand{\trans}{\intercal}

% Operators
\DeclareMathOperator{\rank}{rank}
\DeclareMathOperator*{\argmin}{arg\,min}
\DeclareMathOperator*{\argmax}{arg\,max}

%---------------------------------------------------------------------
% code for automatic setting of caption margins
\makeatletter
\newdimen\overlapleft
\newdimen\overlapright

\newcommand{\pgfremembermainx}{%
    \coordinate (main west) at (current bounding box.west);
    \coordinate (main east) at (current bounding box.east);
}
\newcommand{\pgfgetoverlap}{%
    \pgfextractx{\@tempdima}{%
        \pgfpointdiff{\pgfpointanchor{current bounding box}{west}}%
                     {\pgfpointanchor{main west}{center}}%
    }%
    \global\overlapleft=\@tempdima
    \pgfextractx{\@tempdima}{%
        \pgfpointdiff{\pgfpointanchor{main east}{center}}%
                     {\pgfpointanchor{current bounding box}{east}}%
    }%
    \global\overlapright=\@tempdima
}
\newcommand{\captionsetmargins}{%
    % no additional calculation required here
    \captionsetup{margin={\overlapleft,\overlapright}}%
}
\makeatother
%---------------------------------------------------------------------

\begin{document}
\begin{figure}
  \centering
% not needed here
%  \captionsetup[subfigure]{margin={2.5cm, 0cm}}
  \begin{subfigure}[b]{0.60\textwidth}
    \centering
    \begin{tikzpicture}[>=latex, shorten >=2pt, shorten <=2pt]
      \node[draw, rectangle, label=below:the] (the) {\(\mat W\)};
      \node[draw, rectangle, right=of the, label=below:cat] (cat) {\(\mat W\)};
      \node[draw, rectangle, right=of cat, label=below:sat] (sat) {\(\mat W\)};

      \node[draw, rectangle, fit=(the.west) (the.east), pattern=vertical lines, above=of the] (in_the) {};
      \node[draw, rectangle, fit=(cat.west) (cat.east), pattern=vertical lines, above=of cat] (in_cat) {};
      \node[draw, rectangle, fit=(sat.west) (sat.east), pattern=vertical lines, above=of sat] (in_sat) {};

      \node[draw, rectangle, fit={($(cat.west) + (-8pt,0pt)$) ($(cat.east) + (8pt,0pt)$)}, pattern=vertical lines, above=2cm of cat] (in) {};
      \node[draw, rectangle, above=of in, label=above:mat] (out) {\(\vec b\), \(\mat U\)};

      % remember the x-coordinates of the main part      
      \pgfremembermainx
      % \useasboundingbox was here in the first answer

      % not taken into account for the picture size
      \node[left=of the, outer sep=0] (embed) {embed};
      \node[above=2cm of embed, outer sep=0] (concatenate) {concatenate};
      \node[above=1cm of concatenate, outer sep=0] {softmax};

      % this belongs to the main part, but it doesn't increase its size
      % otherwise it must be moved before \pgfremembermainx
      \foreach \word in {the, cat, sat}{%
        \draw[->] (\word) -- (in_\word);
        \draw[->] (in_\word) -- (in);
      }

      \draw[->] (in) -- (out);

      %for testing, if it also works with overlap to the right
      %\node[draw, right= of sat] {t};

      % must be right before \end{tikzpicture}, everything after it
      % would not be taken into account for the calculation of the overlap
      \pgfgetoverlap
    \end{tikzpicture}
    % setting the caption margins
    % moving this here sets the margin locally (only for the current environment)
    % and here the computed values for the margins are known
    \captionsetmargins
    \caption{CBOW model}\label{fig:cbow}
  \end{subfigure}
% no longer needed
%  \captionsetup[subfigure]{margin={0cm,0cm}}
  \begin{subfigure}[b]{0.35\textwidth}
    \centering
    \begin{tikzpicture}[>=latex, shorten >=2pt, shorten <=2pt]
      \node[draw, rectangle, label=below:cat] (cat) {\(\mat W\)};
      \node[draw, rectangle, fit=(cat.west) (cat.east), pattern=vertical lines, above=of cat] (in) {};
      \node[draw, rectangle, above=2cmof in, label=above:on] (on) {\(\vec b\), \(\mat U\)};
      \node[draw, rectangle, left=of on, label=above:sat] (sat) {\(\vec b\), \(\mat U\)};
      \node[draw, rectangle, right=of on, label=above:the] (the) {\(\vec b\), \(\mat U\)};

      \draw[->] (cat) -- (in);
      \foreach \word in {sat, on, the}{%
        \draw[->] (in) -- (\word);
      }
    \end{tikzpicture}
    \caption{Skip\=/gram model}\label{fig:sg}
  \end{subfigure}
  \caption{\protect\Verb+Word2Vec+ with vocabulary size \(V\), context
    size \(C\), and embedding size \(N\)}
\end{figure}
\end{document}

informação relacionada