matlab dualcursor,李洋:Matlab数据游标(dualcursor)动态展示

本文详细介绍了如何使用Matlab的数据游标dualcursor进行动态展示,包括设置颜色、标记、处理默认值以及添加交互式功能如数据导出。通过实例展示了如何添加和操作数据游标,以及与图形元素的交互,为Matlab用户提供了直观的数据分析工具。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

for ii=1:length(marker_color)

col_ind = strfind(colors,marker_color(ii));

if ~isempty(col_ind) %It's a color

color = marker_color(ii);

else %Try a marker instead

mark_ind = strfind(markers,marker_color(ii));

if ~isempty(mark_ind)

marker = marker_color(ii);

end;

end;

end;

end;

%Handle default marker and color

if ~exist('color','var'), color = 'r'; end; %set default

if ~exist('marker','var'), marker = '*'; end; %set default

%Add the cursors.

%Ideally, the user specified the 2 x coordinates.

%If not, just put the cursors somewhere nice.

lineh = local_findlines(axh);

%Line data

if isempty(lineh)

x1 = 0;

y1 = 0;

% erasemode = 'normal'; %default

else

%if multiple lines, define callback to allow for selection

set(lineh,'ButtonDownFcn', ...

'setappdata(get(gco,''Parent''),''SelectedLine'',gco);dualcursor(''selectline'',[],[],[],get(gco,''Parent''))');

%set erasemode to xor. This speeds things up a ton with large data sets

% erasemode = get(lineh,'EraseMode');

% set(lineh,'EraseMode','xor');

lineh = min(lineh); %Lets just use one line. This was probably added first

setappdata(axh,'SelectedLine',lineh); %The currently selected line.

%Why the last line? Because it is the first one added

xl = get(lineh,'XData');

yl = get(lineh,'YData');

end;

%Find nearest value on the line

[xv1,yv1] = local_nearest(x_init(1),xl,yl);

[xv2,yv2] = local_nearest(x_init(2),xl,yl);

%Build the string for the data label

textstring1 = feval(datalabelformatfcnh,xv1,yv1);

textstring2 = feval(datalabelformatfcnh,xv2,yv2);

%Add the data label

th1 = text(xv1,yv1,textstring1,'FontSize',8,'Tag','CursorText','Parent',axh);

th2 = text(xv2,yv2,textstring2,'FontSize',8,'Tag','CursorText','Parent',axh);

%For R13 or higher (MATLAB 6.5), use a background color on the text string

v=ver('MATLAB');

v=str2num(v.Version(1:3));

if v>=6.5

set(th1,'BackgroundColor','y');

set(th2,'BackgroundColor','y');

end;

yl = ylim(axh);

lim = localObjbounds(axh);

lim = lim(3:4); %y values only

yl(isinf(yl)) = lim(isinf(yl));

%Add the cursors

ph1 = line([xv1 xv1 xv1],[yl(1) yv1 yl(2)], ...

'Color',color, ...

'Marker',marker, ...

'Tag','Cursor', ...

'UserData',[lineh th1], ...

'LineStyle','-', ...

'Parent',axh);

ph2 = line([xv2 xv2 xv2],[yl(1) yv2 yl(2)], ...

'Color',color, ...

'Marker',marker, ...

'Tag','Cursor', ...

'UserData',[lineh th2], ...

'LineStyle','-', ...

'Parent',axh);

%Add context menu to the cursors

% cmenu = uicontextmenu('Parent',get(axh,'Parent'));

cmenu = uicontextmenu('Parent',hFig);

set([ph1 ph2],'UIContextMenu',cmenu);

% Define the context menu items

item1 = uimenu(cmenu, 'Label', 'Export region to workspace', ...

'Callback', 'dualcursor(''exportws'',[],[],[],get(gco,''Parent''))');

item2 = uimenu(cmenu, 'Label', 'Export region to new figure', ...

'Callback', 'dualcursor(''exportfig'',[],[],[],get(gco,''Parent''))');

item3 = uimenu(cmenu, 'Label', 'Export cursor data to workspace', ...

'Callback', 'dualcursor(''exportcursor'',[],[],[],get(gco,''Parent''));');

item4 = uimenu(cmenu, 'Label', 'Turn cursors off', ...

'Callback', 'dualcursor(''off'',[],[],[],get(gco,''Parent''))', ...

'Separator','on');

