MATLAB - 动态调整图中 x 轴但不调整 y 轴的大小?

发布于 2024-12-04 00:29:35 字数 549 浏览 0 评论 0原文

我正在实时生成一个情节。我每 30 秒将 x 轴移动 30 秒。这一切都很好,但我的 y 轴会自动调整大小,比以前更小。请看下面:

Plot before 30 秒阈值 - Y 限制为 [-1 1]

这是我们命中之前的数据30 秒并重新绘制 x 轴标签。我现在只是绘制 ±cos(t),所以我的 Y 限制是 [-1 1]。

30 秒阈值后 - Y 限制为 [-0.8 0.5]

30 秒后,我将轴移过来开始观看该图在时间间隔 [30 60] 上生成。请注意,我的 Y 限制已重新调整为 [-0.8 0.5]。随着时间的增加,限制将回到 [-1 1]。但我希望前一个 30 秒快照和当前快照之间在时间上保持连续性,即在达到 30 秒阈值后,限制应立即为 [-1 1]。

有没有办法保留之前的 Y 限制并仍然让它们正常增长(即,如果 Y 数据超过限制,它会自动适当调整大小)?

I am generating a plot in real-time. I shift the x-axis by 30 seconds, every 30 seconds. This is all well and good, but my y-axis is auto-resizing itself to smaller than previously. Take a look below:

Plot before 30 second threshold - Y limits are [-1 1]

This is my data before we hit the 30 seconds and redraw the x-axis labels. I'm just plotting ±cos(t) right now, so my Y limits are [-1 1].

After 30 second threshold -  Y limits are [-0.8 0.5]

After the 30 seconds, I shift the axes over to start watching the plot generate on the time interval [30 60]. Notice that my Y limits have rescaled to [-0.8 0.5]. As time increases, the limits go back to [-1 1]. But I would like to have continuity between the previous 30 second snapshot and the current snapshot in time, i.e., limits should be [-1 1] immediately after hit the 30 second threshold.

