Data Cursors on Line Plot With Spectrogram Subplot

9 次查看(过去 30 天)
There seems to be a bug in the behavior of data cursors when both a line plot and spectrogram plot are used in the same figure window.
After creating a subplot containing a spectrogram, the data cursors for the line plot will show the x value, a time value, and the colorbar value.
clear
close all
clc
fs = 10e9;
t = (0:1/fs:250e-9);
y = sin(2*pi*500e6*t + 20*cos(2*pi*10e6*t));
subplot(2,1,1)
plot(t,y)
subplot(2,1,2)
spectrogram(y,128,64,128,fs)
I believe this bug also applies to all versions that use the new figure window styles.

采纳的回答

Adam Danz
Adam Danz 2019-8-20
编辑:Adam Danz 2019-8-21
Source of the problem
The following sequence of functions are called when producing the spectrogram() plot.
spectrogram() > pspectrogram() > displayspectrogram() > plotTFR()
Within plotTFR(), the datacursormode (DCM) is set for the entire figure and it contains an UpdateFcn function that returns the frequence, time, and power for each (x,y) coordinate. By default the UpdateFcn is empty. Since the DCM is set for a figure as opposed to axes, the same UpdateFcn is invoked when interacting with the subplot that does not contain time-frequency data.
Swiching the order that the two subplots are created does not have an effect.
Solution 1
After the figure is plotted, you can override the DCM UpdateFcn so that all data tips appear as they normally would by default . To do that, add these 3 lines to the end of the code after the plotting is complete. Now the top subplot will show the (X,Y) coordinates and the bottom subplot will show the (X,Y), index, and RGB values like any other imagesc() plot.
fh = gcf();
DCM = datacursormode(fh);
DCM.UpdateFcn = []; %default
Solution 2
If you want the datatips to appear as (x,y) in the top plot and maintain the Frequency, Time, Power datatips in the bottom plot, you can add a WindowButtonMotionFcn function that determines where the mouse is within the figure. When the mouse is within the upper plot, switch the DCM to (X,Y) mode. When the mouse is in the lower subplot, switch the DCM to Freq,Time,Power mode. One drawback of this method is that it requires you to select the data tip icon within the figure due to the WindowButtonMotionFcn. Below is a fully functional example.
% Create data
fs = 10e9;
t = (0:1/fs:250e-9);
y = sin(2*pi*500e6*t + 20*cos(2*pi*10e6*t));
% Create figure
fh = figure(); % Store figure handle
h(1) = subplot(2,1,1); % Store axis1 handle
plot(t,y);
DCM = datacursormode(fh); % Store the data cursor update function for subplot 1
DCM1Func = DCM.UpdateFcn; % ^ ^ ^
h(2) = subplot(2,1,2); % Store axis2 handle
spectrogram(y,128,64,128,fs);
DCM = datacursormode(fh); % Store the data cursor update function for subplot 2
DCM2Func = DCM.UpdateFcn; % ^ ^ ^
% Assign a callback function that responds to the mouse entering
% the figure area, pass the subplot handles and update functions.
fh.WindowButtonMotionFcn = {@switchDCMFcn,h,{DCM1Func,DCM2Func}};
% Define WindowButtonMotionFcn
function switchDCMFcn(figHand, ~, subHand, DCMFunc)
% This function is invoked when the mouse enters the figure area.
% The first part determines which subplot the mouse is in. If the
% mouse is not within a subplot, the function ends. If the mouse
% is within a subplot it determines which subplot and assigns
% the corresponding data cursor update function to the entire
% figure.
% INPUTS
% figHand: handle to figure
% subHand: cell array of subplot handles. This function is
% only designed to work with 2 subplots.
% DCMFunc: a cell array of data cursor update functions that
% correspond to each subHand.
% Get position of subplots within figure (matching units)
cp = figHand.CurrentPoint; %mouse's current position within fig
figUnits = figHand.Units; %figure units
subUnits = get(subHand,'Units'); % original units for each subplot
set(subHand,'Units',figUnits); %temporarily override subplot units to match fig's units
subplotPos = cell2mat(get(subHand,'Position')); %subplot position within fig (same units as fig)
set(subHand,{'Units'},subUnits); %return original units to subplots
% Which subplot is the mouse 'in' (if any)?
mouseIN = cp(1) >= subplotPos(:,1) & cp(1) <= sum(subplotPos(:,[1,3]),2) & ... %mouse is within the horizontal subplot range
cp(2) >= subplotPos(:,2) & cp(2) <= sum(subplotPos(:,[2,4]),2); % mouse is within the vertical subplot range
if ~any(mouseIN)
% If mouse is not within a subplot, quit now
return
else
% If mouse is within a subplot reassign the corresponding DCM
% fprintf('In %d\n',find(mouseIN)) for troubleshooting
% Get current DCM of figure
currDCM = datacursormode(figHand);
% re-assign DCM
currDCM.UpdateFcn = DCMFunc{mouseIN};
end
end % <-- needed when embedded in a script
  2 个评论
Kyle Young
Kyle Young 2019-8-21
Thank you.
Solution 1 is by far the quickest way to get the cursors to show the correct information.
Solution 2 will be very useful if I get to the point where I would like to create custom datatips.
Adam Danz
Adam Danz 2019-8-21
Agreed. Solution 3 would be to just write your own UpdateFcn which would probably be easier than solution 2.

请先登录,再进行评论。

更多回答(0 个)

类别

Help CenterFile Exchange 中查找有关 Spectral Measurements 的更多信息

产品


版本

R2019a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by