Как мне обновить данные сюжета в Matlab?

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

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

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) - установить ('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 секунд.

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

h = plot(nan);

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

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

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

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

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

Ошибка была передана в Mathworks.

Другие вопросы по тегам