MATLAB.Exponenta
–Û·Ë͇ Matlab&Toolboxes

Приложения с GUI и дескрипторная графика

Обзор новшеств в дескрипторной графике и приложениях с GUI в 7-ой версии MATLAB

По сравнению с MATLAB 6.5, в 7-ой версии появился ряд новшеств, касающихся дескрипторной графики и создания приложений с графическим интерфейсом пользователя. В целом, изменилась иерархическая структура графических объектов, в которую добавились: базовые объекты (Core Objects), создаваемые низкоуровневыми графическими функциями, рисованные объекты (Plot Objects), которые получаются в результате работы высокоуровневых графических функций, и поясняющие объекты (Annotation Objects), т.е. разные стрелки, линии, надписи, которые создаются специальной функцией annotation. Кроме того, появилась возможность группировать объекты.

В следующих разделах дан обзор новых средств с простыми примерами их использования.

Новое в графике

Генерация кода (Code Generation) для восстановления графического окна

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

Например, при помощи команд

>> x = 0:0.2:10;
>> y = sin(x);
>> f = cos(x);
>> plot(x, y, x, f)

мы построили графики, а затем в редакторе графиков (для вызова которого надо в меню View графического окна выбрать пункт Property Editor) придали осям и их потомкам - линиям - следующий вид:

Для генерации файл-функции теперь следует выбрать в меню графического окна File пункт Generate M-File. Автоматически созданная файл-функция createfigure открывается в окне редактора m-файлов. Эту функцию можно сохранить для дальнейшего использования, причем или оставить то имя, которое предлагает MATLAB, или дать другое. Предположим, что она сохранена в файле createfigure.m. Рассмотрим ее структуру. После заголовка

function createfigure(x1, y1, y2)

идут комментарии (которые будут отображаться в командное окно при выполнении >> help createfigure) и комментарии с датой ее создания. Далее, при помощи низкоуровневой функции figure создается графическое окно

figure1 = figure('PaperPosition',[0.6345 6.345 20.3 15.23],'PaperSize',[20.98 29.68]);

с определенными значениями свойств PaperPosition и PaperSize, отвечающими за положение графического окна на листе и размеры листа (см. Свойства графических окон).

После создания графического окна создаются оси заданного цвета с сеткой по обеим координатным линиями (см. Свойства осей и Объект Axes (оси)).

%% Create axes
axes1 = axes('Color',[0.7569 0.8667 0.7765], 'XGrid','on', 'YGrid','on', 'Parent',figure1);

Для вывода нескольких линий на одни оси используется функция hold

hold(axes1,'all');

Далее, при помощи функции plot создаются две линии графиков функций заданной толщины и цвета, с маркерами определенных видов, размеров, и цветового оформления

%% Create plot
plot1 = plot(x1,y1, 'Color',[1 0 0], 'LineWidth',2, 'Marker','square', 'MarkerFaceColor',[1 1 1]);
 
%% Create plot
plot2 = plot(x1,y2, 'LineWidth',2, 'Marker','o', 'MarkerSize',8, 'MarkerEdgeColor',...
[0.1686 0.5059 0.3373], 'MarkerFaceColor',[1 1 0.4745]);

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

>> x = 0:0.2:5;
>> y = log(x+1);
>> f = log10(x+1);
>> createfigure(x, y, f)

Рассмотрим еще один способ использования сгенерированного m-файла createfigure.m. Если открыть этот файл в редакторе m-файлов, то можно заметить, что он содержит ячейки (cells). Каждая ячейка начинается с двойного знака комментария %%. Для того, чтобы выполнить ячейку, надо сделать ее текущей и нажать + (или воспользоваться пунктом Evaluate Current Cell в контекстном меню, или в меню Cell редактора m-файлов). При таком способе следует учесть, что переменные x1, y1 и y2 должны быть глобальными переменными рабочей среды.

В предыдущем примере была сгенерирована файл-функция, для реконструирования графиков двух функций, построенных при одинаковых значениях переменной x, поэтому она имела только три входных аргумента (первый - для x, второй и третий - для значений функций). Если бы мы строили графики функций по разным точкам, т.е.

>> x1=-10:0.1:10;
>> x2=-15:0.1:5;
>> f1=sin(x1);
>> f2=cos(x2);
>> plot(x1,f1,x2,f2)

то заголовок сгенерированной бы функции был такой

function createfigure(x1, y1, x2, y2)

и эту функцию надо было бы вызывать далее от четырех аргументов.