setappdata(th1,'Coordinates',[xv1 yv1]);

setappdata(ph1,'Coordinates',[xv1 yv1]);

setappdata(th2,'Coordinates',[xv2 yv2]);

setappdata(ph2,'Coordinates',[xv2 yv2]);

setappdata(th1,'CursorNumber',1);

setappdata(ph1,'CursorNumber',1);

setappdata(th2,'CursorNumber',2);

setappdata(ph2,'CursorNumber',2);

setappdata(th1,'FormatFcnH',datalabelformatfcnh);

setappdata(th2,'FormatFcnH',datalabelformatfcnh);

setappdata(th1,'Offset',[0 0]); %Offset for the text label from the data value

setappdata(th2,'Offset',[0 0]); %Offset for the text label from the data value

% mh = uicontextmenu('Tag','DeleteObject', ...

% 'Callback','ud = get(gco,''UserData'');delete([gco ud(2)]);');

% set([th1 th2],'UIContextMenu',mh);

set(th1,'UserData',[lineh ph1]); %Store handle to line

set(th2,'UserData',[lineh ph2]); %Store handle to line

%Calculate Difference

dx = xv2 - xv1;

dy = yv2 - yv1;

%Add display for cursor deltas

deltah(1) = text(deltalabelpos(1,1),deltalabelpos(1,2),['({x}_{2}-{x}_{1}) = ' num2str(dx,'%+.2f')], ...

'Units','Normalized', ...

'HorizontalAlignment','left', ...

'Tag','CursorDeltaText', ...

'FontSize',8, ...

'Interpreter','tex', ...

'Parent',axh); %dx

deltah(2) = text(deltalabelpos(2,1),deltalabelpos(2,2),['{y}_{2}-{y}_{1} = ' num2str(dy,'%+.2f')], ...

'Units','Normalized', ...

'HorizontalAlignment','left', ...

'Tag','CursorDeltaText', ...

'FontSize',8, ...

'Interpreter','tex', ...

'Parent',axh); %dy

%Set Application Data.

setappdata(axh,'Delta_Handle',deltah);

setappdata(axh,'Marker',marker);

setappdata(axh,'Color',color);

set(hFig,'WindowButtonDownFcn','dualcursor(''down'',[],[],[],get(gco,''Parent''))')

set(hFig,'DoubleBuffer','on'); %eliminate flicker

case 'down' % Execute the WindowButtonDownFcn

htype = get(gco,'Type');

tag = get(gco,'Tag');

marker = getappdata(axh,'Marker');

color = getappdata(axh,'Color');

%If it's a movable object (Cursor, CursorText label, or Cursor Delta Text

%label), make it movable.

if strcmp(tag,'CursorText') | strcmp(tag,'Cursor') | strcmp(tag,'CursorDeltaText')

set(gco,'EraseMode','xor')

set(gcf,'WindowButtonMotionFcn','dualcursor(''move'',[],[],[],get(gco,''Parent''))', ...

'WindowButtonUpFcn','dualcursor(''up'',[],[],[],get(gco,''Parent''))');

end;

if strcmp(tag,'Cursor') %If clicked on a cursor

%Label the cursor we are moving. Add a text label just above the plot

CursorNumber = getappdata(gco,'CursorNumber');

cnstr = num2str(CursorNumber);

xl = xlim(axh);

lim = localObjbounds(axh);

lim = lim(1:2); %x values only

xl(isinf(xl)) = lim(isinf(xl));

% yl = lim(3:4);

xv = getappdata(gco,'Coordinates');

xv = xv(1);

%Convert to normalized

xn = (xv - xl(1))/(xl(2) - xl(1));

yn = 1.05;

CNh = text(xn,yn,cnstr, ...

'Units','Normalized', ...

'HorizontalAlignment','center', ...

'Parent',axh); %dx

%For R13 or higher (MATLAB 6.5), use a background color on the text string

v=ver('MATLAB');

v=str2num(v.Version);

if v>=6.5

set(CNh,'BackgroundColor','y');

end;

setappdata(gco,'CNh',CNh);

end

case 'move' % Execute the WindowButtonMotionFcn

htype = get(gco,'Type');

tag = get(gco,'Tag');

if ~isempty(gco)

%Special (simple) case - just repositioning the delta labels

if strcmp(tag,'CursorDeltaText') %The cursor delta labels.

