单独初始化和显示绘图
Separate initialization and display of plot
在 Matlab 中将绘图的初始化和显示分开的正确方法是什么? (我指的是广义上的 plots;可以是 plot
、plot3
、scatter
等)举一个具体的例子,我有一个非常复杂的 3D 可视化,它使用 sphere
和 mesh
绘制静态球体网格,然后 scatter3
在球体上绘制移动轨迹。为了能够实时执行此操作,我实施了一些简单的优化,例如每帧仅更新 scatter3
对象。但是代码有点乱,很难添加我想要的额外功能,所以我想改进代码分离。
我还觉得 return 函数中的某种绘图对象而不显示它有时可能很有用,例如以一种很好的模块化方式将其与其他绘图组合。
我想到的例子是这样的:
function frames = spherePlot(solution, options)
% Initialize sphere mesh and scatter objects, configure properties.
...
% Configure axes, maybe figure as well.
...
% Draw sphere.
...
if options.display
% Display figure.
end
for step = 1:solution.length
% Update scatter object, redraw, save frame.
% The frames are saved for use with 'movie' or 'VideoWriter'.
end
end
每个步骤也可以作为一个函数分离出来。
那么,做这样的事情的一种巧妙而正确的方法是什么?所有文档似乎都假设一个人想要立即显示所有内容。
例如
% some sample data
N = 100;
phi = linspace(-pi, pi, N);
theta = linspace(-pi, pi, N);
f = @(phi, theta) [sin(phi).*cos(theta); sin(phi).*sin(theta); cos(phi)];
data = f(phi, theta);
% init plot
figure(1); clf
plot3(data(1,:), data(2,:), data(3,:)); % plot path, not updated
hold on
p = plot3([0 data(1,1)], [0 data(2,1)], [0 data(3,1)]); % save handle to graphics objects to update
s = scatter3(data(1,1), data(2,1), data(3,1), 'filled');
axis equal
xlabel('x'); ylabel('y'); zlabel('z');
t = title('first frame'); % also store handle for title or labels to update during animation
% now animate the figure
for k = 1:N
p.XData = [0 data(1,k)]; % update line data
p.YData = [0 data(2,k)];
p.ZData = [0 data(3,k)];
s.XData = data(1,k); % update scatter data
s.YData = data(2,k);
s.ZData = data(3,k);
t.String = sprintf('frame %i', k); % update title
drawnow % update figure
end
基本上您可以更新图形句柄的所有值,在本例中为 'p' 和 's'。如果您打开 plot
or plot3
you will find a link to all properties of that primitive: e.g. Line Properties 的 matlab 文档。 scatter
/imagesc
等
存在类似的文档页面
所以一般的想法是首先用第一帧创建一个图形,保存你想要更新的对象的句柄 (p = plot(...
),然后进入一个循环,在这个循环中你更新所需的该图形对象的 属性(例如 p.Color = 'r'
或 p.XData = ...
)。
在 Matlab 中将绘图的初始化和显示分开的正确方法是什么? (我指的是广义上的 plots;可以是 plot
、plot3
、scatter
等)举一个具体的例子,我有一个非常复杂的 3D 可视化,它使用 sphere
和 mesh
绘制静态球体网格,然后 scatter3
在球体上绘制移动轨迹。为了能够实时执行此操作,我实施了一些简单的优化,例如每帧仅更新 scatter3
对象。但是代码有点乱,很难添加我想要的额外功能,所以我想改进代码分离。
我还觉得 return 函数中的某种绘图对象而不显示它有时可能很有用,例如以一种很好的模块化方式将其与其他绘图组合。
我想到的例子是这样的:
function frames = spherePlot(solution, options)
% Initialize sphere mesh and scatter objects, configure properties.
...
% Configure axes, maybe figure as well.
...
% Draw sphere.
...
if options.display
% Display figure.
end
for step = 1:solution.length
% Update scatter object, redraw, save frame.
% The frames are saved for use with 'movie' or 'VideoWriter'.
end
end
每个步骤也可以作为一个函数分离出来。
那么,做这样的事情的一种巧妙而正确的方法是什么?所有文档似乎都假设一个人想要立即显示所有内容。
例如
% some sample data
N = 100;
phi = linspace(-pi, pi, N);
theta = linspace(-pi, pi, N);
f = @(phi, theta) [sin(phi).*cos(theta); sin(phi).*sin(theta); cos(phi)];
data = f(phi, theta);
% init plot
figure(1); clf
plot3(data(1,:), data(2,:), data(3,:)); % plot path, not updated
hold on
p = plot3([0 data(1,1)], [0 data(2,1)], [0 data(3,1)]); % save handle to graphics objects to update
s = scatter3(data(1,1), data(2,1), data(3,1), 'filled');
axis equal
xlabel('x'); ylabel('y'); zlabel('z');
t = title('first frame'); % also store handle for title or labels to update during animation
% now animate the figure
for k = 1:N
p.XData = [0 data(1,k)]; % update line data
p.YData = [0 data(2,k)];
p.ZData = [0 data(3,k)];
s.XData = data(1,k); % update scatter data
s.YData = data(2,k);
s.ZData = data(3,k);
t.String = sprintf('frame %i', k); % update title
drawnow % update figure
end
基本上您可以更新图形句柄的所有值,在本例中为 'p' 和 's'。如果您打开 plot
or plot3
you will find a link to all properties of that primitive: e.g. Line Properties 的 matlab 文档。 scatter
/imagesc
等
所以一般的想法是首先用第一帧创建一个图形,保存你想要更新的对象的句柄 (p = plot(...
),然后进入一个循环,在这个循环中你更新所需的该图形对象的 属性(例如 p.Color = 'r'
或 p.XData = ...
)。