Рекомендуется использовать возможность генерирования файл-функции для воссоздания графиков, если число графических объектов не больше 20, иначе у нее будет очень много входных аргументов и ей будет неудобно пользоваться.

Не все графические функции поддерживают генерацию m-файла, например не удается сгенерировать файл-функцию для повторного получения графика, который был создан функцией pie.

Для автоматического создания m-файла используется функция makemcode, которая расположена в подкаталоге \toolbox\matlab\codetools\ корневого каталога MATLAB. Она относится к недокументированным, в справочной системе говорится, что в следующих версиях она может измениться. Основные варианты ее вызова перечислены ниже. В них предполагается, что H - указатель на некоторый графический объект, для которого вместе с его потомками следует сгенерировать восстанавливающую его функцию. Т.е. H может быть не только указателем на графическое окно, но и, например, на оси.

  • makemcode(H,'Output','-editor') - генерация m-файла для объекта с указателем H и отображение его в редакторе m-файлов.
  • str = makemcode(H,'Output','-string') - генерация m-файла для объекта с указателем H и сохранение его в строковой переменной str.
  • makemcode(H,'Output','c:\myfiles\mygraph.m') - генерация m-файла для объекта с указателем H и сохранение его в заданном файле.
  • makemcode(H,...,'ShowStatusBar', 0) генерация m-файла для объекта с указателем H без отображения полосы прогресса.

Связывание свойств графических объектов, функция linkprop

Предположим, что требуется при изменении какого-либо свойства графического объекта сразу же изменять такое же свойство другого объекта или нескольких объектов. Для реализации этой задачи подходит функция linkprop. В ее входных аргументах указывается вектор указателей на объекты и строка с названием свойства. Если требуется одновременно изменять несколько свойств, то их названия указываются в массиве ячеек (см. >> doc linkprop).

Рассмотрим пример, в котором есть два графических окна, в каждое из них выведен график поверхностей и требуется, чтобы поворот одной поверхности приводил к синхронному повороту другой. Для этого следует записать указатели на оси в вектор, в нашем примере это будет вектор hA, и вызвать функцию linkprop, указав свойство CameraPosition в качестве свойства с одинаковым значением.

figure
hA = [];
hA(1) = axes;
surf(peaks(20));
figure
hA(2) = axes;
surf(peaks(20));
LObj = linkprop(hA, 'CameraPosition')

Теперь поворот одной из поверхностей, например при помощи инструмента Rotate 3D графического окна, приведет к повороту другой поверхности. То же самое произойдет и при установке свойству CameraPosition одних из осей нового значения при помощи функции set:

set(hA(1), 'CameraPosition', [0.5 0.5 0.5])

Если требуется, чтобы поверхности не только одновременно поворачивались, но еще и можно было бы производить одновременное увеличение или уменьшение масштаба при помощи, скажем при помощи инструментов Zoom In и Zoom Out графического окна, то требуется также связать их свойства CameraTarget и CameraViewAngle. Как это сделать? Не нужно снова вызывать функцию linkprop, поскольку она уже создала связный объект LObj. Этот объект принадлежит классу graphics.linkprop, в чем несложно убедиться, вызвав функцию class (об объектно-ориентированном программировании см. в разделах справочной системы MATLAB: Programming: Classes and Objects и MATLAB: Functions Categorical List: Programming and Data Types: Programming in MATLAB):

>> class(LObj)
ans =
graphics.linkprop

Для того, чтобы узнать методы, которые можно применить к объекту, следует использовать функцию methods:

>> methods(LObj)
Methods for class graphics.linkprop:
addprop       addtarget     linkprop      removeprop    removetarget

Методы класса graphics.linkprop реализованы в функциях, которые находятся в подкаталоге \toolbox\matlab\graphics\@graphics\@linkprop\ основного каталога MATLAB.

Для добавления свойства, значение которого должно одновременно изменяться у объектов, применяемся метод addprop:

addprop(LObj, 'CameraTarget')
addprop(LObj, 'CameraViewAngle')

Теперь не только поворот, но и увеличение или уменьшение масштаба одной из поверхностей приведет к синхронному изменению масштаба другой поверхности.

Назначение остальныех методов таково.

  • addtarget(LObj, h) - добавление графического объекта с указателем h, свойства которого должны изменять значения одновременно с объектами, указанными в LObj.
  • removetarget(LObj, h) - отказ от изменения свойств графического объекта с указателем h вместе со свойствами графических объектов, указанных в LObj
  • removeprop(LObj, 'НазваниеСвойства') - добавление свойства значение которого должно одновременно изменяться для объектов, указанных в LObj.

