Dev-iL
Dev-iL

Reputation: 24169

How to programatically update histogram contents and datatip location? (MATLAB hg2)

I am trying to make an animation where several datasets are being cycled through in a histogram plot, and a datatip follows the highest bar in every frame, as demonstrated below:

                          The desired result

Here's a code which achieves the desired result using a bar graph:

%% // Initialization
close all force; clear variables; clc;
%% // Generate some data:
indMax = 20; data = randi(indMax,[5,45]);
%% // Generate the 1st values to plot:
edges = 0.5:1:indMax+0.5;
counts = histcounts(data(1,:),edges);
[~,maxInd] = max(counts);
%% // Create the plot and the datatip:
figure(100); hBar = bar(1:indMax,counts); 
hDT = makedatatip(hBar,maxInd); hDT = handle(hDT);
grid on; hold on; grid minor; xlim([0,indMax+1]); ylim([0,10]);
%% // Update the figure and the datatip:
for indFrame = 2:size(data,1)       
   counts = histcounts(data(indFrame,:),edges);
   [~,maxInd] = max(counts);
   hBar.YData = counts; %// Update bar heights
   hDT.Cursor.DataIndex = maxInd; %// Update datatip location
   %// Alternatively to the above line: hDT.Position = [newX newY newZ];
   java.lang.Thread.sleep(1000);
   drawnow;
end

Note that the datatip is created using a modified version of the makedatatip submission from FEX, as per the comment on the submission page (this is true for the 27/06/2012 version of makedatatip):

a couple of changes need to be made to the code:
***********CHANGE 1*********
line 122 needs to be: pos = [X(index(n)) Y(index(n)) 0];
***********CHANGE 2*********
lines 135-141 should be commented OUT

And also Change 3: line 84 to Z = [];

Since makedatatip attempts to acces the 'XData' and 'YData' properties of the input handle, which are absent in histogram plots, it refuses to work. So my question is:

How can datatips be created and updated programmatically in histogram plots (using ), along with the histogram itself?

Upvotes: 2

Views: 581

Answers (1)

Dev-iL
Dev-iL

Reputation: 24169

Turns out the solution is quite straight-forward, at least when only a single datatip is needed. Here are the required steps:

  1. Replace the bar plot with a histogram:

    hHist = histogram(data(1,:),edges);
    
  2. Create the datatip "manually" instead of using makedatatip:

    hDataCursorMgr = datacursormode(ancestor(hHist,'figure'));
    hDT = createDatatip(hDataCursorMgr,hHist);
    
  3. Update the position as needed:

    hDT.Cursor.DataIndex = maxInd;
    
  4. To update the histogram's bar heights, it is not possible to update the 'Values' property directly (since it's read-only), so one must update the 'Data' property (and let MATLAB recompute the bar heights on its own):

    hHist.Data = data(indFrame,:);
    

And everything put together:

%% // Initialization
close all force; clear variables; clc;
%% // Generate some data:
indMax = 20; data = randi(indMax,[5,45]);
%% // Generate the 1st values to plot:
edges = 0.5:1:indMax+0.5;
counts = histcounts(data(1,:),edges);
[~,maxInd] = max(counts);
%% // Create the plot and the datatip:
figure(100); hHist = histogram(data(1,:),edges);
hDataCursorMgr = datacursormode(ancestor(hHist,'figure'));
hDT = createDatatip(hDataCursorMgr,hHist); hDT.Cursor.DataIndex = maxInd;
grid on; hold on; grid minor; xlim([0,indMax+1]); ylim([0,10]);
%% // Update the plot and the datatip:
for indFrame = 2:size(data,1)       
   [~,maxInd] = max(histcounts(data(indFrame,:),edges));
   hHist.Data = data(indFrame,:);
   hDT.Cursor.DataIndex = maxInd;
   java.lang.Thread.sleep(1000);
   drawnow;
end

Which results in:

                              The desired result 2


Some notes \ observations:

  • Datatips can only be added to supported data types, which currently only consist of double values (i.e. plotting something other than double doesn't let you add datatips to it, apparently). This is true for MATLAB 2015a. See another discussion about it here.
  • If datatips should contain some LaTeX-formatted strings, this Q&A describes what needs to be done.
  • The gif animations I used were created using this.
  • To center the animations in the posts, I used a combination of "alt+0160" and "alt+255".

Upvotes: 2

Related Questions