MATLAB - динамически изменять размер оси X, но не оси Y на графиках? - PullRequest
2 голосов
/ 10 сентября 2011

Я создаю сюжет в режиме реального времени.Я сдвигаю ось X на 30 секунд, каждые 30 секунд.Это все хорошо, но моя ось Y автоматически изменяет размеры до меньшей, чем раньше.Посмотрите ниже:

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

Это мои данные до того, как мы наберем 30 секунд и перерисоваем метки оси X.Я просто строю график ±cos(t) прямо сейчас, поэтому мои пределы Y равны [-1 1].

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

Через 30 секунд я сдвигаю оси, чтобы начать просмотрсюжет генерируют на временном интервале [30 60].Обратите внимание, что мои пределы Y изменились до [-0,8 0,5].По мере увеличения времени пределы возвращаются к [-1 1].Но я хотел бы иметь преемственность между предыдущим 30-секундным снимком и текущим моментальным снимком во времени, т. Е. Пределы должны быть [-1 1] сразу после достижения 30-секундного порога.

Есть ли способ сохранитьпредыдущие пределы Y и все еще позволяют им расти должным образом (т. е. если данные Y превышают пределы, они автоматически изменят свой размер соответственно) *

Ответы [ 3 ]

1 голос
/ 10 сентября 2011

Пределы оси Y будут автоматически масштабироваться, если YLimMode оси установлено на auto. Установите значение manual, чтобы предотвратить это:

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

Для того чтобы пределы обновлялись автоматически до соответствующих значений при обновлении данных на графике, вы можете прослушивать обновления строки, используя прослушиватель событий . При таком подходе требуется обновить построенную линию, обновив свойства линии XData и YData. Создайте линию и слушателя:

>> 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
1 голос
/ 23 октября 2011

Если вы все еще заинтересованы в проблеме, рассмотрите следующий пример.

В основном мы поддерживаем буфер значений, используемый для установки данных строк на каждой итерации. Мы отключаем автоматические ограничения осей и вместо этого обновляем их сами, только когда это необходимо.

Полученная анимация быстрая и отзывчивая (я фактически замедлил ее с помощью небольшой ПАУЗЫ), тем более что мы поддерживаем значения только для видимой части строк (мы просто отбрасываем / перезаписываем старые значения).

Я использую два одномерных сигнала случайного блуждания вместо функций косинуса. Ожидается, что эти последовательности будут расти в обоих направлениях, а ось постоянно корректирует свои пределы. Код может быть легко изменен для отображения более двух сигналов.

%# 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

1 голос
/ 10 сентября 2011

Это может быть не "автоматически", как вы думаете, но я бы сделал что-то вроде этого.

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 каждый раз, когда вы выводите новые данные.

...