При создании связного объекта функцией linkprop разумно сделать так, чтобы этот объект был доступен в той среде, где обрабатываются сами графические объекты. Рассмотрим простой пример приложения с графическим интерфейсом пользователя, окно которого выглядит следующим образом

Флаги ведут себя следующим образом:

  1. Если флаг All the same установлен, то установка или снятие любого из верхних флагов (Left, Center, Right) приводит к установке или снятию двух других.
  2. Если флаг All the same снят, то только флаги Left и Right ведут себя одинаково, а флаг Center можно ставить и убирать независимо от них.

Для этого при помощи linkprop создадим объект, в котором сначала все флаги Left, Center, Right будут согласованы, и запишем объект в поле структуры handles (получаемую при помощи функции guihandles), в которой хранятся указатели на объекты приложения. После этого сохраним структуру handles, вызвав функцию guidata. В функции обработки события Callback флага All the same проверяем значение флага. Если он снят, то удаляем флаг Center из связного объекта, а если установлен - то добавляем (см. раздел "Создание приложений с GUI без среды GUIDE").

function mygui
% Создание графического окна и флагов
hf = figure('Position',[500   200   200   70],'MenuBar','none','Tag','mainwin')
hcb1 = uicontrol('Style','checkbox','Position',[10 40 40 15],'String','Left','Tag','left')
hcb2 = uicontrol('Style','checkbox','Position',[55 40 70 15],'String','Center','Tag','center')
hcb3 = uicontrol('Style','checkbox','Position',[135 40 80 15],'String','Right','Tag','right')
hcb = uicontrol('Style','checkbox','Position',[10 10 90 15],'String','All the same','Value',1,...
    'Callback',@chbox_callback)
% Получение структуры с указателями на объекты приложения
handles = guihandles(hf);
% Создание связного объекта при помощи функции linkprop 
% и запись его в поле LObj структуры handles
handles.LObj = linkprop([hcb1 hcb2 hcb3],'Value')
% Сохранение структуры handles
guidata(hf,handles)

function chbox_callback(src,evt)
% Обработка события Callback флага All the same
% Получение структуры указателей
handles = guidata(src)
if get(src,'Value')
    %Флаг установлен, добавляем флаг Center в связный объект
    addtarget(handles.LObj, handles.center)
else
    %Флаг снят, исключаем флаг Center из связного объект
    removetarget(handles.LObj, handles.center)    
end
guidata(src,handles)

В этом примере можно было поступить и по-другому - создать связный объект и сохранить его в данных флага All the same. Тогда функции guihandles и guidata в основной функции mygui не нужны. В ней следовало бы использовать операторы:

LObj = linkprop([hcb1 hcb2 hcb3],'Value');
setappdata(hcb,'link',LObj)

а в подфункции chbox_callback обработки события Callback флага All the same достаточно было бы написать:

LObj=getappdata(src,'link')
handles=guihandles;
if get(src,'Value')
    addtarget(LObj,handles.center)
else
    removetarget(LObj,handles.center)    
end

Еще один пример использования связного объекта, создаваемого функцией linkprop, в котором применяется функция setappdata приведен в справочной системе MATLAB на странице с информацией о функции linkprop (>> doc linkprop).

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

Синхронизация пределов разных пар осей, функция linkaxes

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

Рассмотрим пример, в котором требуется на одних осях отобразить график функции, а на других - график ее производной. При изменении масштаба по оси x одного из графиков при помощи инструментов Zoom In и Zoom Out графического окна другой график должен менять масштаб по оси x совершенно аналогично. Создаем две пары осей, каждую со своим графиком, записываем указатели на них в вектор ha, который потом указываем в первом входном аргументе функции linkaxes. Во втором входном аргументе пишем 'x':

ha=[];
figure('Color','w')
ha(1) = subplot(2,1,1);
fplot('sin(1/x)',[0.05 1])
ha(2) = subplot(2,1,2);
fplot('-1/x^2*cos(1/x)',[0.05 1],'r')
linkaxes(ha,'x');

Функцию linkaxes можно использовать и для синхронизации осей ординат, или и абсцисс и ординат. Для этого следует вызвать ее со вторым входным аргументом 'y', или 'xy', соответственно. Для отмены синхронизации используется аргумент 'off'.

Новая опция команды hold

В 7-ой версии к опциями 'on' и 'off' команды hold добавилась новая опция, которая называется 'all'. Если для текущих осей выполнить

hold all