Is there a way to keep the previous Y limits and still let them grow properly (i.e., if Y data goes over limits it'll resize appropriately, automatically)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

梦屿孤独相伴 2024-12-11 00:29:35

如果轴的 YLimMode 设置为 auto,则 y 轴限制将自动重新缩放。将其设置为手动以防止出现这种情况:

>> set(gca, 'YLimMode', 'manual');

为了在绘图上的数据更新时将限制自动更新为适当的值,您可以使用 事件监听器。此方法要求您通过更新线的 XDataYData 属性来更新绘制的线。创建线路和侦听器:

>> h = line('XData', [], 'YData', []);
>> addlistener(h, 'YData', 'PostSet', @(src, evnt) set(evnt.AffectedObject.Parent, 'YLim', [min(evnt.AffectedObject.YData) max(evnt.AffectedObject.YData)]));

侦听器定义包括匿名函数它使用事件属性来访问线的父级(即轴)并将 y 轴限制设置为绘制的 y 值的最小值和最大值。当绘制线的 YData 属性更新时执行此函数。

要查看此操作的实际效果,请尝试以下操作:

>> x = 1;
>> y = cos(x);
>> for ii = 2:1000
x(end+1) = ii;
y(end+1) = cosd(x(end));
set(h, 'XData', x, 'YData', y);
pause(0.01);
end

The y-axis limits will rescale automatically if the YLimMode of the axis is set to auto. Set it to manual to prevent this:

>> set(gca, 'YLimMode', 'manual');

In order to have the limits update automatically to appropriate values when the data on the plot is updated you could listen for updates to the line using an event listener. This approach requires you to update the plotted line by updating the line's XData and YData properties. Create the line and listener:

>> h = line('XData', [], 'YData', []);
>> addlistener(h, 'YData', 'PostSet', @(src, evnt) set(evnt.AffectedObject.Parent, 'YLim', [min(evnt.AffectedObject.YData) max(evnt.AffectedObject.YData)]));

The listener definition includes an anonymous function that uses the event properties to access the line's parent (i.e. the axes) and set the y-axis limits to the minimum and maximum of the plotted y values. This function is executed when the YData property of the plotted line is updated.

To see this in action, try the following:

>> x = 1;
>> y = cos(x);
>> for ii = 2:1000
x(end+1) = ii;
y(end+1) = cosd(x(end));
set(h, 'XData', x, 'YData', y);
pause(0.01);
end
潇烟暮雨 2024-12-11 00:29:35

这可能不像你想的那样“自动”,但我会做这样的事情。

new_axes = function resize_axes(x_data, y_data, x_increment)

old_axes = axis();
new_axes = old_axes;
if max(x_data(:)) > old_axes(2)
    new_axes(2) = new_axes(2) + x_increment; # e.g., 30 seconds
    new_axes(1) = old_axes(2);  # if you want the new axes to start
                                #  where the old ones ended
end
if max(y_data(:)) > old_axes(4)
    new_axes(4) = max(y_data(:));
end
if min(y_data(:)) < old_axes(3)
    new_axes(3) = min(y_data(:));
end

axis(new_axes);

然后每当绘制新数据时调用 resize_axes 。

This may not be "automatic" like you're thinking, but I would do something like this.

new_axes = function resize_axes(x_data, y_data, x_increment)

old_axes = axis();
new_axes = old_axes;
if max(x_data(:)) > old_axes(2)
    new_axes(2) = new_axes(2) + x_increment; # e.g., 30 seconds
    new_axes(1) = old_axes(2);  # if you want the new axes to start
                                #  where the old ones ended
end
if max(y_data(:)) > old_axes(4)
    new_axes(4) = max(y_data(:));
end
if min(y_data(:)) < old_axes(3)
    new_axes(3) = min(y_data(:));
end

axis(new_axes);

Then call resize_axes whenever you plot new data.

爱给你人给你 2024-12-11 00:29:35

如果您仍然对这个问题感兴趣,请考虑以下示例。

基本上,我们维护一个值缓冲区,用于设置每次迭代的行数据。我们关闭自动轴限制,而是仅在必要时自行更新它们。

生成的动画快速且响应灵敏(实际上我通过一个小暂停减慢了它的速度),特别是因为我们只维护线条可见部分的值(我们只是丢弃/覆盖旧值)。

我使用两个一维随机游走信号而不是余弦函数。这些序列预计将在两个方向上不断增长,轴不断调整其极限。可以轻松更改代码以绘制两个以上的信号。

%# setup axis and lines
N = 60;             %# window size (60 sec)
XLIMS = [1 N];      %# starting axis limits
YLIMS = [-1 1];
hAx = axes('XLim',XLIMS, 'YLim',YLIMS, 'Box','on', ...
    'YLimMode','manual', 'XLimMode','manual');
hLine1 = line('XData',1:N, 'YData',nan, 'Color','b', ...
    'Parent',hAx, 'YLimInclude','off');
hLine2 = line('XData',1:N, 'YData',nan, 'Color','r', ...
    'Parent',hAx, 'YLimInclude','off');

%# initialize vectors
y1 = nan(N,1);
y2 = nan(N,1);
ind = 1;
val1 = 0; val2 = 0;

while true
    %# get new values, and insert them in vectors
    val1 = val1 + (rand-0.5);
    val2 = val2 + (rand-0.5);
    y1(ind) = val1;
    y2(ind) = val2;

    %# update lines data
    set(hLine1, 'YData',y1)
    set(hLine2, 'YData',y2)

    %# keep track of smallest/largest values seen
    mn = min(val1,val2); mx = max(val1,val2);
    if mn<YLIMS(1), YLIMS(1) = mn; flag = true; end
    if mx>YLIMS(2), YLIMS(2) = mx; flag = true; end

    %# update axis Y-limits if needed
    if flag
        set(hAx, 'YLim',YLIMS); flag = false;
    end

    %# refresh plot
    drawnow, pause(0.02)

    %# circularly increment counter
    ind = ind + 1;
    if ind>N
        %# perparing for next cycle
        ind = 1;
        y1(:) = nan; y2(:) = nan;

        %# update axis x-limits and slide line x-data
        set(hAx, 'XLim',get(hAx,'XLim')+N);
        set(hLine1, 'XData',get(hLine1,'XData')+N);
        set(hLine2, 'XData',get(hLine2,'XData')+N);
    end

    %# break in case you close the figure
    if ~ishandle(hAx), break, end
end

屏幕截图

If you are still interested in the problem, then consider the following example.

Basically we maintain a buffer of values, used to set the lines data each iteration. We turn off automatic axis limits, and instead update them ourselves only when necessary.

The resulting animation is fast and responsive (I actually slowed it down with a small PAUSE), especially since we only maintain values for the visible portion of the lines (we simply discard/overwrite old values).

I am using two 1D random walk signals instead of cosine functions. These sequences are expected to keep growing in both directions, with the axis continuously adjusting its limits. The code can be easily changed to plot more than two signals.

%# setup axis and lines
N = 60;             %# window size (60 sec)
XLIMS = [1 N];      %# starting axis limits
YLIMS = [-1 1];
hAx = axes('XLim',XLIMS, 'YLim',YLIMS, 'Box','on', ...
    'YLimMode','manual', 'XLimMode','manual');
hLine1 = line('XData',1:N, 'YData',nan, 'Color','b', ...
    'Parent',hAx, 'YLimInclude','off');
hLine2 = line('XData',1:N, 'YData',nan, 'Color','r', ...
    'Parent',hAx, 'YLimInclude','off');

%# initialize vectors
y1 = nan(N,1);
y2 = nan(N,1);
ind = 1;
val1 = 0; val2 = 0;

while true
    %# get new values, and insert them in vectors
    val1 = val1 + (rand-0.5);
    val2 = val2 + (rand-0.5);
    y1(ind) = val1;
    y2(ind) = val2;

    %# update lines data
    set(hLine1, 'YData',y1)
    set(hLine2, 'YData',y2)

    %# keep track of smallest/largest values seen
    mn = min(val1,val2); mx = max(val1,val2);
    if mn<YLIMS(1), YLIMS(1) = mn; flag = true; end
    if mx>YLIMS(2), YLIMS(2) = mx; flag = true; end

    %# update axis Y-limits if needed
    if flag
        set(hAx, 'YLim',YLIMS); flag = false;
    end

    %# refresh plot
    drawnow, pause(0.02)

    %# circularly increment counter
    ind = ind + 1;
    if ind>N
        %# perparing for next cycle
        ind = 1;
        y1(:) = nan; y2(:) = nan;

        %# update axis x-limits and slide line x-data
        set(hAx, 'XLim',get(hAx,'XLim')+N);
        set(hLine1, 'XData',get(hLine1,'XData')+N);
        set(hLine2, 'XData',get(hLine2,'XData')+N);
    end

    %# break in case you close the figure
    if ~ishandle(hAx), break, end
end

screenshot

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文