function plot_results2(results, cfg, classLabels) % PLOT_RESULTS2 — Scenario 2 plotting suite % Produces and saves: % (A) CV heatmap of Kappa over (#features × radius) % (B) CV heatmap of mean #rules over the same grid % (C) Confusion matrix on TEST for the best model % (D) PA/UA bars on TEST % (E) Learning curves (train/validation error) % (F) MFs before/after for the best model % (G) Truth vs Prediction (TEST) % (H) ReliefF feature weights bar chart % % All PNGs saved under cfg.outDir. outDir = cfg.outDir; % (A) CV heatmap — Kappa fig = figure('Color','w'); imagesc(results.cvScores); set(gca,'XTick',1:numel(results.rGrid),'XTickLabel',compose('%.2f',results.rGrid)); set(gca,'YTick',1:numel(results.fGrid),'YTickLabel',string(results.fGrid)); xlabel('SC radius r_a'); ylabel('#Features (ReliefF)'); colorbar; title(sprintf('CV mean Kappa (K=%d folds)', cfg.kfold)); for i = 1:numel(results.fGrid) for j = 1:numel(results.rGrid) text(j,i,sprintf('%.2f',results.cvScores(i,j)),... 'HorizontalAlignment','center','Color','w','FontWeight','bold'); end end exportgraphics(fig, fullfile(outDir,'cv_kappa_heatmap.png'), 'Resolution', 200); close(fig); % (B) CV heatmap — mean #rules fig = figure('Color','w'); imagesc(results.cvRules); set(gca,'XTick',1:numel(results.rGrid),'XTickLabel',compose('%.2f',results.rGrid)); set(gca,'YTick',1:numel(results.fGrid),'YTickLabel',string(results.fGrid)); xlabel('SC radius r_a'); ylabel('#Features (ReliefF)'); colorbar; title(sprintf('CV mean #Rules (K=%d folds)', cfg.kfold)); for i = 1:numel(results.fGrid) for j = 1:numel(results.rGrid) text(j,i,sprintf('%d',results.cvRules(i,j)),... 'HorizontalAlignment','center','Color','w','FontWeight','bold'); end end exportgraphics(fig, fullfile(outDir,'cv_rules_heatmap.png'), 'Resolution', 200); close(fig); % (C) Confusion matrix — TEST fig = figure('Color','w'); confusionchart(results.metrics.confMat, string(classLabels), ... 'Title', sprintf('Confusion — best model (features=%d, r=%.2f, rules=%d)', ... results.bestF, results.bestR, numel(results.bestFis.rule))); exportgraphics(fig, fullfile(outDir,'cm_best_model.png'), 'Resolution', 200); close(fig); % (D) PA/UA bars — TEST fig = figure('Color','w'); t = tiledlayout(2,1,'TileSpacing','compact','Padding','compact'); nexttile; bar(results.metrics.PA); ylim([0 1]); xticks(1:numel(classLabels)); xticklabels(string(classLabels)); ylabel('PA (Recall)'); title('Producer''s Accuracy (TEST)'); grid on; nexttile; bar(results.metrics.UA); ylim([0 1]); xticks(1:numel(classLabels)); xticklabels(string(classLabels)); ylabel('UA (Precision)'); title('User''s Accuracy (TEST)'); grid on; exportgraphics(fig, fullfile(outDir,'pa_ua_best_model.png'), 'Resolution', 200); close(fig); % (E) Learning curves fig = figure('Color','w'); plot(1:numel(results.trError), results.trError, 'LineWidth', 1.2); hold on; if ~isempty(results.vaError) plot(1:numel(results.vaError), results.vaError, '--', 'LineWidth', 1.2); legend('Training Error','Validation Error','Location','best'); else legend('Training Error','Location','best'); end xlabel('Epoch'); ylabel('Error'); grid on; title(sprintf('Learning Curve — best model (features=%d, r=%.2f)', ... results.bestF, results.bestR)); exportgraphics(fig, fullfile(outDir,'learning_best_model.png'), 'Resolution', 200); close(fig); % (F) MFs before/after for the best model try plot_mfs_before_after(results.initFis, results.bestFis, ... sprintf('MFs — best model (features=%d, r=%.2f)', results.bestF, results.bestR), ... fullfile(outDir,'mfs_best_model.png')); catch ME warning('MF plot failed: %s', ME.message); end % (G) Truth vs Prediction — TEST fig = figure('Color','w'); plot(results.ytrue, 'LineWidth', 1.0); hold on; plot(results.yhat, '--', 'LineWidth', 1.0); xlabel('Test sample index'); ylabel('Class label'); grid on; title('Truth vs Prediction (TEST)'); legend('Truth','Prediction','Location','best'); exportgraphics(fig, fullfile(outDir,'pred_vs_truth_best_model.png'), 'Resolution', 200); close(fig); % (H) ReliefF feature weights (on full train+val) fig = figure('Color','w'); w = results.reliefW(:); idx = results.selIdx(:); % map back: selected indices first for clarity bar(1:numel(idx), w(idx)); grid on; xlabel('Selected feature index'); ylabel('ReliefF weight'); title(sprintf('ReliefF weights (top %d features)', results.bestF)); exportgraphics(fig, fullfile(outDir,'relieff_weights_selected.png'), 'Resolution', 200); close(fig); % ===================== local helper ===================== function plot_mfs_before_after(fisBefore, fisAfter, suptitleStr, outPng) D = numel(fisAfter.Inputs); fig = figure('Color','w','Position',[100 100 1200 420]); t = tiledlayout(2, D, 'TileSpacing','compact','Padding','compact'); for d = 1:D nexttile(d); hold on; try [xB, yB] = plotmf(fisBefore, 'input', d); plot(xB, yB, 'LineWidth', 1.0); catch end title(sprintf('Input %d — BEFORE', d)); ylim([0 1]); grid on; nexttile(D + d); hold on; [xA, yA] = plotmf(fisAfter, 'input', d); plot(xA, yA, 'LineWidth', 1.0); title(sprintf('Input %d — AFTER', d)); ylim([0 1]); grid on; end sgtitle(suptitleStr); exportgraphics(fig, outPng, 'Resolution', 200); close(fig); end end