184 lines
7.8 KiB
Matlab
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
|