How to plot discrete data in a stackedplot
Show older comments
I'd like to plot timetable data consisting of discrete data (e.g. boolean, enumerations) in a stackedplot (common time x-axis).
In order to plot discrete data there are functions like stairs which supress (?) linear interpolation and plot like interpolation method "zoh".
Is it possible to change the interpolation of stackedplot (to "zoh") or a similar plot with time cursor (lets call it stackedstairs) ? Or do I have to use multiple subplots with stairs and link the x-axis?
Accepted Answer
More Answers (1)
You can get creative and use stackedplot to create the axes for you, and then go "handle-diving" to find and modify the content of the underlying axes...
I used one of the examples for stackedplot as a start point --
tbl = readtable('patients.xls'); % some sample data
vars={'Height','Weight','Systolic','Diastolic'}; % pick the variables
hSP=stackedplot(tbl,vars); % stacked plot for starters
hAx=flip(hSP.NodeChildren(numel(vars)+1:end)); % get the axes handles
for i=1:numel(hAx) % for each axes (same as numel(vars))
hold(hAx(i),'on') % set hold on for each axes to keep other properties unchanged
hL=hAx(i).Children; % get existing line handle
delete(hL); % delete that line
hSL(i)=stairs(hAx(i),tbl.(vars{i})); % replace with stairs line
end
Above yields

Introducing a function handle for the plot function into stackedplot seems worthwhile enhancmenet request.
NOTA BENE: The stackedplot object hides the axes handles in the undocumented and hidden NodeChildren property. Another case IMO of TMW getting far too clever in their penchant to create opaque objects.
Inspection showed the Axes are the last elements in the array and are stored in obverse order of their creation; this is a pretty common (universal?) order in such case; one can tell which is which by inspection of the .Position property for the bottom location of the axes. Remember the position 4-vector is [left bottom width height]
11 Comments
Edited to fix 1 typo:
hSP=stackedplot(tbl,)
% ^ removed
BTW, to access the axis handles without returning other NodeChildren (e.g. Legend handles),
hAx = flip(findobj(hSP.NodeChildren, 'Type','Axes'))
The typo correction should be
hSP=stackedplot(tbl,vars);
% ^ plot only the listed vars
I created the vars variable to shorten the for loop and then didn't patch up the copied code to match...if use whole table will get a bunch more variables than the above four.
The enhancement to find the axes handles is good, I can never recall exact syntax for findobj or otomh.
jonas
on 29 Mar 2021
Adam Danz
on 29 Mar 2021
Could you show us what's in hL and hAx?
Seeing the relevant section of your code would also help.
jonas
on 29 Mar 2021
All the code and error messages in context.
Which release are you using? Something after R2019b? It's possible TMW locked down something in a later release, but I'd guess you've got a typo and are referencing an already deleted line handle inadvertently.
NB: I deleted the line handle and the created a new array to hold the stacked-plot new handles...if one reused the same variable name, it would be very easy to wipe that array out and end up having/trying to reference an invalid handle.
jonas
on 29 Mar 2021
jonas
on 29 Mar 2021
This is bizzaro...If I just paste the code in, it errors here, as well.
But the following session is what I did at command line interactively and it still works as it did and generates the figure attached. There's something different between running the interactive code and pasting it; at this point I've no idea what nor why.
Here's the log of the session---identical code just retrieved line-by-line at command line to build the for...end loop before the CR to execute after the end was entered. I stuck in the disp(i) just in case to see which loop it error'ed on if it did...
>> clear hSP hAx hL
>> hSP=stackedplot(tbl,vars); % stacked plot for starters
>> hSP
hSP =
StackedLineChart with properties:
SourceTable: [100×10 table]
DisplayVariables: {'Height' 'Weight' 'Systolic' 'Diastolic'}
XVariable: []
Color: [0 0.4470 0.7410]
LineStyle: '-'
LineWidth: 0.5000
Marker: 'none'
MarkerSize: 6
Show all properties
>> hAx=flip(hSP.NodeChildren(numel(vars)+1:end)); % get the axes handles
>> hAx
hAx =
4×1 Axes array:
Axes
Axes
Axes
Axes
>> for i=1:numel(hAx) % for each axes (same as numel(vars))
hold(hAx(i),'on') % set hold on for each axes to keep other properties unchanged
hL=hAx(i).Children; % get existing line handle
delete(hL);
hSL(i)=stairs(hAx(i),tbl.(vars{i})); % replace with stairs line
disp(i)
end
1
2
3
4
>>
My former post was to simply take the above command window and put it into the Answer and clean it up a little -- little suspecting there would/could be any difference in result.
I'm at a loss to explain the difference; some internal race condition on updating the properties between what the JIT interpreter does between a code segment seen all at once versus entered line-by-line interactively, maybe?
I've no explanation, can only suggest to try to write the code serially instead of in the loop as a possible workaround unless somebody else can delve into the bowels and find a root cause.
jonas
on 29 Mar 2021
" I just set the linestyle to none after the loop."
You can do that first instead of last to make them not show. Of course, that leaves the old data in place as well, but "any port in a storm!" when it comes to workarounds.
However, see the alternate Answer for the REAL workaround -- but your above reference got me looking more deeply at the stackedplot object and turns out TMW had it built-in all along -- and it is even documented in an example, I just didn't look at all the examples.
Categories
Find more on Creating, Deleting, and Querying Graphics Objects 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!