или для осей с указателем ha выполнить

hold(ha, 'all')

то при добавлении следующих графиков смена цветов и тип линий не будет начинаться сначала, как это было раньше при опции 'on', а будет продолжаться в том порядке, который записан в свойствах ColorOrder и LineStyleOrder осей. На следующих графиках показано, чем отличаются значения 'on' и 'all':

figure('Color','w')
axes
hold on
x=0:0.01:10;
for k=1:20
    y=k*sin(x);
    plot(x,y)
end
figure('Color','w')
axes
hold all
x=0:0.01:10;
for k=1:20
    y=k*sin(x);
    plot(x,y)
end

По умолчанию, значением свойства ColorOrder осей является матрица размера 7 на 3, которая задает семь разных цветов в формате RGB, а значением свойства LineStyleOrder является '-', т.е. все линии получаются сплошные. Если, например, требуется чередовать цвета и линии так, как показано на следующем рисунке:

т.е. красная сплошная - синяя сплошная - зеленая сплошная - красная пунктирная - синяя пунктирная - зеленая пунктирная - ...., то следует предварительно установить нужные значения свойствам ColorOrder и LineStyleOrder осей:

axes('ColorOrder', [1 0 0; 0 0 1; 0 1 0], 'LineStyleOrder', {'-';'--'});

Новые свойства осей

В 7-ой версии MATLAB появились три новых свойства осей:

ActivePositionProperty, которое может принимать значения 'outerposition' (по умолчанию), или 'position'. Если свойство ActivePositionProperty принимает значение 'position', то положение и размеры осей при изменении размеров графического окна определяются как и в предыдущей версии MATLAB, т.е. принимаются во внимание размеры и положение прямоугольной области осей, что может привести к выходу за границы окна подписей к осям, координатной разметки и заголовка. Если Если свойство ActivePositionProperty принимает значение 'outerposition', то размеры и положение осей определяются значением свойства OuterPosition, при изменении размеров графического окна подписи к осям, координатная разметка и заголовок всегда останутся в пределах окна.

OuterPosition - вектор из четырех чисел [left bottom width height], задающий координаты левого нижнего угла (left, bottom), ширину (width) и высоту (height) прямоугольной рамки, заключающей в себя оси, подписи к осям, заголовок и некоторые поля, которые являются значением свойства TightInset (доступного только для чтения).

TightInset - вектор из четырех чисел [left bottom right top], которые являются значениями левого, нижнего, правого и верхнего полей, добавляемых к значению свойства Position для получения значения OuterPosition.

На следующих двух рисунках показано различие в значениях 'outerposition' и 'position' свойства ActivePositionProperty при уменьшении размеров графического окна (на левом рисунке ActivePositionProperty установлено 'outerposition', а на правом - в 'position'):

Новые свойства графического окна - встраивание

Графические окна могут быть встроены в специальное окно или рабочую среду. За встраивание окна отвечает свойство WindowStyle. В более ранних версиях его значениями могли быть 'normal' (по умолчанию, обычное окно) и 'modal' (модальное окно, которое находится поверх остальных и перехватывает все события, т.е. для продолжения работы его требуется закрыть), то теперь появилось значение 'docked'. Если установить свойству WindowStyle графических окон значение 'docked', то они встраиваются в специальное окно:

h1=figure
fplot(@sin,[0 10])
set(h,'WindowStyle', 'docked')
h2=figure
fplot(@cos,[0 10])
set(h2,'WindowStyle', 'docked')

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

Свойство DockControls отвечает за наличие кнопок для встраивания в графическом окне. По умолчанию оно принимает значение 'on', т.е. кнопки для встраивания есть в верхнем правом углу под заголовком графического окна. Установка свойству DockControls значения 'off' приведет к тому, что кнопки пропадут и окно не сможет быть встроено. Однако, если создать графическое окно без кнопок встраивания, то потом его можно встроить, установив свойство WindowStyle графического окна в значение 'docked':

h3=figure('DockControls','off')
set(h3,'WindowStyle', 'docked')

При этом свойство DockControls автоматически получит значение 'on'. Если окно встроено, то установка DockControls в 'off ' приведет к ошибке:

set(h3,'DockControls','off')
??? Error using ==> set
Cannot set DockControls to 'off' while WindowStyle is 'docked'

Новые свойства графического окна - поддержка структуры с информацией о клавишах для KeyPressFcn

При обработке события KeyPressFcn графического окна можно узнать какие клавиши были нажаты и в каком сочетании со специальными. При возникновении этого события в функцию его обработки передается структура со следующими полями:

