当使用 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 south
at={(.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}