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 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: " or "MFCn ()" 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