Как обновить данные графика в Matlab?

Предположим, что я хочу обновить график новыми данными. Какой метод выбрать?

  1. Задайте для свойства XDataSource какое-либо имя, обновите переменную и вызовите refreshdata
  2. Сотрите исходный plot и снова вызовите команду plot.
  3. Используйте Set('Xdata',...')

person Andrey Rubshtein    schedule 27.10.2012    source источник
comment
Связано: Сюжет в реальном времени в Matlab   -  person gnovice    schedule 22.12.2016


Ответы (3)


Короткий ответ: всегда используйте Set('Xdata',...').

Пример кода:

function PlotUpdate()   
    x = 0:.1:8;
    y = sin(x);
    h = plot(x,y);
    y = sin(x.^3);    
    set(h,'XData',x,'YData',y);
end

Длинный ответ:

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

  1. Четкость кода. Насколько легко кому-то прочитать ваш код?
  2. Время выполнения. Насколько быстро каждый метод выполняет свою задачу?
  3. Переносимость кода. Как быстро вы сможете реорганизовать свой код?

Теперь разберем возможные методы.

Метод (1) — обновить данные

function PlotUpdate()   
    x = 0:.1:8;
    y = sin(x);
    h = plot(x,y);
    set(h,'YDataSource','y')
    set(h,'XDataSource','x')
    y = sin(x.^3);
    refreshdata(h,'caller');
end

M-lint сразу выдает предупреждение в строке y=sin(x.^3)

The value assigned to variable `y` might be unused

Почему это происходит? refreshdata использует eval, а m-lint не может знать, что вы будете использовать y. Кто-то, читающий ваш код, может полностью удалить эту строку. Это произошло потому, что вы нарушили принцип инкапсуляции. refreshdata обращается к переменным из рабочей области вызывающей стороны. Другой способ взглянуть на это, предположим, что вы передаете дескриптор графика другой функции. Читатель понятия не имеет, с какой стати вы написали y = sin(x.^3); и как это будет связано с обновлением сюжета.

Теперь давайте обсудим скорость/время работы. Взглянув на исходный код refreshdata, вы заметите два уродливых цикла for, которые проходят через все переменные графических дескрипторов в вашем пространстве. Вот первое:

% gather up all the objects to refresh
objs = {};
for k = 1:length(h)
  obj = h(k);
  objfields = fields(obj);
  for k2 = 1:length(objfields)
    % search for properties ending in DataSource
    if strncmpi(fliplr(objfields{k2}),'ecruoSataD',10)
      objs = {objs{:},obj, objfields{k2}};
    end
  end
end

Представьте, что у вас не один участок, а 100 участков и вы хотите обновить только первый. Это будет очень медленно, потому что для каждого из сюжетов вы пытаетесь найти тот, который вам нужен! (Я оставляю читателю упражнение, чтобы понять, что такое ecruoSataD и как оно используется.)

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

Вывод: сложно понять, сложно рефакторить, медленное выполнение


Метод (2) — удалить и заново построить

function PlotUpdate()   
    x = 0:.1:8;
    y = sin(x);
    h = plot(x,y);
    set(h,'YDataSource','y')
    set(h,'XDataSource','x')
    y = sin(x.^3);          
    delete(h);
    h = plot(x,y);    
end

Этот метод вполне понятен читателю. Вы удалили сюжет, и нарисовали новый. Однако, как мы увидим из сравнения времени в конце, это самый медленный метод.

Заключение. Простота понимания, легкость рефакторинга, очень медленное выполнение


Метод(3) — set('XData',...,'YData')

Код действительно понятен. Вы хотите изменить два свойства вашего графика, XData и YData. И это именно то, что вы делаете. Кроме того, код работает очень быстро, как видно из сравнения ниже.

function PlotUpdate()   
    x = 0:.1:8;
    y = sin(x);
    h = plot(x,y);
    y = sin(x.^3);          
    set(h,'XData',x,'YData',y);
end

Начиная с нового графического движка hg2 (R2014b и выше), вы также можете использовать синтаксис свойств для указания данных, если вы предпочитаете это обозначение:

function PlotUpdate()   
    x = 0:.1:8;
    y = sin(x);
    h = plot(x,y);
    y = sin(x.^3);          
    h.XData = x;
    h.YData = y;
end

Заключение. Простота понимания, легкость рефакторинга, быстрая работа


Вот код сравнения времени

function PlotUpdateTimeCompare()    
    x = 0:.1:8;
    y = sin(x);
    h = plot(x,y);
    set(h,'YDataSource','y')
    set(h,'XDataSource','x')
    y = sin(x.^3);


    tic
    for i=1:100
        refreshdata(h,'caller');
    end
    toc 

    tic
    for i=1:100
        delete(h);
        h = plot(x,y);
    end
    toc     

    tic
    for i=1:100
        set(h,'XData',x,'YData',y);
    end
    toc 

end

И результаты:

Прошедшее время: 0,075515 секунд.
Прошедшее время: 0,179954 секунд.
Прошедшее время: 0,002820 секунд.

person Andrey Rubshtein    schedule 27.10.2012
comment
И вы можете добавить к методу (1), что refreshdata не работает в R2012b. - person MattLab; 28.10.2012
comment
@MattLab, спасибо за информацию. У меня не установлена ​​2012b. Можете ли вы привести пример или указать на какую-то ссылку? Вы также можете добавить этот факт в качестве еще одного ответа на вопрос. - person Andrey Rubshtein; 28.10.2012
comment
Хорошие моменты. Я исправил опечатку в "предпочтительном" коде - вы назвали set(h,'XDataSource',x), я думаю, опечатка при копировании. В первом фрагменте кода их нет. В противном случае я вижу вашу точку зрения. Хотя, с другой стороны, если у вас есть 100 графиков, которые вы хотите обновить, вызов refreshdata — это одна строка, а вызов set(h, ...) 100 раз после пересчета входных данных может быть немного утомительным. - person angainor; 29.10.2012
comment
Плюс: использовать set('XData') проще, чем refreshdata, когда вы хотите редактировать данные внутри обратного вызова. Единственное, что вам нужно найти (или кэшировать с помощью persistent), это графический дескриптор. У меня возникли проблемы с попыткой автоматически связать материал, и после переключения на XData все стало очень гладко. - person lemonzi; 12.11.2015
comment
h.XData = x; h.YData = y; на моей машине на самом деле на 33% быстрее, чем аналогичный set(h,'XData',x,'YData',y);. Я проверил в вашем сценарии, установка i = 1: 1000 дает общее время 0,058861 секунды против 0,088543 секунды. - person Lucademicus; 03.12.2019
comment
@Lucademicus, спасибо за информацию. Пост немного устарел, может быть, оптимизированы новые версии Matlab? - person Andrey Rubshtein; 04.12.2019

Вы можете вызвать функцию drawnow и сделать что-то вроде этого:

h = plot(nan);

for i = 1:n
  y = ...
  set(h,'YData',y);
  drawnow                 %update the graph
end
person R.Falque    schedule 26.07.2013

Предположим, что я хочу обновить график новыми данными. Какой метод выбрать?

Если у вас есть более одного линейного объекта в заданных осях, тогда метод:

  1. Задайте для свойства XDataSource какое-либо имя, обновите переменную и вызовите refreshdata

вызовет ошибку в MATLAB R2012b. Соответствующий пример приведен в ответе Андрея.

Ошибка была отправлена ​​​​в Mathworks.

person MattLab    schedule 29.10.2012