居中標題,但忽略 TikZ 圖片的某些部分

居中標題,但忽略 TikZ 圖片的某些部分

考慮以下 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:

哪個排版為:

Word2Vec 插圖

正如您所看到的,我通過使用“居中”了“(a) CBOW model”標題\captionsetup[subfigure]{margin={2.5cm, 0cm}}。我的問題是:是否可以不必這樣做?或至少以某種方式計算出我需要偏移標題的正確寬度?

答案1

您可以\useasboundingbox在 TikZ 中使用來設定圖片的尺寸。然後 TikZ 將忽略該命令之後的所有內容來計算圖片大小。您(current bounding box)可以參考到目前為止圖片的尺寸。只要您在線條之前繪製所有內容(應計入紙張尺寸),\useasboundingbox (current bounding box)圖片就會具有所需的尺寸。

此外,還需要一個空白subfigure以允許向左重疊。所以它必須是第一個。當然,必須調整左側(現在是中間)子圖的寬度。

\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}

答案2

這是一個比我原來的(相對)簡單的答案(相對)不那麼簡單的方法,它更靈活一些,並且經過了更好的測試。它需要etoolboxxparse。 (如果需要的話,您可以輕鬆地放棄後者,但這很方便。)

  • 正如我所設定的,這會修改所有tikzpicture環境。

    • 如果需要的話,可以將其擴展為包含\tikz巨集。

    • 如果全域影響是不可取的,請刪除定義並僅在 的可選參數中every picture使用。mark outtikzpicture

  • 它允許調整左側、右側、兩側或兩者都不調整的材料。

基於 MWE 的簡單情況的唯一要求是在圖片中要標記用於放置標題\tikzmarkerwest的圖片部分左側的位置處插入。\caption如果您在圖片中完全不使用宏,則當圖片完成時,程式碼只會退回到圖片邊界框的左側。這發生在subfigure範例中的第二個。

第一個代碼subfigure被重新排列,以便所有\caption應該忽略的內容都出現在圖片的第一部分之後。\tikzmarkerwest然後插入以標記此時的左側。

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

這就是我們想要\caption用於放置的所有內容,因此現在標記圖片的左側。

      \tikzmarkerwest

現在我們將這些內容放在該點的左側,該點\caption應該被忽略。

      \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}

調整後的標題

對於右側的材料,\tikzmarkereast可以使用 代替 或 以及\tikzmarkerwest

在某些情況下,以這種方式重新排列圖片中的程式碼是不方便或不可能的。它只是不能輕易地按照所需的順序繪製(如果有的話)。為此,\tikzmarkereast\tikzmarkerwest支援可選參數。如果指定,這應該是圓括號中的座標,就像通常的座標一樣。在這種情況下,放置標題時,指定座標右側或左側的所有內容都將被忽略。

支援此功能的程式碼定義巨集\tikzmarkerwest如下。

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

這會(tikz marker west)在適當的位置創建一個座標。然後它會確保\tikzmarkerwestdefault沒有成功執行任何操作。

\tikzmarkereast以同樣的方式定義。

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

我們確定\tikzmarkerwestdefault並被\tikzmarkereast定義。預設情況下,它們不執行任何操作。

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

現在對於鈦kZ 代碼。

\tikzset{%

此樣式mark out會新增要在目前圖片的開頭和結尾執行的程式碼(如果在環境的可選參數中給出)或所有圖片的開頭和結尾(如果配置如下)。

  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);
      }%
    },

這重新定義了\tikzmarkerwestdefault和巨集以在當前邊界框的左側和右側\tikzmarkereastdefault建立座標(tikz marker west)和。(tikz marker east)這些只是定義,覆蓋預設的空定義。他們實際上還沒有創建任何座標。

    execute at end picture={%
      \tikzmarkerwestdefault
      \tikzmarkereastdefault

在圖片的最後,我們執行\tikzmarkerwestdefault.如果\tikzmarkerwest已在圖片中調用,則不會成功執行任何操作。否則,它將在當前邊界框的左側建立標記,這是圖片的最終邊界框。同樣對於\tikzmarkereastdefault.

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

這將計算當前邊界框左側x座標部分(tikz marker west)與座標部分之間的差異。x通常,這將為 0pt。但是,如果\tikzmarkerwest被調用,標記節點距當前邊界框左側的距離可能不為零。 (事實上,如果巨集已被調用,則可能是這種情況,因為這是使用巨集的唯一原因。)

(tikz marker east)現在我們對目前邊界框的 和 右側執行相同的操作。

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


  every picture/.style={mark out},

該行將該mark out樣式套用至所有 TikZ 圖片。如果這會導致問題,請將其刪除並添加mark out到您想要的圖片中。

}
\newlength\myadjustwest
\newlength\myadjusteast

確保\myadjustwest\myadjusteast無論如何都可用。

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

這會適應所有環境的末端tikzpicture以正確修改\caption。如果您使用它,您應該用對自己有意義的消息來代替OK!Oh, no!

以下範例集說明了基本的可能性。如果你想相對於一個陰影矩形放置標題,你不能(很容易)遮蔽它的一部分,然後是另一個部分,然後是另一個部分,適當地標記階段之間的邊界框。因此,對於這種情況,我們使用\tikzmarkerwest和/或 的可選參數\tikzmarkereast來獲取聚焦於可見光譜的紅端、藍端和中間位左側的字幕的位置。

對於紅軍來說...

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

對於布魯斯...

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

對於內臟...

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

調整可見光譜的標題

完整程式碼:

% 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}

答案3

首先,我沒有編輯我的第一個答案,因為它可能對某些人有用。

這個新答案計算標題的邊距。為此,前言中有一些宏。然後必須放置三個命令。他們都是沒有任何爭論的。

在圖片中,必須先繪製主要部分(即標題應居中的部分)。然後\pgfremembermainx必須插入。它設定座標來記住到目前為止最外面的 x 位置。之後,必須繪製與主要部分左側和右側重疊的部分。

必須將\end{tikzpicture}指令放置在最後、之前的位置。\pgfgetoverlap它計算兩側的重疊(相對於主要部分)並將其儲存在尺寸寄存器\overlapleft和中\overlapright。兩者都設置為全局,因此可以在tikzpicture.注意:\pgfgetoverlap計算重疊時不會考慮之後繪製的所有內容。

最後,在tikzpicture和標題之間設定邊距\captionsetmargins。它的影響是局部的,因為它在subfigure環境中。它不應該在環境之外使用,因為它會設定所有標題的邊距,因為[subfigure]這裡不能使用可選參數 ( )。當然,這只適用於圖片之後,因為重疊在圖片之前是未知的。

\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}

相關內容