cp = get(axh,'CurrentPoint');

pt = cp(1,[1 2]);

%Put into normalized units

ax = axis;

lim = localObjbounds(axh);

ax(isinf(ax)) = lim(isinf(ax));

pt(1) = (pt(1) - ax(1))/(ax(2)-ax(1));

pt(2) = (pt(2) - ax(3))/(ax(4)-ax(3));

set(gco,'Position', [pt 0])

drawnow

return

end;

%Is this the cursor or the text

if strcmp(tag,'CursorText') %The text

th = gco;

handles = get(gco,'UserData');

ph = handles(2);

slide = 0; %Don't slide along line; just reposition text

else %The marker

ph = gco;

handles = get(gco,'UserData');

th = handles(2);

slide = 1; %Slide along line to next data point

end;

offset = getappdata(th,'Offset'); %Offset from data value

cp = get(axh,'CurrentPoint');

pt = cp(1,[1 2]);

%Constrain to Line

lh = getappdata(get(th,'Parent'),'SelectedLine');

% lh = handles(1); %Line

x = cp(1,1); %first xy values

y = cp(1,2); %first xy values

if slide %Move to new data value

xl = get(lh,'XData');

yl = get(lh,'YData');

%Get nearest value

[xv,yv]=local_nearest(x,xl,yl);

%If we are moving a cursor, must move the cursor number label, too

if strcmp(tag,'Cursor')

%Move the Cursor Number label, too

CNh = getappdata(gco,'CNh');

pos = get(CNh,'Position');

xlm = xlim(axh);

lim = localObjbounds(axh);

lim = lim(1:2); %x values only

xlm(isinf(xlm)) = lim(isinf(xlm));

xn = (xv - xlm(1))/(xlm(2)-xlm(1));

set(CNh,'Position',[xn pos(2:3)])

end;

yl = ylim(axh);

lim = localObjbounds(get(lh,'Parent'));

lim = lim(3:4); %y values only

yl(isinf(yl)) = lim(isinf(yl));

datalabelformatfcnh = getappdata(th,'FormatFcnH');

textstring = feval(datalabelformatfcnh,xv,yv);

set(th,'Position', [xv yv 0] + [offset 0],'String',textstring)

set(ph,'XData',[xv xv xv],'YData',[yl(1) yv yl(2)]);

setappdata(ph,'Coordinates',[xv yv]);

setappdata(th,'Coordinates',[xv yv]);

%Update delta calculation

cursors = findobj(axh,'Tag','Cursor');

cn1 = getappdata(cursors(1),'CursorNumber');

if cn1==2 %Switch order

temp = cursors(1);

cursors(1) = cursors(2);

cursors(2) = temp;

end;

deltah = getappdata(axh,'Delta_Handle'); %Handle to cursors

%Positions of two dualcursors

xy1 = getappdata(cursors(1),'Coordinates');

xy2 = getappdata(cursors(2),'Coordinates');

%Calculate Difference

dx = xy2(1) - xy1(1);

dy = xy2(2) - xy1(2);

set(deltah(1),'String',['({x}_{2}-{x}_{1}) = ' num2str(dx,'%+.2f')]);

set(deltah(2),'String',['({y}_{2}-{y}_{1}) = ' num2str(dy,'%+.2f')]);

else %Just move text around.

set(th,'Position', [x y 0])

end;

drawnow

end;

case 'up' % Execute the WindowButtonUpFcn

htype = get(gco,'Type');

tag = get(gco,'Tag');

if strcmp(tag,'CursorText') | strcmp(tag,'Cursor') | strcmp(tag,'CursorDeltaText');

set(gco,'EraseMode','Normal')

set(gcf,'WindowButtonMotionFcn','')

if strcmp(tag,'CursorText') %If the text label, record it's relative position

cp = get(axh,'CurrentPoint');

pt = cp(1,[1 2]);

coords = getappdata(gco,'Coordinates');

offset(1) = pt(1) - coords(1);

offset = pt - coords;

setappdata(gco,'Offset',offset);

end;

if strcmp(tag,'Cursor') %Delete the temporary cursor number label

CNh = getappdata(gco,'CNh');

delete(CNh);

end;

end;

case 'selectline' % User selected a new line to be active

%Make the selected line bold

lh = getappdata(axh,'SelectedLine');

