function historyG = plotNodeHistory(G, targetFile) % PLOTNODEHISTORY Extracts and plots the entire upstream history for a single file. % % USAGE: % G = buildDependencyGraph(); % plotNodeHistory(G, 'Results/FinalPlot.fig'); % % ========================================================================= % SCRIPT OUTPUTS & VISUALIZATION OPTIONS % ========================================================================= % 1. MATLAB Figure: A standard MATLAB figure window will automatically % open displaying the dependency graph. % % 2. Static Image (PNG): A high-resolution (300 DPI) PNG file is saved to % your current directory (e.g., 'ProjectDependencies.png'). This is % ideal for quick viewing, sharing, or inserting into reports. % % 3. Interactive Graph (yEd Graph Editor): For complex networks where you % can drag, auto-layout, and isolate nodes: % a) Find the generated text file (e.g., 'Dependency_Graph.tgf'). % b) Open the free yEd Graph Editor app (macOS/Windows/Linux). % c) Go to File -> Open and select the .tgf file. % d) To arrange the messy graph, go to the top menu: % Layout -> Hierarchical (or press Cmd+Option+H). % % ========================================================================= % ========================================================================= % HOW TO UNTANGLE THE GRAPH IN yEd (First-time Open) % ========================================================================= % When you first open the .tgf file, the nodes will be in a messy pile. % Follow these 3 steps to instantly format the dependency tree: % % 1. UNTANGLE: Go to Layout -> Hierarchical (or press Cmd+Option+H). % This arranges the scripts and data files in a logical flow. % % 2. FIX BOX SIZES: Press Cmd+A to select all, then go to: % Tools -> Fit Node to Label... -> Click OK. % This resizes the boxes to fit your file names perfectly. % % 3. VIEW ALL: Click the 'Fit Content' icon (magnifying glass with square) % in the top toolbar to center the graph on your screen. % % You can now click and drag any node; the arrows will follow automatically. % ========================================================================= % 1. Check if the file actually exists in the graph if findnode(G, targetFile) == 0 error('File "%s" was not found in the dependency graph.', targetFile); end % 2. Reverse the graph's arrows to walk backwards up the chain revG = flipedge(G); % 3. Use Breadth-First Search to find all "ancestors" (upstream nodes) % This returns the target file itself plus everything that leads to it. ancestors = bfsearch(revG, targetFile); % 4. Extract the historical subgraph from the ORIGINAL graph historyG = subgraph(G, ancestors); % --------------------------------------------------------- % 5. Apply Colors % --------------------------------------------------------- numNodes = numnodes(historyG); nodeColors = zeros(numNodes, 3); colorScript = [0 0.4470 0.7410]; % Blue for .m scripts colorData = [0.8500 0.3250 0.0980]; % Orange for .mat data colorFig = [0.4940 0.1840 0.5560]; % Purple for figures (.fig, .png, etc.) colorOther = [0.4660 0.6740 0.1880]; % Green for anything else colorTarget = [0.9290 0.6940 0.1250]; % Gold/Yellow for the TARGET file for n = 1:numNodes nodeName = historyG.Nodes.Name{n}; if strcmp(nodeName, targetFile) nodeColors(n, :) = colorTarget; elseif endsWith(nodeName, '.m', 'IgnoreCase', true) nodeColors(n, :) = colorScript; elseif endsWith(nodeName, '.mat', 'IgnoreCase', true) nodeColors(n, :) = colorData; elseif endsWith(nodeName, {'.fig', '.png', '.svg', '.pdf'}, 'IgnoreCase', true) nodeColors(n, :) = colorFig; else nodeColors(n, :) = colorOther; end end % --------------------------------------------------------- % 6. Plot the History Graph % --------------------------------------------------------- fig = figure('Name', ['History for ' targetFile], 'Color', 'w'); p = plot(historyG, 'Layout', 'layered', ... 'NodeLabel', historyG.Nodes.Name, ... 'Interpreter', 'none', ... 'NodeColor', nodeColors, ... 'MarkerSize', 8, ... 'EdgeColor', [0.7 0.7 0.7], ... 'LineWidth', 1.5, ... 'ArrowSize', 12); % Highlight the target file highlight(p, targetFile, 'MarkerSize', 14); p.NodeFontSize = 10; p.NodeFontWeight = 'bold'; title(['Full Provenance Chain for: ' targetFile], 'Interpreter', 'none'); % --------------------------------------------------------- % 7. Export Data % --------------------------------------------------------- safeName = strrep(targetFile, '/', '_'); safeName = strrep(safeName, '\', '_'); outputFile = sprintf('Dependency_History_%s.png', safeName); % --- Export text for yEd Graph Editor (TGF Format) --- if numedges(historyG) > 0 % Extract the exact edges from the history subgraph histSources = historyG.Edges.EndNodes(:,1); histTargets = historyG.Edges.EndNodes(:,2); % 1. Create a unique list of all nodes in this history graph allNodes = unique([histSources; histTargets; targetFile]); safeName = strrep(targetFile, '/', '_'); safeName = strrep(safeName, '\', '_'); tgfFile = sprintf('Dependency_History_%s.tgf', safeName); fid = fopen(tgfFile, 'w'); % 2. Write the Node List (Format: ID Label) for i = 1:length(allNodes) fprintf(fid, '%d %s\n', i, allNodes{i}); end % 3. Write the Separator fprintf(fid, '#\n'); % 4. Write the Edge List (Format: SourceID TargetID) for i = 1:length(histSources) srcIdx = find(strcmp(allNodes, histSources{i})); tgtIdx = find(strcmp(allNodes, histTargets{i})); fprintf(fid, '%d %d\n', srcIdx, tgtIdx); end fclose(fid); fprintf('Generated %s for yEd Graph Editor.\n', tgfFile); end % --- Export high-res PNG --- exportgraphics(fig, outputFile, 'Resolution', 300, 'BackgroundColor', 'w'); fprintf('Saved full history graph to %s\n', outputFile); end