Cursor line
71 views (last 30 days)
Show older comments
Hi,
I've got a figure with several subplots. These subplots are located one under the other one. Then, that I want to do is create a vertical cursor to across all subplots and when I'm going to move this appear the current values of all subplots.
How can I develop this?
thanks
regards
0 Comments
Accepted Answer
Matt Fig
on 14 Feb 2011
This can be done with a little handle graphics. I don't have time right now to make this code perfect (error checking, special cases handling, commenting(!), etc.), but it should give you something of an idea. Run this function then hit the left and right arrow to see what happens.
function [] = data_subplots()
% Link data cursors so that they track accross subplots.
% Create the subplots.
% Alternatively, use GET to create s and L from existing plots.
x = 1:.1:10;
for ii = 1:3
s(ii) = subplot(3,1,ii);
L(ii) = plot(x,sin(x/ii)*ii);
end
% Now start the work.
for ii = 1:length(s)
S.D{ii} = get(L(ii),{'xdata','ydata'});
S.L(ii) = length(S.D{ii}{1});
S.M(ii) = floor(S.L(ii)/2);
S.DF = diff(S.D{ii}{1}(S.M(ii):S.M(ii)+1)); % uniform assum
S.I(ii) = S.M(ii);
S.T(ii) = text(S.D{ii}{1}(S.M(ii)+2),S.D{ii}{2}(S.M(ii)+2),'here');
set(S.T(ii),'string',{['X: ',sprintf('%3.3g',S.D{ii}{1}(S.M(ii)))];...
['Y: ',sprintf('%3.3g',S.D{ii}{2}(S.M(ii)))]},...
'parent',s(ii),'backgroundco',[.8 .8 0]);
set(s(ii),'nextplot','add')
S.F(ii) = plot(s(ii),S.D{ii}{1}(S.M(ii)),S.D{ii}{2}(S.M(ii)),'sk');
set(S.F(ii),'markerfacec','b')
end
set(gcf,'keypressfcn',{@fh_kpfcn,S})
function [] = fh_kpfcn(varargin)
D = varargin{2}.Key;
S = varargin{3};
if strcmp(D,'leftarrow')
for ii = 1:length(S.T)
if S.I(ii)~=1
S.I(ii) = S.I(ii)-1;
set(S.F(ii),'xdata',S.D{ii}{1}(S.I(ii)),...
'ydata',S.D{ii}{2}(S.I(ii)))
set(S.T(ii),'position',...
[S.D{ii}{1}(S.I(ii))+S.DF*2,S.D{ii}{2}(S.I(ii))],...
'string',{['X: ',sprintf('%3.3g',S.D{ii}{1}(S.I(ii)))];...
['Y: ',sprintf('%3.3g',S.D{ii}{2}(S.I(ii)))]})
end
end
elseif strcmp(D,'rightarrow')
for ii = 1:length(S.T)
if S.I(ii)~=S.L(ii)
S.I(ii) = S.I(ii)+1;
set(S.F(ii),'xdata',S.D{ii}{1}(S.I(ii)),...
'ydata',S.D{ii}{2}(S.I(ii)))
set(S.T(ii),'position',...
[S.D{ii}{1}(S.I(ii))+S.DF*2,S.D{ii}{2}(S.I(ii))],...
'string',{['X: ',sprintf('%3.3g',S.D{ii}{1}(S.I(ii)))];...
['Y: ',sprintf('%3.3g',S.D{ii}{2}(S.I(ii)))]})
end
end
end
set(gcf,'keypressfcn',{@fh_kpfcn,S}) % Update the structure.
3 Comments
Matthias Luh
on 19 Mar 2022
This is awesome, thank you! I extended the function a bit and tried to make it more readable for me (see below).
For others looking for help: Also have a look the solution jiro posted here: http://www.mathworks.com/matlabcentral/answers/1758-crosshairs-or-just-vertical-line-across-linked-axis-plots
It might be more intuitive because it allows clicking instead of using the arrow keys.
Dear MATLAB team, if you read this: please add a simple and intuitive crosshair function that can be easily used and activated, e.g. also in the GUI. Something like used in Grafana: https://play.grafana.org/
Extension of Matt Fig's code:
- compatibility with datetime x-axis
- use "shift" + left/right to move around faster
- variable to adjust offset of the textbox relative to data point (textbox_dx_offset, 2x)
- created an own function to generates the text so you only need to adjust it once
function [] = data_subplots_2()
% Link data cursors so that they track accross subplots.
% Create the subplots.
% Alternatively, use GET to create s and L from existing plots.
x = 1:.1:10;
for ii = 1:3
subpl(ii) = subplot(3,1,ii);
pl(ii) = plot(x,sin(x/ii)*ii);
end
% Data tool tip
% https://de.mathworks.com/matlabcentral/answers/1308-cursor-line
textbox_dx_offset = 3;
for ii = 1:length(subpl) % for each subplot
S.data_x{ii} = get(pl(ii), 'xdata');
S.data_y{ii} = get(pl(ii), 'ydata');
S.datalength(ii) = length(S.data_x{ii});
S.startindex(ii) = floor(S.datalength(ii) / 2);
S.delta_x = diff(S.data_x{ii}(S.startindex(ii):(S.startindex(ii) + 1))); % assume uniform x-axis data difference
S.index(ii) = S.startindex(ii);
S.text(ii) = text(S.data_x{ii}(S.startindex(ii) + textbox_dx_offset), S.data_y{ii}(S.startindex(ii) + textbox_dx_offset),'here');
set(S.text(ii), 'string', get_tooltip_text(S, ii), 'parent', subpl(ii), 'BackgroundColor', [1 1 1], 'EdgeColor', [0 0 0]);
set(subpl(ii), 'nextplot', 'add')
S.tooltip_point(ii) = plot(subpl(ii), S.data_x{ii}(S.startindex(ii)), S.data_y{ii}(S.startindex(ii)), 'sk');
set(S.tooltip_point(ii), 'markerfacec', 'b')
end
set(gcf, 'keypressfcn', {@key_press_function, S})
% "on key press" function:
function [] = key_press_function(varargin)
key_id = varargin{2}.Key;
S = varargin{3};
if (size(varargin{2}.Modifier, 2) > 0) && (strcmp(varargin{2}.Modifier{1}, 'shift') == 1)
dx_fac = 12;
else
dx_fac = 1;
end
textbox_dx_offset = 3;
if strcmp(key_id, 'leftarrow')
for ii = 1:length(S.text)
if S.index(ii) ~= 1
S.index(ii) = S.index(ii) - dx_fac;
set(S.tooltip_point(ii), 'xdata', S.data_x{ii}(S.index(ii)),...
'ydata', S.data_y{ii}(S.index(ii)))
set(S.text(ii), 'position',...
[get_text_xpos(S.data_x{ii}(S.index(ii)) + S.delta_x * textbox_dx_offset), S.data_y{ii}(S.index(ii))],...
'string', get_tooltip_text(S, ii))
end
end
elseif strcmp(key_id, 'rightarrow')
for ii = 1:length(S.text)
if S.index(ii) ~= S.datalength(ii)
S.index(ii) = S.index(ii) + dx_fac;
set(S.tooltip_point(ii),'xdata',S.data_x{ii}(S.index(ii)),...
'ydata',S.data_y{ii}(S.index(ii)))
set(S.text(ii),'position',...
[get_text_xpos(S.data_x{ii}(S.index(ii)) + S.delta_x * textbox_dx_offset), S.data_y{ii}(S.index(ii))],...
'string', get_tooltip_text(S, ii))
end
end
end
set(gcf,'keypressfcn',{@key_press_function,S}) % Update the structure.
% end of "on key press" function
% "get tooltip text" function:
function text = get_tooltip_text(S, ii)
if isa(S.data_x{ii}(S.index(ii)), 'datetime') == 1
text = {...
['X: ',sprintf('%s', datestr(S.data_x{ii}(S.index(ii))))];...
['Y: ',sprintf('%3.3g', S.data_y{ii}(S.index(ii)))]...
};
else
text = {...
['X: ',sprintf('%3.3g', S.data_x{ii}(S.index(ii)))];...
['Y: ',sprintf('%3.3g', S.data_y{ii}(S.index(ii)))]...
};
end
% end of "get tooltip text" function
% "get x-position" function:
function xpos = get_text_xpos(x_value)
if isa(x_value, 'datetime') == 1
ax1 = gca;
% dx_days = diff(ax1.XLim)/24;
x_min = ax1.XLim(1);
xpos = datenum(x_value - x_min);
else
xpos = x_value;
end
% end of "get tooltip text" function
More Answers (3)
Paulo Silva
on 14 Feb 2011
You might find useful tips inside the ginput function
edit ginput
%this function can be found inside ginput
set(fig,'pointer','fullcrosshair'); %horizontal and vertical cursor lines
9 Comments
Paulo Silva
on 14 Feb 2011
I'm finally understanding but what you want isn't easy, at least for me and my basic matlab skills, maybe someone with more experience might help you.
Here's some websites with info, maybe you can find something useful in them
http://matlab.wikia.com/wiki/MATLAB_Wiki
http://undocumentedmatlab.com
See Also
Categories
Find more on Specifying Target for Graphics Output in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!