lw = get(lh,'LineWidth');

set(lh,'LineWidth',5*lw);

drawnow

%Update the cursors

dualcursor('update',deltalabelpos,marker_color,datalabelformatfcnh,axh);

%Put the line back the way you found it!

set(lh,'LineWidth',lw);

case 'update' %Update the cursor value

%Find the position of the existing cursors

cursors = findobj(axh,'Tag','Cursor');

cd1 = getappdata(cursors(1),'Coordinates');

cd2 = getappdata(cursors(2),'Coordinates');

cn1 = getappdata(cursors(1),'CursorNumber');

cn2 = getappdata(cursors(2),'CursorNumber');

clear x

x(cn1) = cd1(1); %x value of cursor number cn1

x(cn2) = cd2(1); %x value of cursor number cn2

lh = getappdata(axh,'SelectedLine');

handles = get(cursors(cn1),'UserData');

th1 = handles(2);

handles = get(cursors(cn2),'UserData');

th2 = handles(2);

offset1 = getappdata(th1,'Offset'); %Offset from data value

offset2 = getappdata(th2,'Offset'); %Offset from data value

ylm = ylim(axh);

lim = localObjbounds(get(lh,'Parent'));

lim = lim(3:4); %y values only

ylm(isinf(ylm)) = lim(isinf(ylm));

xl = get(lh,'XData');

yl = get(lh,'YData');

%Get nearest value

[xv1,yv1]=local_nearest(x(1),xl,yl);

[xv2,yv2]=local_nearest(x(2),xl,yl);

datalabelformatfcnh = getappdata(th1,'FormatFcnH');

% textstring1 = {['x=' num2str(xv1)];['y=' num2str(yv1)]};

% textstring2 = {['x=' num2str(xv2)];['y=' num2str(yv2)]};

textstring1 = feval(datalabelformatfcnh,xv1,yv1);

textstring2 = feval(datalabelformatfcnh,xv2,yv2);

set(th1,'Position', [xv1 yv1 0] + [offset1 0],'String',textstring1)

set(th2,'Position', [xv2 yv2 0] + [offset2 0],'String',textstring2)

set(cursors(cn1),'XData',[xv1 xv1 xv1],'YData',[ylm(1) yv1 ylm(2)]);

set(cursors(cn2),'XData',[xv2 xv2 xv2],'YData',[ylm(1) yv2 ylm(2)]);

%Update delta calculation

deltah = getappdata(axh,'Delta_Handle'); %Handle to delta calculation

% %Positions of two dualcursors

xy1 = getappdata(cursors(1),'Coordinates');

xy2 = getappdata(cursors(2),'Coordinates');

%Calculate Difference

dx = xv2 - xv1;

dy = yv2 - yv1;

set(deltah(1),'String',['{x}_{2}-{x}_{1} ' num2str(dx,'%+.2f')]);

set(deltah(2),'String',['{y}_{2}-{y}_{1} ' num2str(dy,'%+.2f')]);

case 'exportws' %Export selected region to workspace

[xd,yd] = local_extractregion(axh);

%If there's only one line, don't make the user hassle with cell arrays

if length(xd)==1

xd = xd{1};

yd = yd{1};

end;

cursors.xd = xd;

cursors.yd = yd;

assignin('base','cursors',cursors);

disp('Variable: cursors created in workspace');

case 'exportfig' %Export selected region to a new figure

% [xd,yd,proplist,props] = local_extractregion;

[xd,yd,hgS] = local_extractregion(axh);

%Create new plot

fh = figure;

ax = axes;

struct2handle(hgS,ax);

%Get labels from axes, too

%Clunky, but it seems to work

%First, create empty title, xlabel, ylabel

newhandles(1) = title('');

newhandles(2) = xlabel('');

newhandles(3) = ylabel('');

%Get strings from original plot

props = {'Title','xlabel','ylabel'};

vals = get(axh,props);

handles = [vals{:}];

str = get(handles,'String');

%Set the new strings to match

set(newhandles,{'String'},str)

case 'exportcursor'

% Get cursor coordinates

cursordata = dualcursor(axh);

% Push the data into the base workspace.

assignin('base','cursordata',cursordata);

disp('Variable: cursordata created in workspace');

case 'off' % Unset the WindowButton...Fcns

% set(get(axh,'Parent'),'WindowButtonDownFcn','','WindowButtonUpFcn','')

