在MATLAB中使用for循环绘制图形

3
我正在尝试使用for循环绘制简单的图表,如下所示。
x=linspace(0,2*pi,100);
for i=1:numel(x)
    y=sin(x(i));
    plot(x(i),y)
    hold on
end

然而,我的图表上没有任何显示。为什么呢?

我真的很感兴趣:你是从哪里得到这个想法来解决问题的?是在某个课程中学到的吗?还是在网上读到的?还是只是通过文档尝试了一些东西? - Dev-iL
嗯,我目前正在使用MatConvNet进行一些工作,并被要求绘制误差图表,该图表是在一个for循环中计算的,例如2000次迭代。这就是为什么我尝试上面的代码,因为当我尝试绘制误差图表时,它是空的。 - cathy305
通常在循环内部绘图是一个不好的想法(从性能角度来看),所以除非绝对没有其他方法,否则请尽量避免。更好的方法是首先计算出您想要绘制的任何内容,然后仅在之后调用 plot 一次。如果您知道将要进行多少次迭代,那么应该很容易分配一个大小为 numDataPoints * numIterations 的矩阵,然后仅为以后存储您的误差向量(除非您更喜欢仅存储一个值,例如 SSE 或 RMSE,在这种情况下,大小为 numIterations 的向量就足够了)。祝你好运! - Dev-iL
2个回答

4

为什么会发生这种情况...

使用plot(x(i),y),您正在绘制100个单独的点(每次迭代一个),默认情况下它们不会显示。因此,绘图看起来是空的。


解决方案1:向量化计算和直接绘图

我假设您想要绘制连续的线条。在这种情况下,不需要for循环,因为您可以直接在MATLAB中计算和绘制向量。因此,以下代码可能实现您的需求:

x = linspace(0,2*pi,100);
y = sin(x);
plot(x,y);

请注意,yx 一样是向量,并且对于所有的 ny(n) 等于 sin(x(n))。如果您想要绘制点本身,请在调用 plot 时使用LineSpec语法,像这样1:
plot(x,y,'*');

1) 还有其他类型的点,详见上述链接的文档。


解决方案2: 在for循环中计算数值并之后绘制

如果你想在for循环中计算数值并之后绘制:预分配所需变量(在这种情况下为y),在for循环中计算数值,最后在计算后用一个命令绘制它。

x = linspace(0,2*pi,100);

y = zeros(size(x));
for i = 1:numel(x)
    y(i) = sin(x(i));
end

plot(x,y);

解决方案3:在计算时动态更新绘图

如果您坚持要在每次迭代中绘制图形,则可以在解决方案2的基础上进行扩展:创建一个图形,向其中添加一个“空”绘图并存储其句柄。在for循环内部计算值并将其添加到y向量中,如上所示。作为最后一步,您可以通过更改其XDataYData属性并调用drawnow来更新绘图。请注意,在for循环内每次调用plot是不必要的昂贵操作,我不建议这样做。

% create figure and plot
figure;
ph = plot(0,0);
ax = gca;
set(ax,'XLim',[0,2*pi]);
set(ax,'YLim',[-1,1]);

% calculate and update plot
x = linspace(0,2*pi,100);
y = zeros(size(x));
for i = 1:numel(x)
    y(i) = sin(x(i));
    set(ph,'XData',x(1:i));
    set(ph,'YData',y(1:i));
    drawnow;
end

感谢您的回答,但我的意图是使用for循环来绘制图形。那么这是否意味着我不能使用for循环绘制连续线条? - cathy305
你最终想要实现什么?是在for循环中计算数值并创建一个图形吗?还是真的需要在每次迭代中绘制?如果是,为什么? - Matt
是的,我想绘制值,确切地说是在每次迭代中在 for 循环内计算的误差值,以显示随着 epoch 增加误差实际上正在减小,这意味着准确性正在提高。 - cathy305
@cathy305,我更新了我的回答,现在应该涵盖了所有可能性。 - Matt

2

简单的方法

如果你想在添加数据时绘制曲线,请尝试以下方法:

x = linspace(0,2 * pi, 100);
y = zeros(size(x));
for i=1:numel(x)
     y(i) = sin(x(i));
     plot(x(1:i), y(1:i), 'color', 'r')
     drawnow();
end

请注意,绘图自动尝试设置x和y限制(曲线缩放到绘图窗口),为了防止这种情况,您需要使用xlimylim手动设置x和y限制。

正如Matt在他的回答中所写的那样,在每次迭代中调用plot是非常昂贵的(即耗时的)。因此,我建议使用数据源:

使用数据源更新图形

% Create a panel and axes object
h_panel = uipanel;
h_axes = axes( 'Parent', h_panel);

% Create data sources
x = linspace(0,2 * pi, 100);
y = zeros(size(x));

% Create graph object, in this case stairs 
% and bind the variables x and y as its data sources
h_stairs = stairs(h_axes, x, y, 'XDataSource', 'x', 'YDataSource', 'y');

for i=1:size(x)
    y(i) = sin(x(i));
    % Update the data of the stairs graph
    refreshdata(h_stairs); 
    drawnow();
end

每次迭代中调用drawnow并非必须,它仅用于更新可视化效果,以便您可以直接看到更改。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接