Character - символ, соответствующий сочетанию нажатых клавиш;
Modifier - структура, содержащая строки 'control', 'alt' или 'shift' (одну или несколько) в зависимости от того, какие были нажаты специальные клавиши;
Key - нажатая клавиша.

Следующее небольшое приложение mykey, окно которого выглядит так:

демонстрирует использование структуры при обработке события KeyPressFcn. В текстовой области отображаются значения полей структуры

function mykey
%создание окна приложения
h=figure('KeyPressFcn',@KeyPressFcn_callback, 'Position', [200 200 300 250])
%создание текстового объекта
uicontrol('Style','text','Tag','char','Position',[10 10 280 230],...
    'FontSize', 16, 'BackgroundColor', 'k', 'ForegroundColor', 'g')

function KeyPressFcn_callback(src,evt)
% функция обработки события KeyPressFcn
% формирование массива ячеек для вывода многострочного текста
% с информацией о значениях полей Character, Modifier и Key структуры evt
TEXT=[{'Character:'} {evt.Character} {'Modifier:'} evt.Modifier {'Key:'} {evt.Key}]; 
% вывод текста
handles=guihandles(src);
set(handles.char,'String',TEXT)

Усовершенствованная функция findobj

При поиске объектов при помощи функции findobj можно использовать логические операторы. Для этого к паре НазваниеСвойства-Значение добавляется логический оператор:

h = findobj('НазваниеСвойства', Значение, оператор,...)

где оператор может принимать одно из следующих значений:

-and - логическое И
-or - логическое ИЛИ
-xor - логическое исключающее ИЛИ
-not - логическое НЕ

Вот несколько примеров (см. также >> doc findobj)

% создаем четыре полигональных объекта с разными цветами границ и заливки
x=[-1 1 0]; 
y=[0 0 1];
figure;
hA=axes;
patch('XData', x, 'YData', y ,'EdgeColor','k', 'FaceColor', 'g')
patch('XData', 0.8*x, 'YData', 0.8*y ,'EdgeColor','k', 'FaceColor', 'b')
patch('XData', 0.6*x, 'YData', 0.6*y ,'EdgeColor','k', 'FaceColor', 'g')
patch('XData', 0.4*x, 'YData', 0.4*y ,'EdgeColor','r', 'FaceColor', 'y')

Среди осей и их потомков находим объекты с черной границей и зеленой заливкой

h=findobj(hA, 'EdgeColor','k','-and', 'FaceColor', 'g')

Среди осей и их потомков находим объекты с черной границей или зеленой заливкой

h=findobj(hA, 'EdgeColor','k','-or', 'FaceColor', 'g')

Среди осей и их потомков находим объекты с черной границей и не с синей

h=findobj(hA, 'EdgeColor','k','-and', '-not', 'FaceColor', 'b')

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

h=findobj(hA, '-not', {'FaceColor', 'b', '-or', 'FaceColor', 'g'}, '-and', 'Type', 'patch')

Поясняющие объекты (Annotation)

Поясняющие объекты (Annotation) создаются при помощи функции annotation. Тип создаваемого объекта указывается в первом входном аргументе функции. Возможные типы объекты и соответствующее значение входного аргумента функции annotation приведены в следующей таблице:

Тип объекта Входной аргумент функции annotation
линия 'line'
стрелка 'arrow'
двунаправленная стрелка 'doublearrow'
стрелка с текстовой подписью 'textarrow'
надпись 'textbox'
эллипс 'ellipse'
прямоугольник 'rectangle'

Функция annotation возвращает указатель на создаваемый объект. Последующие входные аргументы функции annotation определяются в зависимости от типа объекта. Если объект - линия или любой из типов стрелок, то достаточно указать два вектора x и y, тогда линия или стрелка проведутся от начальной точки (x(1),y(1)) до конечной (x(2),y(2)), например операторы:

figure
annotation('arrow',[0.2 0.7], [0.3 0.9])

создают стрелку в графическом окне, которая начинается в точке с координатами (0.2, 0.3) и заканчивается в точке с координатами (0.7, 0.9). Здесь берутся нормализованные единицы, т.е. считается, что левый нижний угол графического окна имеет координаты (0, 0), а правый верхний угол - координаты (1, 1).

Примечание. В результате работы функции annotation создается объект, который принадлежит классу scribe со своими методами. Объект размещается на невидимых осях, совпадающих по размеру с графическим окном.

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

h=annotation('ellipse',[0 0 1 1])

