- 目标:我想旋转完整的 3D 图表(轴系统),同时保持“感知大小”不变。
- 我的当前版本(参见 MWE)原则上有效。
- 问题:问题在于图表一直在“改变大小”(它正在“呼吸”/“抽水”)。
- 问题:我怎样才能保持尺寸不变(从人类的角度来看)?
- 我想我几年前看到过一篇相关的帖子,但我没有找到它。
\documentclass{article}
\usepackage{pgfplots}
\pgfplotsset{compat=newest}
\usepackage{animate}
\begin{document}
\begin{animateinline}[controls]{20}
\multiframe{200}{rAngle=25+1}{
\begin{tikzpicture}
\begin{axis}[
view = {\rAngle}{30}, % <-- Rotate View
scale only axis,
unit vector ratio = 1 1 1,
]
\addplot3[surf, mesh/rows=3] coordinates {
(0,0,0) (1,0,0) (2,0,0) (3,0,0)
(0,1,0) (1,1,0.6) (2,1,0.7) (3,1,0.5)
(0,2,0) (1,2,0.7) (2,2,0.8) (3,2,0.5)
};
\end{axis}
\end{tikzpicture}
}
\end{animateinline}
\end{document}
答案1
Tikz 会自动计算图片中图形元素的边界框,从而确定其最终的整体大小。从不同角度观看时,投影在画布上的轴框的大小会发生变化,从而导致观察到的“抽吸”。
解决此问题的方法是放置一个图形对象,该对象在旋转时不会改变其在画布上的 2d 投影,并且包含绘图的所有部分。最适合此目的的是轴与旋转轴对齐的边界圆柱体。
边界圆柱隐藏 ( draw=none
):
图示气缸:
\documentclass[export]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=newest}
\usepackage{animate}
\begin{document}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% fix axes to these ranges (depending on the data to be plotted, of course)
\def\xmin{-0.2}
\def\xmax{3.2}
\def\ymin{-0.2}
\def\ymax{2.2}
\def\zmin{-0.2}
\def\zmax{1.2}
% bounding cylinder based on axes ranges with some scaling and z-offsets to also
% include tick labels
\def\scaleCylRadius{1.25}
\pgfmathsetmacro\cylCentreX{0.5*(\xmin+\xmax)}
\pgfmathsetmacro\cylCentreY{0.5*(\ymin+\ymax)}
\pgfmathsetmacro\cylRadius{\scaleCylRadius*sqrt((\xmax-\xmin)^2+(\ymax-\ymin)^2))/2}
\pgfmathsetmacro\cylZMin{\zmin - 0.02}
\pgfmathsetmacro\cylZMax{\zmax + 0.0}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{animateinline}[controls]{20}
\multiframe{60}{rAngle=25+6}{
\begin{tikzpicture}
\begin{axis}[
view = {\rAngle}{30}, % <-- Rotate View
unit vector ratio = 1 1 1,
trig format plots=rad,
xmin=\xmin,xmax=\xmax,
ymin=\ymin,ymax=\ymax,
zmin=\zmin,zmax=\zmax,
clip=false, % don't clip cylinder circles to axes ranges
]
% lower circle
\addplot3[
draw=none, % comment out to see cylinder circles
domain=0:2*pi,samples=60]({\cylCentreX+\cylRadius*sin(x)},{\cylCentreY+\cylRadius*cos(x)},\cylZMin);
% data
\addplot3[surf, mesh/rows=3] coordinates {
(0,0,0) (1,0,0) (2,0,0) (3,0,0)
(0,1,0) (1,1,0.6) (2,1,0.7) (3,1,0.5)
(0,2,0) (1,2,0.7) (2,2,0.8) (3,2,0.5)
};
% upper circle
\addplot3[
draw=none,
domain=0:2*pi,samples=60]({\cylCentreX+\cylRadius*sin(x)},{\cylCentreY+\cylRadius*cos(x)},\cylZMax);
\end{axis}
\end{tikzpicture}
}
\end{animateinline}
\end{document}
答案2
这让我想起:使用 tikz 在球体上绘制抛物线莫比乌斯地图
@Fritz 用旋转坐标系给出了答案。我不明白代码,但也许定义viewport
就是用于这个目的!?
这是我的初步尝试:
\documentclass{article}
\usepackage{animate}
\usepackage{pgfplots}
\pgfplotsset{compat=1.18}
\tikzset{viewport/.style 2 args={
x={({cos(-#1)*1cm},{sin(-#1)*sin(#2)*1cm})},
y={({-sin(-#1)*1cm},{cos(-#1)*sin(#2)*1cm})},
z={(0,{cos(#2)*1cm})}
}}
\begin{document}
\begin{animateinline}[controls]{20}
\multiframe{200}{rAngle=25+1}{
\begin{tikzpicture}
\useasboundingbox (0,0) circle[radius=4];
\begin{axis}[
view = {\rAngle}{30},
disabledatascaling,
anchor=origin,
viewport={\rAngle}{30},
]
\addplot3[surf, mesh/rows=3] coordinates {
(0,0,0) (1,0,0) (2,0,0) (3,0,0)
(0,1,0) (1,1,0.6) (2,1,0.7) (3,1,0.5)
(0,2,0) (1,2,0.7) (2,2,0.8) (3,2,0.5)
};
\end{axis}
\end{tikzpicture}
}
\end{animateinline}
\end{document}
所有框架都相互叠置:
需要进行更多的实验并理解代码。