完整代码

完整代码

当使用 matlab2tikz 从 Matlab 生成 .tikz 时,图例位置设置为“SouthOutside”(图的 ylabel 下方),图例的位置将覆盖 ylabel,除非使用 tikzpicture 选项的“图例样式”参数中的“at={(0.5,-0.17)}”手动移动图例位置。这个问题在过去已经提出过在开发者的某个网页上。包 pgfplots 允许您使用我选择的变量“\figureheight”和“\figurewidth”轻松调整图形的宽度和高度,因此我认为我可以创建线性曲线拟合以将图例位置与图形高度关联起来。我可以做到这一点,但我不知道如何将变量“\figureheight”转换为可以按以下方式操作的值,其中此行将位于 MWE 中的位置:

at={(0.5,(0.0704*\figurewidth - 0.3572)}

由于 \figurewidth 以英寸为单位,我想知道是否有办法“剥离”单位并让其表现为双精度数,然后乘以 0.0704 并减去 0.3572 以下是该问题的 MWE:

\documentclass{article}

\usepackage{pgfplots}
\usepackage{amsmath}

\newlength\figureheight
\newlength\figurewidth

\begin{document}

\setlength\figureheight{2.0in} 
\setlength\figurewidth{2.0in}
\begin{figure}
    \begin{tikzpicture}
        \begin{axis}[
        width=\figurewidth,
        height=\figureheight,
        xlabel={x label text},
        ylabel={y label text},
        legend style={at={(0.5,-0.17)},anchor=north,legend cell align=left} %
        ]

        \addplot coordinates {(0,0) (1,1)};
        \addlegendentry{Legend Entry 1}

        \addplot coordinates {(0,1) (1,2)};
        \addlegendentry{Legend Entry 2}

        \end{axis}
    \end{tikzpicture}
    \caption{2" tall figure, x label covered} %
\end{figure}
%now with a larger figure, the xlabel will no longer be hidden
\setlength\figureheight{3.0in} 
\setlength\figurewidth{3.0in}
\begin{figure}
    \begin{tikzpicture}
        \begin{axis}[
        width=\figurewidth,
        height=\figureheight,
        xlabel={x label text},
        ylabel={y label text},
        legend style={at={(0.5,-0.17)},anchor=north,legend cell align=left} %
        ]

        \addplot coordinates {(0,0) (1,1)};
        \addlegendentry{Legend Entry 1}

        \addplot coordinates {(0,1) (1,2)};
        \addlegendentry{Legend Entry 2}

        \end{axis}
    \end{tikzpicture}
    \caption{3" tall figure, x label visible} %
\end{figure}

\end{document}

输出如下所示:

在此处输入图片描述

提前致谢!

Jake 提供的解决方案见下文以获得直接答案。这是经过修改的 matlab2tikz,可自动进行这些更改:与未修改的 matlab2tikz 相比,唯一的变化是当您set(hlegend,'Location','SouthOutside')在 Matlab 中时。我在三个部分中添加了代码:

靠近1200行:

withinif ~isempty(axisLabel)和 underif length(label) > 1声明:

m2t.axesContainers{end}.options = ...
            addToOptions(m2t.axesContainers{end}.options, ...
                        [axis, 'label style'], '{align=center}');
      end
        m2t.axesContainers{end}.options = ...%RESOLVE SOUTHOUTSIDE LEGEND ISSUES
            addToOptions(m2t.axesContainers{end}.options, ...%RESOLVE SOUTHOUTSIDE LEGEND ISSUES
            [axis, 'label style'], ['{name=' axis 'label}']);%RESOLVE SOUTHOUTSIDE LEGEND ISSUES

大约第 3622 行:

case 'southoutside'
          position = [0.5, -outside_dist];
          position_string='xlabel.south';%RESOLVE SOUTHOUTSIDE LEGEND ISSUES
          anchor = 'north';

大约第 3700 行:

% append to legend options
  if ~isempty(anchor) %RESOLVE SOUTHOUTSIDE LEGEND ISSUES
      if exist('position_string')%reference the xlabel so legend doesn't cover label when figure is scaled
          lStyle = {lStyle{:}, ...%RESOLVE SOUTHOUTSIDE LEGEND ISSUES
                sprintf('at={(%s)}', position_string), ...%RESOLVE SOUTHOUTSIDE LEGEND ISSUES
                sprintf('anchor=%s', anchor)};%RESOLVE SOUTHOUTSIDE LEGEND ISSUES
      else %hard code the leged position - works well for legends inside the axes
        lStyle = {lStyle{:}, ...
                sprintf('at={(%.15g,%.15g)}', position), ...
                sprintf('anchor=%s', anchor)};
      end
  end

答案1

基本上,您正在寻找的是密钥legend pos=outer south,但它尚不存在,正如 PGFPlots 开发人员在您链接到的论坛讨论。原因是要考虑轴下方是否有轴标题,这会影响图例的放置位置,这很复杂。但事实证明,其实并没有那么复杂:以下代码片段为 x 轴标签分配一个节点别名,然后使用来自的代码片段我如何知道某个节点是否已定义?legend pos/outer south代码中决定是否必须考虑轴标题:

\makeatletter
\pgfplotsset{
    every axis x label/.append style={
        alias=current axis xlabel
    },
    legend pos/outer south/.style={
        /pgfplots/legend style={
            at={%
                (%
                \@ifundefined{pgf@sh@ns@current axis xlabel}%
                {xticklabel cs:0.5}%
                {current axis xlabel.south}%
                )%
            },
            anchor=north
        }
    }
}
\makeatother

完整代码:

\documentclass{article}

\usepackage{pgfplots}
\usepackage{amsmath}

\makeatletter
\pgfplotsset{
    every axis x label/.append style={
        alias=current axis xlabel
    },
    legend pos/outer south/.style={
        /pgfplots/legend style={
            at={%
                (%
                \@ifundefined{pgf@sh@ns@current axis xlabel}%
                {xticklabel cs:0.5}%
                {current axis xlabel.south}%
                )%
            },
            anchor=north
        }
    }
}
\makeatother

\newlength\figureheight
\newlength\figurewidth

\begin{document}

\setlength\figureheight{2.0in} 
\setlength\figurewidth{2.0in}
\begin{figure}\centering
    \begin{tikzpicture}[trim axis left]
        \begin{axis}[
        width=\figurewidth,
        height=\figureheight,
        xlabel={x label text},
        ylabel={y label text},clip=false,
        legend pos=outer south
        ]

        \addplot coordinates {(0,0) (1,1)};
        \addlegendentry{Legend Entry 1}

        \addplot coordinates {(0,1) (1,2)};
        \addlegendentry{Legend Entry 2}
        \end{axis}
    \end{tikzpicture}
    \caption{2" tall figure, x label covered} %
\end{figure}
%now with a larger figure, the xlabel will no longer be hidden
\setlength\figureheight{3.0in} 
\setlength\figurewidth{3.0in}
\begin{figure}\centering
    \begin{tikzpicture}[trim axis left]
        \begin{axis}[
        width=\figurewidth,
        height=\figureheight,
        xlabel={x label text},
        ylabel={y label text},
        legend pos=outer south
        ]

        \addplot coordinates {(0,0) (1,1)};
        \addlegendentry{Legend Entry 1}

        \addplot coordinates {(0,1) (1,2)};
        \addlegendentry{Legend Entry 2}

        \end{axis}
    \end{tikzpicture}
    \caption{3" tall figure, x label visible} %
\end{figure}

\end{document}

或者,你可以将图例放置在相对于xlabel节点的位置,方法是先使用命名节点xlabel style={name=xlabel},然后使用legend style={ at={(xlabel.south)}, % Place legend relative to xlabel node yshift=-1ex, anchor=north }

这样,图例与 x 轴标签的距离将始终相同:

\documentclass{article}

\usepackage{pgfplots}
\usepackage{amsmath}

\newlength\figureheight
\newlength\figurewidth
\pgfplotsset{compat=newest}

\begin{document}

\setlength\figureheight{2.0in} 
\setlength\figurewidth{2.0in}
\begin{figure}
    \begin{tikzpicture}
        \begin{axis}[
        width=\figurewidth,
        height=\figureheight,
        xlabel={x label text},
        xlabel style={name=xlabel}, % Name the xlabel node
        ylabel={y label text},
        legend style={
                at={(xlabel.south)}, % Place legend relative to xlabel node
                yshift=-1ex,
                anchor=north,
                legend cell align=left
            } %
        ]

        \addplot coordinates {(0,0) (1,1)};
        \addlegendentry{Legend Entry 1}

        \addplot coordinates {(0,1) (1,2)};
        \addlegendentry{Legend Entry 2}

        \end{axis}
    \end{tikzpicture}
    \caption{2" tall figure, x label visible} %
\end{figure}
\setlength\figureheight{3.0in} 
\setlength\figurewidth{3.0in}
\begin{figure}
    \begin{tikzpicture}
        \begin{axis}[
        width=\figurewidth,
        height=\figureheight,
        xlabel={x label text},
        xlabel style={name=xlabel},
        ylabel={y label text},
        legend style={at={(xlabel.south)},yshift=-1ex, anchor=north,legend cell align=left} %
        ]

        \addplot coordinates {(0,0) (1,1)};
        \addlegendentry{Legend Entry 1}

        \addplot coordinates {(0,1) (1,2)};
        \addlegendentry{Legend Entry 2}

        \end{axis}
    \end{tikzpicture}
    \caption{3" tall figure, x label visible} %
\end{figure}

\end{document}

答案2

@Jack 的回答是一个很好的起点。一些小问题是:

  • 预定义选项legend pos使用.03.97和作为魔法数字。当不存在 xlabel/xtick 时,应产生1.03向后兼容的选项。outer southat={(.5,-.03)}
  • x 标签(如果有)不必放在底部。这取决于是否axis x line修改xtick pos了。
  • current axis xlabel.south没有必要放在正确的位置,尤其是当文本旋转时。

为了解决最后两个问题,可以使用current bounding box。例如

legend pos/outer south/.style={
    /pgfplots/legend style={
        at=({current bounding box.south-|.5,0}),
        anchor=north
    }
}

注意,axis环境被放在了 里面pgfinterruptboundingbox。因此current bounding box指的是axis本身,而不是 父tikzpicture


为了解决第一个问题,只需调用(.5,-.03),PGF 就会自动更新下限。例如

legend pos/outer south/.style={
    /pgfplots/legend style={
        /utils/exec={\pgfpathmoveto{\pgfpointxy{.5}{-.03}}},
        %/utils/exec={\useasboundingbox(.5,-.03);}, % same
        at=({current bounding box.south-|.5,0}),
        anchor=north
    }
}

完整代码

\documentclass{article}

\usepackage{pgfplots}
%\usetikzlibrary{fit}
\pgfplotsset{compat=1.14}

\begin{document}

%\tikz[inner sep=0]{
%   \path(0,0)node(A)[draw,rotate=-30]{node0,0}
%        (1,1)node(B)[draw,rotate=30]{node1,1};
%   \node[fit=(A)(B),draw]{};
%}
%
%
%\tikz[inner sep=0]{
%   \path(0,0)node(A)[draw,rotate=-30]{node0,0}
%        (1,1)node(B)[draw,rotate=30]{node1,1};
%   \draw(current bounding box.south west)rectangle(current bounding box.north east);
%}

\makeatletter
\pgfplotsset{
    every axis x label/.append style={
        alias=current axis xlabel
    },
    legend pos/outer south/.style={
        /pgfplots/legend style={
            /utils/exec={\pgfpathmoveto{\pgfpointxy{.5}{-.03}}},
            %/utils/exec={\useasboundingbox(.5,-.03);}, % same
            at=({current bounding box.south-|.5,0}),
            anchor=north,
            %/utils/exec={\draw(.5,-.03)circle(.03);}
        }
    }
}

\begin{tikzpicture}
    %\draw(-1,-1)--(8,7); % this does not effect (current bounding box) inside \begin{axis}
    \begin{axis}[
            legend pos=outer south,
            xlabel={x label text},
            %x tick label style={rotate=45}
        ]
        \addplot coordinates {(0,0) (1,1)};
        \addplot coordinates {(0,1) (1,2)};
        \addplot coordinates {(0,2) (1,3)};
        \legend{$l_1$,$l_2$,$l_3$}
    \end{axis}
\end{tikzpicture}

\vfill

\begin{tikzpicture}
    %\draw(-1,-1)--(8,7); % this does not effect (current bounding box) inside \begin{axis}
    \begin{axis}[
            legend pos=outer south,
            xlabel={x label text},
            xtick pos=right,
            %x label style={rotate=45}
        ]
        \addplot coordinates {(0,0) (1,1)};
        \addplot coordinates {(0,1) (1,2)};
        \addplot coordinates {(0,2) (1,3)};
        \legend{$l_1$,$l_2$,$l_3$}
    \end{axis}
\end{tikzpicture}

\clearpage





\pgfplotsset{
    legend pos/outer north east v2/.style={
        /pgfplots/legend style={
            /utils/exec={\pgfpathmoveto{\pgfpointxy{1.03}{1}}},
            at=(current bounding box.north east),
            anchor=north west
        }
    },
    legend pos/outer north east v3/.style={
        /pgfplots/legend style={
            /utils/exec={\pgfpathmoveto{\pgfpointxy{1.03}{1}}},
            at={(current bounding box.north east|-0,1)},
            anchor=north west
        }
    }
}

\begin{tikzpicture}
    \begin{axis}[title=original,
                 legend pos=outer north east,
                 ytick pos=right]
        \addplot coordinates {(0,0) (1,1)};
        \addplot coordinates {(0,1) (1,2)};
        \addplot coordinates {(0,2) (1,3)};
        \legend{$l_1$,$l_2$,$l_3$}
    \end{axis}
\end{tikzpicture}

\begin{tikzpicture}
    \begin{axis}[title=version 2,
                 legend pos=outer north east v2,
                 ytick pos=right]
        \addplot coordinates {(0,0) (1,1)};
        \addplot coordinates {(0,1) (1,2)};
        \addplot coordinates {(0,2) (1,3)};
        \legend{$l_1$,$l_2$,$l_3$}
    \end{axis}
\end{tikzpicture}

\begin{tikzpicture}
    \begin{axis}[title=version 3,
                 legend pos=outer north east v3,
                 ytick pos=right]
        \addplot coordinates {(0,0) (1,1)};
        \addplot coordinates {(0,1) (1,2)};
        \addplot coordinates {(0,2) (1,3)};
        \legend{$l_1$,$l_2$,$l_3$}
    \end{axis}
\end{tikzpicture}

\end{document}

相关内容