создает эллипс, полностью вписанный в графическое окно.

У одномерных поясняющих объектов (линий, стрелок) есть свойства, отвечающие за толщину, тип и цвет линии:

  • Color - один из предопределенных цветов 'r', 'g', 'b', 'c', 'm', 'y', 'k', 'w', или цвет в формате RGB
  • LineStyle - '-' (по умолчанию сплошная линия), '-' (штрихованная), ' :' (пунктир), '-.' (штрих-пунктир), 'none' (отсутствие линии)
  • LineWidth - толщина линии в пунктах

Использование этих свойств не отличается от соответствующих свойств, например базовых объектов линий (объект стрелка составлен из базовых объектов: линий и полигональных объектов). Например:

h=annotation('line',[0 1],[0 1])
set(h,'LineWidth',4,'Color','r')

создают красную линию толщины 4пт.

Функция annotation позволяет сразу задать значения свойствам при создании поясняющего объекта, например, при создании стрелки с текстовой подписью сразу можно ввести текст, воспользовавшись свойством 'String':

h=annotation('textarrow',[0.1 0.4],[0.1 0.7],'String','point N1')

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

  • HeadLength
  • HeadWidth
  • HeadStyle

Например:

h=annotation('arrow',[0 0.5],[0 0.6], 'HeadStyle', 'plain')

создает обычную стрелку с наконечником в виде треугольника. Все значения свойства HeadStyle можно посмотреть в справочной системе MATLAB в разделе Handle Graphics Property Browser. В правой части окна в иерархической структуре надо перейти к свойству осей, затем выбрать Annotation Objects и Arrow.

Для двунаправленных стрелок все практически аналогично, только вместо свойств HeadLength, HeadWidth и HeadStyle определены свойства Head1Length, Head1Width, Head1Style и Head2Length, Head2Width, Head2Style для начала и конца двунаправленной стрелки.

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

  • TextBackgroundColor - цвет фона текста, один из предопределенных цветов 'r', 'g', 'b', 'c', 'm', 'y', 'k', 'w', или цвет в формате RGB. По умолчанию 'none', т.е. заливки нет.
  • TextColor - цвет шрифта
  • TextEdgeColor - цвет рамки вокруг текста
  • TextLineWidth - толщина рамки вокруг текста в пунктах
  • TextMargin - величина полей в пикселях между рамкой и текстом
  • TextRotation - величина поворота текста в градусах против часовой стрелки например:
h=annotation('textarrow',[0.1 0.4],[0.1 0.7],'String','point N1',...
    'Color','r',...
    'TextBackgroundColor','y', 'TextColor','b','TextEdgeColor','g')

Следующие свойства позволяют задать шрифт, размер, начертание и выравнивание (см. свойства текстовых объектов в разделе Текстовый объект, вывод текста и математических формул в графическое окно):

  • FontName - строка с названием шрифта
  • FontSize - размер шрифта в пунктах
  • FontWeight - 'normal' (обычный, по умолчанию), 'bold' (жирный).
  • VerticalAlignment - выравнивание текста по вертикали, значения: 'top', 'cap', 'middle' (по умолчанию), 'baseline'
  • HorizontalAlignment - выравнивание текста по горизонтали, значения: 'left' (по умолчанию), 'center', 'right'

Кроме этого, можно использовать средства TeX и LaTeX как и для текстового объекта (см. Вывод математических формул, смена шрифта и начертания).

Для прямоугольника и эллипса свойств немного:

  • EdgeColor - цвет границы
  • FaceColor - цвет внутренности
  • LineStyle - тип линии
  • LineWidth - толщина линии в пунктах
Для надписи добавляются свойства, отвечающие за форматирование текста и прозрачность:

  • BackgroundColor - цвет фона текста
  • EdgeColor - цвет границы
  • FaceAlpha - прозрачность фона, задаваемая числом от 0 (полностью прозрачный) до 1 (полностью невидимый)
  • FitHeightToText - 'on' (использовать автоматический подбор высоты надписи для длинного текста), 'off' (по умолчанию, не использовать автоматический подбор высоты)
  • FontAngle - начертание, 'normal' (по умолчанию, прямой), 'italic' (курсив)
  • FontName - строка с названием шрифта
  • FontSize FontSize - размер шрифта в пунктах
  • FontWeight - начертание, 'normal' (обычный, по умолчанию), 'bold' (жирный).
  • HorizontalAlignment - выравнивание текста по горизонтали, значения: 'left' (по умолчанию), 'center', 'right'
  • Interpreter - использование интерпретаторов TeX или LaTeX, значения 'tex' (по умолчанию использовать интерпретатор TeX), 'latex' (использовать интерпретатор LaTeX), 'none' (интерпретировать команды TeX и LaTeX как обычный текст)
  • LineStyle '-' (по умолчанию сплошная линия), '-' (штрихованная), ' :' (пунктир), '-.' (штрих-пунктир), 'none' (отсутствие линии)
  • LineWidth - толщина линии в пунктах
  • Margin - поля вокруг текста, задаются в пунктах.
  • VerticalAlignment - выравнивание текста по вертикали, значения: 'top', 'cap', 'middle' (по умолчанию), 'baseline'