set(hFig,'WindowButtonDownFcn','','WindowButtonUpFcn','')

h1 = findobj(axh,'Tag','CursorText'); %All text

h2 = findobj(axh,'Tag','Cursor'); %The cursors

h3 = findobj(axh,'Tag','CursorDeltaText'); %The cursors

lineh = local_findlines(axh);

set(lineh,'ButtonDownFcn','');

% erasemode = getappdata(axh,'OriginalEraseMode');

% if isempty(erasemode), erasemode = 'normal'; end; %handles first time

% set(local_findlines(axh),'EraseMode',erasemode);

delete([h1;h2;h3]);

end %switch/case on action

end

% function hFig = figHandle(axh)

% % Get the handle to the parent figure

% hFig = ancestor(axh,'figure');

% end

function [xv,yv]=local_nearest(x,xl,yl)

%Inputs:

% x Selected x value

% xl Line Data (x)

%Find nearest value of [xl] to (x)

%Special Case: Line has a single non-singleton value

if sum(isfinite(xl))==1

fin = find(isfinite(xl));

xv = xl(fin);

yv = yl(fin);

else

%Normalize axes

xlmin = min(xl);

xlmax = max(xl);

xln = (xl - xlmin)./(xlmax - xlmin);

xn = (x - xlmin)./(xlmax - xlmin);

%Find nearest x value only.

c = abs(xln - xn);

[junk,ind] = min(c);

%Nearest value on the line

xv = xl(ind);

yv = yl(ind);

end;

end

function textstring = local_maketextstring(xv,yv)

textstring = {['x = ' num2str(xv,'%2g')];

['y = ' num2str(yv,'%2.2g')]};

end

function [xd,yd,hgS] = local_extractregion(axh)

val = dualcursor(axh);

%Find all lines

lineh = local_findlines(axh);

Nl = length(lineh);

%Get all line properties, so we can reproduce the appearance

hgS = handle2struct(lineh); %Get properties

xd = get(lineh,'XData');

yd = get(lineh,'YData');

%Figure out the index into these lines that val corresponds to

x1ind = zeros(Nl,1);

x2ind = zeros(Nl,1);

%Special handling for single line case

if Nl==1

xd= {xd};

yd = {yd};

end;

for ii = 1:Nl

x1ind(ii) = max(find(xd{ii}<=val(1)));

x2ind(ii) = max(find(xd{ii}<=val(3)));

%Keep data from this region only

xd{ii} = xd{ii}(x1ind(ii):x2ind(ii));

yd{ii} = yd{ii}(x1ind(ii):x2ind(ii));

%Update handle structure, to make plotting really easy

hgS(ii).properties.XData = xd{ii};

hgS(ii).properties.YData = yd{ii};

end;

end

function lineh = local_findlines(axh);

lineh = findobj(axh,'Type','line'); %Find a line to add cursor to

dots = findobj(axh,'Type','line','Tag','Cursor'); %Ignore existing cursors

lineh = setdiff(lineh,dots);

%Ignore lines with only one or two values - these are probably annotations of some

%sort

xdtemp = get(lineh,'XData');

linehtemp = lineh;

lineh=[];

if ~iscell(xdtemp) %If there's only one line, force data into a cell array

xdtemp = {xdtemp};

end;

for ii=1:length(xdtemp);

if length(xdtemp{ii})>2

lineh = [lineh; linehtemp(ii)];

end;

end;

end

function lim = localObjbounds(axh);

% Get x limits of all data in axes axh

kids = get(axh,'Children');

xmin = Inf; xmax = -Inf;

ymin = Inf; ymax = -Inf;

for ii=1:length(kids)

try % Pass through if can't get data. hopefully we hit at least one

xd = get(kids(ii),'XData');

xmin = min([xmin min(xd(:))]);

xmax = max([xmax max(xd(:))]);

yd = get(kids(ii),'YData');

ymin = min([ymin min(yd(:))]);

ymax = max([ymax max(yd(:))]);

end

end

% Nuclear option, in case things went really bad

xmin(xmin==Inf) = 0; xmax(xmax==-Inf) = 1;

ymin(ymin==Inf) = 0; ymax(ymax==-Inf) = 1;

lim = [xmin xmax ymin ymax];

end(李洋 安期货)

(责任编辑:金明正)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值