Как мне обновить данные сюжета в Matlab?
Предположим, что я хочу обновить сюжет новыми данными. Какой метод мне выбрать?
- Установить
XDataSource
свойство для некоторого имени, обновить переменную и вызватьrefreshdata
- Стереть оригинал
plot
и позвонитеplot
команда снова. - использование
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) - обновить данные
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
Предположим, что я хочу обновить сюжет новыми данными. Какой метод мне выбрать?
Если у вас есть более одного линейного объекта по заданным осям, то метод:
- Установите для свойства XDataSource какое-либо имя, обновите переменную и вызовите
refreshdata
сгенерирует ошибку в MATLAB R2012b. Соответствующий пример приведен в ответе Андрея.
Ошибка была передана в Mathworks.