Группировка объектов

В 7-ой версии появились два новых группированных объекта: Hggroup и Hgtransform, которые по иерархии принадлежат осям. Их потомками могут быть любые потомки осей, т.е. базовые объекты, рисованные объекты и поясняющие объекты. Объект Hggroup позволяет сделать всех его потомков одновременно видимыми или невидимыми, выделить сразу всю группу щелчком мыши по одному из объектов группы, или сделать всю группу объектов текущей щелчком мыши по любому объекту, входящему в группу. Объект Hgtransform имеет смысл создавать, если к группе объектов должны применяться следующие преобразования: перемещение, изменение размеров или поворот. Сами группированные объекты так же могут быть потомками других группированных объектов.

Для создания группированного объекта Hggroup предназначена одноименная функция hggroup. При создании группированного объекта следует учесть, что его поведение зависит от значений свойства HitTest его потомков. Если свойство HitTest потомков группированного объекта Hggroup установлено в 'off', то возможно

  • выделять группированный объект щелчком мыши по одному из его потомков
  • делать объект Hggroup текущим щелчком мыши по одному из его потомков.

Установка свойства Visible объекта Hggroup в 'off' приводит к тому, что все объекты, являющиеся потомками объекта Hggroup становятся невидимыми.

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

function gdemo
% создание графического окна белого цвета и невидимых осей размером с окно
figure('Color','w')
axes('Visible','off','Position',[0 0 1 1])
% создание трех красных восьмиугольных полигональных объектов
t=linspace(0,2*pi,8)
x=sin(t); y=cos(t);
p(1)=patch(x,y,'r','HitTest','off') 
p(2)=patch(x*0.7,y*0.7,'r','HitTest','off') 
p(3)=patch(x*0.3,y*0.3,'r','HitTest','off') 
% создание группированного объекта и связывание его события ButtonDownFcn
% с подфункцией movegroup
hg=hggroup('ButtonDownFcn',@movegroup)
% задание потомками группированного объекта полигональныых объектов
set(p,'Parent',hg)

function movegroup(src,evt)
% подфункция обработки события ButtonDownFcn группированного объекта 
% узнаем указатели на потомков группированного объекта (полигональные объекты)
p=get(src,'Children')
% в цикле меняем их вершины и цвет случайным образом
for i=1:3
    set(p(i),'Xdata',rand(1,8), 'YData', rand(1,8),...
        'FaceColor',rand(1,3))
end

После запуска приложения gdemo

	>> gdemo

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

Рассмотрим теперь работу с группированным объектом Hgtransform. Предположим, что у нас есть три параллелепипеда, являющихся полигональными объектами, которые созданы при помощи функции patch. Требуется повернуть сразу три параллелепипеда вокруг оси y на 30o против часовой стрелки. Сначала создаем три параллелепипеда, используя свойства Vertices и Faces, в которых указываем матрицу координат каждой из восьми вершин и матрицу, задающую вершины каждой из шести граней:

figure('Color','w')
a=0.25;
V=[-1 1 -a; 1 1 -a; 1 -1 -a; -1 -1 -a;...
   -1 1 a;  1 1 a;  1 -1 a; -1 -1 a];
F=[1 2 3 4; 1 2 6 5; 3 7 6 2; 4 8 7 3; 4 1 5 8; 5 6 7 8];
hcube=[];
hcube(1)=patch('Vertices',V, 'Faces', F, 'FaceColor', 'r', 'FaceAlpha',0.8)
V(:,3)=V(:,3)+0.5
V(:,1:2)=V(:,1:2)*0.6
hcube(2)=patch('Vertices',V, 'Faces', F, 'FaceColor', 'g', 'FaceAlpha',0.8)
V(:,3)=V(:,3)+0.5
V(:,1:2)=V(:,1:2)*0.6
hcube(3)=patch('Vertices',V, 'Faces', F, 'FaceColor', 'y', 'FaceAlpha',0.8)

