Files
nappMATLAB-toolbox/beamtime/issPlotFlowData.m
T

184 lines
7.8 KiB
Matlab

function sp = issPlotFlowData(tbl, channels, options)
%PLOTFLOWDATA Stacked plot of selected MFC flow channels vs lab time.
%
% sp = plotFlowData(tbl)
% sp = plotFlowData(tbl, channels)
% sp = plotFlowData(tbl, channels, TimeWindow=timeWindow)
% sp = plotFlowData(tbl, channels, MfcNames=mfcNames)
% sp = plotFlowData(tbl, channels, TimeWindow=timeWindow, MfcNames=mfcNames)
%
% Plots one stacked panel per selected MFC flow channel (via stackedplot),
% all sharing a linked lab-time x-axis. Each panel keeps its own y-scale,
% so channels in different units (l/min vs sccm) sit cleanly on their own
% axis without needing yyaxis.
%
% TimeWindow and MfcNames are name-value arguments (order-independent,
% optional, with autocomplete/tooltips in the Editor and Live Script).
%
% INPUTS
% tbl table from flowImportData (columns MFC4..MFC10)
% channels which channel(s) to plot. Any of:
% * [] -> all channels present (default)
% * MFC numbers, e.g. [4 7 10] or 7 (physical MFC number)
% * flow tags, e.g. {'flow1','flow2'} or 'flow3'
% * MFC names, e.g. {'MFC4','MFC9'} or 'MFC7'
% * YOUR custom names from MfcNames, e.g. 'Water dosing'
% or {'Cryo cooling (LN2)','Water dosing'} — only
% resolvable if MfcNames is also supplied in this call.
% All selection styles resolve to the same underlying
% channel — pick whichever is most convenient. Pass multiple
% as a CELL ARRAY of char, e.g. {'flow1','flow2'} — NOT
% ['flow1','flow2'], which MATLAB concatenates into the
% single char 'flow1flow2'.
%
% NAME-VALUE ARGUMENTS
% TimeWindow date-string window as a 2-element cell/string array,
% {'2026-07-01 11:30:00','2026-07-01 18:30:00'}. Default: the
% full available range.
% MfcNames your own display names for the panels (and, per above,
% usable to SELECT channels too), as a containers.Map keyed
% by MFC NUMBER (double), e.g.:
% mfcNames = containers.Map('KeyType','double','ValueType','char');
% mfcNames(4) = 'Cryo cooling (LN2)';
% mfcNames(7) = 'Water dosing';
% Panel labels always show the MFC identifier for
% traceability, e.g. "MFC7: Water dosing [sccm]". Channels
% without an entry fall back to "MFC7 (N2) [sccm]" using the
% gas type parsed from the file header.
%
% OUTPUT
% sp the StackedLineChart object. To further customize (e.g. the x-axis
% tick format, since stackedplot is a chart, not a plain axes):
% axs = findobj(sp.NodeChildren, 'Type', 'Axes');
% axs(end).XAxis.TickLabelFormat = 'dd-MMM HH:mm'; % bottom panel
%
% EXAMPLE
% tbl = flowImportData('01-07-2026_11-28datafile.txt');
% tbl.Properties.UserData.mfcMap % check the mapping once
%
% mfcNames = containers.Map('KeyType','double','ValueType','char');
% mfcNames(4) = 'Cryo cooling (LN2)';
% mfcNames(7) = 'Water dosing';
%
% sp = plotFlowData(tbl, 'Water dosing', MfcNames=mfcNames); % by custom name
% sp = plotFlowData(tbl, {'flow1','flow2'}, MfcNames=mfcNames);
% sp = plotFlowData(tbl, {'MFC4','MFC9'}); % by MFC name
% sp = plotFlowData(tbl, [4 7], ...
% TimeWindow={'2026-07-01 11:30:00','2026-07-01 18:30:00'}, ...
% MfcNames=mfcNames);
%
% See also FLOWIMPORTDATA
arguments
tbl table
channels = []
options.TimeWindow = []
options.MfcNames containers.Map = containers.Map('KeyType','double','ValueType','char')
end
mfcMap = tbl.Properties.UserData.mfcMap; % MFC, SourceColumn, Gas, Unit, MfcVarName
mfcNames = options.MfcNames;
%--- Resolve requested channels into MfcVarName column names ---
if isempty(channels)
selVars = mfcMap.MfcVarName;
elseif isnumeric(channels)
selVars = arrayfun(@(n) resolveByMfcNumber(mfcMap, n), channels, 'UniformOutput', false);
elseif ischar(channels)
selVars = {resolveChannel(mfcMap, mfcNames, channels)};
elseif iscellstr(channels) || isstring(channels) %#ok<ISCLSTR>
c = cellstr(channels);
selVars = cellfun(@(v) resolveChannel(mfcMap, mfcNames, v), c, 'UniformOutput', false);
else
error('plotFlowData:badChannels', ...
'channels must be [] , MFC numbers, or flow/MFC/custom name(s).');
end
selVars = cellstr(string(selVars));
%--- Resolve the time window (date strings) ---
if isempty(options.TimeWindow)
tStart = min(tbl.datetime);
tEnd = max(tbl.datetime);
else
tw = cellstr(options.TimeWindow);
if numel(tw) ~= 2
error('plotFlowData:badTimeWindow', ...
'TimeWindow must be a 2-element cell/string array {start, end}.');
end
tStart = datetime(tw{1});
tEnd = datetime(tw{2});
end
mask = tbl.datetime >= tStart & tbl.datetime <= tEnd;
tblSub = tbl(mask, [{'datetime'}, selVars]);
%--- Panel labels: always "MFCn: <name>" or "MFCn (<gas>)" as fallback ---
labels = cellfun(@(v) labelFor(mfcMap, mfcNames, v), selVars, 'UniformOutput', false);
%--- Units per panel, for the y-axis label ---
units = cellfun(@(v) mfcMap.Unit{strcmp(mfcMap.MfcVarName, v)}, selVars, 'UniformOutput', false);
dispLabels = cellfun(@(l,u) sprintf('%s [%s]', l, u), labels, units, 'UniformOutput', false);
%--- Stacked plot ---
figure;
sp = stackedplot(tblSub, selVars, 'XVariable', 'datetime', ...
'DisplayLabels', dispLabels);
sp.Title = 'MFC flow channels';
sp.GridVisible = 'on';
sp.XLimits = [tStart tEnd];
% Format the shared x-axis date ticks (stackedplot is a chart object,
% so its axes are reached via NodeChildren)
axs = findobj(sp.NodeChildren, 'Type', 'Axes');
if ~isempty(axs)
axs(end).XAxis.TickLabelFormat = 'dd-MMM HH:mm';
end
end
% -------------------------------------------------------------------------
function varName = resolveByMfcNumber(mfcMap, n)
idx = find(mfcMap.MFC == n, 1);
if isempty(idx)
error('plotFlowData:unknownMFC', 'MFC%d not found in this table.', n);
end
varName = mfcMap.MfcVarName{idx};
end
% -------------------------------------------------------------------------
function varName = resolveChannel(mfcMap, mfcNames, v)
v = char(v);
% 1) MFC var name, e.g. 'MFC7'
idx = find(strcmpi(mfcMap.MfcVarName, v), 1);
if ~isempty(idx), varName = mfcMap.MfcVarName{idx}; return; end
% 2) raw source column tag, e.g. 'flow3', 'flowCryo'
idx = find(strcmpi(mfcMap.SourceColumn, v), 1);
if ~isempty(idx), varName = mfcMap.MfcVarName{idx}; return; end
% 3) your custom display name, e.g. 'Water dosing' (only if MfcNames given)
if mfcNames.Count > 0
ks = cell2mat(keys(mfcNames));
vs = values(mfcNames);
idxName = find(strcmpi(vs, v), 1);
if ~isempty(idxName)
mfcNum = ks(idxName);
idx = find(mfcMap.MFC == mfcNum, 1);
if ~isempty(idx), varName = mfcMap.MfcVarName{idx}; return; end
end
end
error('plotFlowData:unknownChannel', ...
'Channel "%s" not recognized as an MFC name, flow tag, or custom name in MfcNames.', v);
end
% -------------------------------------------------------------------------
function s = labelFor(mfcMap, mfcNames, varName)
idx = find(strcmp(mfcMap.MfcVarName, varName), 1);
mfcNum = mfcMap.MFC(idx);
if isKey(mfcNames, mfcNum)
s = sprintf('%s: %s', varName, mfcNames(mfcNum));
else
s = sprintf('%s (%s)', varName, mfcMap.Gas(idx));
end
end