Короткий ответ: всегда используйте 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) — 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