Устанавливаем трехмерный вид осей, делаем равный масштаб и подписываем оси

view(3)
axis equal
axis([-1.5,1.5,-1.5,1.5,-1.5,1.5]) 
xlabel('x');
ylabel('y');
zlabel('z');

В результате получается так, как изображено на левом рисунке (см. ниже). Теперь создаем группированный объект Hgtransform

hgt=hgtransform;

и задаем в качестве его потомков полигональные объекты

set(hcube,'Parent',hgt)

Поворот вокруг оси задается квадратной матрицей размера четыре, например для поворота вокруг оси y на угол следует использовать матрицу

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

M = makehgtform('yrotate',deg2rad(-30))
M =
    0.8660         0   -0.5000         0
         0    1.0000         0         0
    0.5000         0    0.8660         0
         0         0         0    1.0000

Нужная матрица создана, осталось установить свойству Matrix группированного объекта значение матрицы преобразования

set(hgt, 'Matrix', M)

Результат приведен на среднем рисунке (см. ниже), на который добавлен заголовок

title('M = makehgtform(''yrotate'',deg2rad(-30))', 'FontSize',14)

Для отмены преобразований достаточно установить единичную матрицу размера четыре на четыре в качестве значения свойства Matrix группированного объекта:

M = eye(4)
set(hgt,'Matrix',M)
title('M = eye(4)', 'FontSize',14)

В результате все преобразования отменяются и потомки группированного объекта приобретают первоначальное положение (см. правый рисунок выше).

Другие возможные преобразования, соответствующие им матрицы и основные обращения к функции makehgtform приведены ниже.

Перенос вдоль осей
M = makehgtform('translate',[tx ty tz]) или M = makehgtform('translate',tx,ty,tz) - возвращает матрицу переноса на tx вдоль оси x, на ty вдоль оси y и на tz вдоль оси z. Матрица имеет вид

Пропорциональное изменение размеров
M = makehgtform('scale',s) - возвращает матрицу пропорционального изменения размеров на величину s. Матрица изменения размеров имеет вид

Произвольное изменение размеров M = makehgtform('scale',[sx,sy,sz]) ) - возвращает матрицу произвольного изменения размеров вдоль оси x на величину sx, вдоль оси y на величину sy, вдоль оси z на величину sz. Матрица имзенения размеров имеет вид

Повороты вокруг осей M = makehgtform('xrotate',thetax) - поворот вокруг оси x на thetax радиан. Матрица поворота имеет вид

M = makehgtform('yrotate', thetay) - поворот вокруг оси y на thetay радиан. Матрица поворота имеет вид

M = makehgtform('zrotate', thetaz) - поворот вокруг оси z на thetaz радиан. Матрица поворота имеет вид

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

  • повернуть объект вокруг оси y на -10o
  • перенести объект: вдоль оси x на 0.2, вдоль оси y на 0.4, вдоль оси z на 0.1
  • изменить размеры: вдоль оси x увеличить в 1.2 раза, вдоль оси y увеличить в 1.4 раза, вдоль оси z уменьшить в 2 раза
  • повернуть вдоль оси z на 20o

Составляем соответствующие матрицы

My = makehgtform('yrotate',deg2rad(-10))
Mt=  makehgtform('translate',[0.2 0.4 0.1])
Ms=makehgtform('scale',[1.2 1.4 0.5])
Mz = makehgtform('zrotate',deg2rad(20))

и формируем матрицу преобразования, помножая слева матрицу первого преобразования на матрицу каждого следующего преобразования

M=Mz*Ms*Mt*My
set(hgt,'Matrix',M)

Получаем следующую матрицу преобразования

M =
    1.1105   -0.4788   -0.1958    0.0340
    0.4042    1.3156   -0.0713    0.6083
    0.0868         0    0.4924    0.0500
         0         0         0    1.0000

и соответствующий вид объектов (см. левый рисунок ниже)

Неверное указание матриц при перемножении

M=My*Mt*Ms*Mz
set(hgt,'Matrix',M)
M =
    1.1105   -0.4042   -0.0868    0.1796
    0.4788    1.3156         0    0.4000
    0.1958   -0.0713    0.4924    0.1332
         0         0         0    1.0000

приведет к другой матрице и результату, который показан на правом рисунке выше, поскольку матричное умножение некоммутативно, т.е. в общем случае для матриц A и B:


Поиск по сайту:

Система Orphus

Яндекс.Метрика