Matlab Generate Report
MathWorksOfficialCreated by MathWorks
- Skill
- Tool integration
- Science and research
- BSD-2-Clause
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
The MATLAB Report Generation skill provides a unified framework for creating structured, professional documentation directly from MATLAB and Simulink. It leverages the Report API for high-level document structure and the DOM API for granular control over formatting, tables, and images. The system supports template-based styling, custom reporter classes for branded content, and specialized tools for documenting Simulink models, including block diagrams and execution order.
What it does
- Creates PDF, Word, and HTML documents from MATLAB data.
- Supports auto-numbered figures, tables, and chapters.
- Generates technical documentation for Simulink models.
- Enables custom branded templates with headers, footers, and page borders.
- Provides a scaffolded approach for building custom reporter classes.
- Supports multipage HTML output with navigation.
When to use it
- When you need to automate the creation of technical reports from MATLAB analysis.
- When documenting Simulink models, including system I/O and execution order.
- When you require consistent, branded document styling across multiple reports.
- When you need to integrate MATLAB plots and data into professional PDF or Word documents.
Advantages
- Maintains document structure and numbering automatically.
- Separates content logic from visual styling via templates.
- Provides specialized support for complex Simulink model documentation.
- Allows for highly customized, reusable report components.
Usage examples
- “Create a basic PDF report with a title page and a chapter containing a plot.”
- The agent provides a script using mlreportgen.report.Report, TitlePage, and Figure classes to generate a PDF with auto-numbered content.
- “How do I document a Simulink model's system I/O?”
- The agent guides you to use slreportgen.report.Report and the SystemIO reporter to extract and format model I/O data.
- “How can I create a custom report template?”
- The agent instructs you to use the customizeReporter method to scaffold a custom reporter class and its associated template files.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/matlab/matlab-generate-report/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip matlab-generate-report.zip -d .agents/skills
Documentation by MathWorks
MATLAB Report Generation
Generate structured, professional reports (PDF, Word, HTML) from MATLAB data and Simulink models.
When to Use
Creating PDF, Word, or HTML reports from MATLAB data
Building reports with chapters, title pages, tables of contents
Adding auto-numbered figures and tables to documents
Creating multipage HTML reports (separate HTML files with navigation)
Documenting Simulink models with block diagrams, I/O tables, execution order
Customizing report templates (styles, colors, fonts, headers, footers)
Creating custom reporter classes with template holes and dynamic content
Building multi-reporter packages with shared company styles
Creating table variant reporters with different header colors
Including HTML content in reports
When NOT to Use
Simple file export (CSV, Excel) — use
writetable,writematrixLive Scripts as reports — use MATLAB Live Editor export
Interactive report building — use Report Explorer GUI
Web views of Simulink models — use
slreportgen.webview.*directly
API Selection
Always use the Report API (mlreportgen.report.*) as the foundation. It provides the Report container and reporters (Figure, BaseTable, FormalImage, Chapter, TitlePage, etc.) that handle auto-numbering, captions, and document structure.
Use both APIs together. Use the Report API to create the report and add content for which reporters exist. Use the DOM API (mlreportgen.dom.*) for styled paragraphs, custom tables, inline formatting, HTML inclusion, and images without captions. DOM objects append directly to Report, Chapter, or Section alongside reporters.
Critical rule: Report API reporters (Figure, BaseTable, FormalImage) can ONLY be appended to Report, Chapter, or Section objects — never to DOM objects like TableEntry. Use DOM objects inside TableEntry.
Simulink reports: Use slreportgen.report.Report (not mlreportgen.report.Report) — it extends the base with model compilation support required by SystemIO, ExecutionOrder, and other Simulink reporters.
Multipage HTML: Use mlreportgen.dom.Document with "html-multipage" type + HTMLPage objects. This is the only case where you use the DOM Document instead of the Report API Report.
Core Workflow: Standard Report
TitlePage, TableOfContents, ListOfFigures, and ListOfTables are optional — include only when the task requires them. The minimal report is just Report + content + close.
import mlreportgen.report.*
import mlreportgen.dom.*
rpt = Report("MyReport","pdf");
append(rpt,TitlePage(Title="Report Title",Author="Team")); % optional
append(rpt,TableOfContents()); % optional
append(rpt,ListOfFigures()); % optional
append(rpt,ListOfTables()); % optional
ch = Chapter("Results");
append(ch,Paragraph("Analysis complete."));
% Auto-numbered table
data = FormalTable(["ID","Value"],[1 10; 2 20]);
bt = BaseTable(data);
bt.Title = "Measured values";
append(ch,bt);
% Auto-numbered figure
fig = figure("Visible","off");
plot([1 2],[10 20]);
rptFig = Figure(fig);
rptFig.Snapshot.Caption = "Value trend";
append(ch,rptFig);
close(fig);
append(rpt,ch);
close(rpt);
rptview(rpt);Core Workflow: Simulink Report
load_system(modelName);
% MUST use slreportgen.report.Report for Simulink content
rpt = slreportgen.report.Report(outputPath,"pdf");
append(rpt,mlreportgen.report.TitlePage("Title","Model Report"));
append(rpt,mlreportgen.report.TableOfContents());
ch = mlreportgen.report.Chapter("Diagrams");
% Root diagram — direct reporter
rootDiag = slreportgen.report.Diagram(modelName);
rootDiag.Snapshot.ScaleToFit = true;
append(ch,rootDiag);
% Subsystems — finder pattern (iterator for memory efficiency)
finder = slreportgen.finder.SystemDiagramFinder(modelName);
finder.IncludeRoot = false;
finder.SortType = "alphabetical";
while finder.hasNext()
result = finder.next();
sec = mlreportgen.report.Section("Title",result.Name);
append(sec,result);
append(ch,sec);
end
append(rpt,ch);
close(rpt);
rptview(rpt);Choosing Built-In vs Custom Reporters
Before writing code, analyze requirements against built-in reporter capabilities:
List all content/format requirements — title page fields, page borders, headers/footers, branded styling
Check built-in reporters. Built-in
TitlePagehas: Title, Subtitle, Author, Publisher, PubDate, Image. Built-inChapter/Sectionprovide headings, auto-numbering, and a Content hole.If built-in reporters meet all requirements, use them directly
If any requirement is unmet, create custom reporters:
Single custom reporter — see references/custom-reporters.md
Multiple reporters sharing a visual identity — see references/report-package.md
Common triggers for custom reporters:
Title page needs fields beyond the standard set (project name, facility, contract number)
Page borders, watermarks, or custom page layout
Page headers/footers with dynamic content (per-chapter images, tickers)
Branded table variants with different header colors
MATLAB-generated logos (geometric shapes drawn with plot/patch + exportgraphics)
Do NOT force-fit requirements into built-in properties (e.g., concatenating fields into Subtitle). Create a custom reporter instead.
Do NOT build custom title pages with raw DOM elements (Paragraphs, Images appended to a Chapter). Always use customizeReporter for template-based layout and format portability.
Decision Tree: What Reference Do I Need?
| I need to... | Reference |
|---|---|
| Build a standard report with chapters, figures, tables, verification | references/report-api-patterns.md |
| Work with DOM tables, HTML inclusion, multipage HTML, Number/NumberFormat | references/dom-api-patterns.md |
| Understand template file types, locate/inspect templates | references/template-system.md |
| Look up built-in template holes, styles, page layout (pre-computed) | references/template-reference.md |
| Create a custom reporter class (customizeReporter, holes, headers) | references/custom-reporters.md |
| Build a multi-reporter package with shared styles and buildTemplates | references/report-package.md |
| Generate Simulink model reports (finders, orientation, centering) | references/simulink-report.md |
| Look up all Simulink finders and reporters | references/finders-and-reporters.md |
| Iterate struct arrays into chapters with custom reporters | references/data-driven-report-pattern.md |
| Edit template styles (colors, fonts, headers, footers, TOC) | references/template-system.md |
Key Functions
| Class | Purpose | Package |
|---|---|---|
Report | Top-level report container | mlreportgen.report |
TitlePage | Title page with title, subtitle, author | mlreportgen.report |
TableOfContents | Auto-generated TOC | mlreportgen.report |
Chapter / Section | Document structure | mlreportgen.report |
Figure | Auto-numbered figure from MATLAB figure | mlreportgen.report |
FormalImage | Auto-numbered image from file with caption | mlreportgen.report |
BaseTable | Auto-numbered table wrapper (pass FormalTable) | mlreportgen.report |
FormalTable | Table with header/body/footer from cell arrays | mlreportgen.dom |
Template (3-arg) | Edit templates: Template(out,fmt,src) | mlreportgen.dom |
HTMLFile / HTML | Include HTML content in any output format | mlreportgen.dom |
HTMLPage | Page in multipage HTML document (R2024a+) | mlreportgen.dom |
Number | Numeric DOM object (use with NumberFormat) | mlreportgen.dom |
TemplateHole | Placeholder filled at report time | mlreportgen.dom |
Page / NumPages | Page number / total pages | mlreportgen.dom |
*.customizeReporter | Scaffold custom reporter + templates | mlreportgen.report |
getStyle / replaceStyle | Modify template styles | mlreportgen.dom |
slreportgen.report.Report | Report container for Simulink content | slreportgen.report |
slreportgen.report.Diagram | Diagram snapshot of a system | slreportgen.report |
slreportgen.finder.SystemDiagramFinder | Find system/subsystem diagrams | slreportgen.finder |
slreportgen.report.SystemIO | Report inputs/outputs (requires compilation) | slreportgen.report |
slreportgen.report.ExecutionOrder | Report block execution order | slreportgen.report |
slreportgen.report.LookupTable | Report lookup table data + plot | slreportgen.report |
rptview | Display report (updates DOCX fields) | function |
docview | Process Word documents (update fields, convert) | function |
Common Mistakes
| Mistake | Correct Approach |
|---|---|
Using mlreportgen.dom.Document as report container | Use mlreportgen.report.Report. Exception: multipage HTML requires Document with "html-multipage" |
Using mlreportgen.report.Report for Simulink content | Use slreportgen.report.Report — needed for model compilation |
Using Report with "html" for multipage output | Use mlreportgen.dom.Document with "html-multipage" + HTMLPage objects |
| Appending reporters to DOM objects (Paragraph, TableEntry) | Reporters can ONLY go in Report, Chapter, or Section. Use DOM objects inside TableEntry |
Putting raw doubles in FormalTable cells | Use Number with NumberFormat in Style: n = Number(42); n.Style = {NumberFormat("%.0f")}. Put n directly in cell arrays. See references/dom-api-patterns.md § Number and NumberFormat |
NumberFormat("$%.0f") or NumberFormat("%,.0f") | Only standard sprintf specifiers work (no $, no %,, no %d). For currency/units, wrap Number in Paragraph and prepend/append Text |
| Customizing only "default"/"even" page headers | Customize ALL page types: "first", "default", "even" — but differentiate content (see below) |
| Putting StyleRef (chapter title) in the first-page header | First page already displays the chapter heading — omit StyleRef from "first" header. Use it only in "default"/"even" for wayfinding |
Opening DOCX with winopen/open/start | Use rptview(rpt) or docview(file,"updatefields") — triggers field update |
Using ColSpec/ColSpecGroup for widths | Use TableColSpecGroup + TableColSpec with Width in Style |
Setting widths without ResizeToFitContents(false) | Add ResizeToFitContents(false) to table Style; set absolute ft.Width (not "100%") |
TemplateParagraphStyle.Formats = {Bold(true)} | Use array: Formats = [Bold(true),FontSize("12pt")] |
Template(path,"pdf") to edit existing template | 2-arg creates blank. Use 3-arg: Template(out,"pdf",src) |
| Same path for source and output in Template constructor | OPC cannot read/write simultaneously. Use different paths, then movefile |
Setting PDFPageLayout.PageSize.Orientation without rotate() | Call rotate(pl) — swaps Width/Height AND sets Orientation |
Using DOCXPageLayout without explicit Height and Width | DOCX does not auto-swap — set both explicitly |
Page numbers resetting after PDFPageLayout | Set pl.FirstPageNumber = '' (empty string) to continue numbering |
| Wrapping reporter in Paragraph to center it | Customize the reporter's template style via Template API |
Using RawText(html) for HTML in PDF | Use HTMLFile(path) or HTML(string) — works for any format |
Using Group in a Table cell array | Use nested cell arrays: Table({{img,caption},desc}) |
Passing MATLAB table() to BaseTable | Pass FormalTable(headers,body) — avoids MATLABTable wrapper |
e.Style = {BackgroundColor("yellow")} (overwrites existing styles) | Append: e.Style = [e.Style, {BackgroundColor("yellow")}] — preserves inherited styles |
Force-fitting fields into TitlePage.Subtitle | Create a custom title page reporter via customizeReporter |
| Writing custom reporter class from scratch | Use customizeReporter to scaffold — creates required binary templates |
Writing classdef before running customizeReporter | Scaffolding overwrites classdef files. Scaffold first, then edit |
Unqualified TitlePage.getClassFolder() in package | Use fully-qualified: mypkg.TitlePage.getClassFolder() |
getStyle(ss,name,type) for PDF/HTML | Type arg returns []. Use getStyle(ss,name) without type |
OuterMargin("12pt","6pt","0","0") for vertical spacing | Args are (left,right,top,bottom) — NOT CSS order. Use OuterMargin("0","0","12pt","6pt") for top/bottom spacing |
Using TemplateCharacterStyle | Does not exist. Use TemplateTextStyle for character/inline styles in PDF/HTML |
Unzipping .pdftx/.htmtx/.dotx to edit with fileread/regexprep | ALWAYS use DOM Template API — Template(out,fmt,src) + open + modify objects + close. Raw edits bypass framework validation |
find_system + DiagramFinder for discovery | Use SystemDiagramFinder with filter properties |
Diagram(result.Path) on ChartDiagramFinder results | Use getReporter(result) — chart paths are invalid for Diagram constructor |
find() + for loop on finders | Always use iterator: while finder.hasNext() / result = finder.next() |
BlockFinder with SearchDepth=inf expecting referenced models | BlockFinder does NOT traverse Model References. Use SystemDiagramFinder (IncludeReferencedModels=true) + per-system BlockFinder (SearchDepth=1) |
ExecutionOrder on virtual subsystem | Check get_param(obj,'IsSubsystemVirtual') first |
ExecutionOrder/SystemIO on Simulink Functions | Guard with slreportgen.utils.isSimulinkFunction(result.Object) |
Conventions
Always
close(rpt)after appending all content — generates the output fileAlways
rptviewordocviewto open DOCX — neverwinopenoropenUse
figure("Visible","off")for plots destined for reportsUse
exportgraphics(notprint) when saving figures to filesOne Chapter = one numbering scope — figures/tables numbered Chapter-Sequence (e.g., "Figure 2-1")
BaseTablewrapsFormalTable— passFormalTable(headers,body), not a MATLABtable()Cell-level styling: Use
entry(t,row,col)after construction, not duringTemplate styles use
[]arrays; inline.Styleproperties use{}Reporters in
@ClassNamedirectories — each needs its ownresources/templates/Scaffold ALL reporters before editing ANY —
customizeReportercreates binary templates + overwrites classdefFix unqualified class names after scaffolding — use package-qualified names
Customize all output formats — PDF/Word/HTML templates are independent
Simulink: Always
slreportgen.report.Report; alwaysDiagram.Snapshot.ScaleToFit = trueSimulink finders: Use
.Objecthandle (not path string) forget_param; useresult.Namefor titlesJSON is single source of truth for multi-reporter packages — never hardcode style values
Viewing and Processing Reports
rptview(rpt); % Open in system viewer (updates DOCX fields)
rptview("MyReport.docx","pdf"); % Convert DOCX to PDF via Word
docview("Report.docx","updatefields","closedoc","closeapp"); % Update without displayVerification: Running without error does NOT confirm correctness. After close(rpt):
Check
isfile(rpt.OutputPath)anddir(rpt.OutputPath).bytes > 1000For PDF: call
open(rpt), then setrpt.Document.RetainFO = truebefore appending content, search*_FO/*.fofilesFor DOCX: unzip and search
word/document.xmlAssert expected titles, headings, captions appear in output
See references/report-api-patterns.md for full verification patterns.
Required Toolbox
MATLAB Report Generator (verify with mcp__matlab__detect_matlab_toolboxes). Simulink Report Generator additionally required for Simulink model reports.
Copyright 2026 The MathWorks, Inc.
Files
- ATTRIBUTION.mdAdded by AutoGineer1.1 KiB
- LICENSELicence file added by AutoGineer1.4 KiB
- SKILL.md17.1 KiB
- manifest.yaml598 B
- references/custom-reporters.md39.1 KiB
- references/data-driven-report-pattern.md13.1 KiB
- references/dom-api-patterns.md31.0 KiB
- references/finders-and-reporters.md13.1 KiB
- references/report-api-patterns.md7.2 KiB
- references/report-package.md15.8 KiB
- references/simulink-report.md19.9 KiB
- references/template-reference.md38.1 KiB
- references/template-system.md30.9 KiB
references/simulink-report.md
Simulink Report Generation
Generate structured reports from Simulink models using finders to extract model content and reporters to format it.
Core Concepts
Direct Reporters (known path)
When you know the system or block path, construct the reporter directly:
append(ch,slreportgen.report.Diagram("model/Subsystem"));
append(ch,slreportgen.report.SystemIO("model/Subsystem"));
append(ch,slreportgen.report.ExecutionOrder(modelName));
append(ch,slreportgen.report.LookupTable(blockPath));Finder Pattern (discovery)
When you need to discover content (all subsystems, all blocks of a type), use finders:
finder = slreportgen.finder.SystemDiagramFinder(modelName);
results = find(finder);
for i = 1:numel(results)
append(chapter,results(i));
endUse getReporter(result) instead of constructing reporters manually — returns a specialized reporter matched to the block type.
Workflow
Load the model —
load_system(modelName)Create the report — always use
slreportgen.report.Report(notmlreportgen.report.Report)Add structure — TitlePage, TableOfContents, Chapter, Section from
mlreportgen.report.*Use finders — extract diagrams, blocks, or other content from the model
Append results — append finder results (or reporters) to chapters/sections
Close —
close(rpt)generates the output file
load_system(modelName);
rpt = slreportgen.report.Report(outputPath,"pdf");
append(rpt,mlreportgen.report.TitlePage("Title","Model Report"));
append(rpt,mlreportgen.report.TableOfContents());
ch = mlreportgen.report.Chapter("Title","Diagrams");
append(rpt,ch);
close(rpt);Why slreportgen.report.Report? It extends mlreportgen.report.Report with model compilation support. Reporters like SystemIO and ExecutionOrder require compilation — they error with the base class.
Patterns
Root Diagram + All Subsystems
Use a direct reporter for the root (known path). Use SystemDiagramFinder for subsystems. Always use the iterator pattern (hasNext/next) — never find() + for loop. The iterator enables AutoCloseModel to close each model after processing and avoids holding all results in memory.
% Root diagram — direct reporter
rootDiag = slreportgen.report.Diagram(modelName);
rootDiag.Snapshot.ScaleToFit = true;
append(rootChapter,rootDiag);
% All subsystems, sorted alphabetically — iterator pattern
subFinder = slreportgen.finder.SystemDiagramFinder(modelName);
subFinder.IncludeRoot = false;
subFinder.SortType = "alphabetical";
while subFinder.hasNext()
subResult = subFinder.next();
sec = mlreportgen.report.Section("Title",subResult.Name);
append(sec,subResult);
append(subsysChapter,sec);
endSingle-Pass: All Diagrams via SystemDiagramFinder
When all diagrams receive uniform treatment, use a single finder with IncludeRoot = true:
finder = slreportgen.finder.SystemDiagramFinder(modelName);
finder.IncludeRoot = true;
finder.SortType = "alphabetical";
while finder.hasNext()
result = finder.next();
sec = mlreportgen.report.Section("Title",result.Name);
d = getReporter(result);
d.Snapshot.ScaleToFit = true;
append(sec,d);
append(ch,sec);
endSystemDiagramFinder Filter Properties
Key defaults: IncludeRoot=true, SearchDepth=Inf, IncludeReferencedModels=true, SortType="none", IncludeCommented=false, IncludeVariants="Active".
Set IncludeReferencedModels = false when you only want subsystems of the top model (avoids returning block_diagram objects that lack IsSubsystemVirtual).
See finders-and-reporters.md for the full property table.
Per-Diagram Page Orientation
Computing Orientation
function orientation = getSystemOrientation(systemHandle)
arguments
systemHandle (1,1) double
end
orientation = "portrait";
try
finder = slreportgen.finder.BlockFinder(systemHandle);
finder.SearchDepth = 1;
results = find(finder);
if isempty(results), return; end
positions = cell2mat(arrayfun( ...
@(r) get_param(r.Object,"Position"),results,"UniformOutput",false)');
width = max(positions(:,3))-min(positions(:,1));
height = max(positions(:,4))-min(positions(:,2));
if width > height % strictly wider → landscape; equal or taller → portrait
orientation = "landscape";
end
catch
end
endPDF Orientation
Clone the chapter's template PDFPageLayout (via getImpl) for each page break. Call rotate(pl) for landscape.
Critical rules:
Never use a bare
PDFPageLayout— it has NO headers/footers. Always clone from the chapter template.Never append
PDFPageLayoutas first item in a chapter (blank page) — put content first.Set
pl.FirstPageNumber = ''to continue numbering; remove first-page header; injectCustomElement("fo:marker")to restore chapter title in headers.ch.Layout.Landscapecontrols the first page only.
import mlreportgen.report.*
import mlreportgen.dom.*
ch = Chapter("Title",modelName);
% Extract the chapter's template layout (has headers/footers/rules)
tempRpt = Report(fullfile(tempdir,"tmp_layout"),"pdf");
tempCh = Chapter("Title","tmp");
open(tempRpt);
docPart = getImpl(tempCh,tempRpt);
chLayout = docPart.Children(1); % PDFPageLayout with headers/footers
close(tempRpt);
% Root diagram — fills chapter's initial page
rootOrientation = getSystemOrientation(get_param(modelName,"Handle"));
ch.Layout.Landscape = (rootOrientation == "landscape");
rootDiag = slreportgen.report.Diagram(modelName);
rootDiag.Snapshot.ScaleToFit = true;
append(ch,rootDiag);
% Subsystems — clone layout for each page break
subFinder = slreportgen.finder.SystemDiagramFinder(modelName);
subFinder.IncludeRoot = false;
subFinder.SortType = "alphabetical";
chapterTitle = "Chapter 1. " + modelName;
while subFinder.hasNext()
subResult = subFinder.next();
pl = clone(chLayout);
orientation = getSystemOrientation(subResult.Object);
if orientation == "landscape"
rotate(pl);
end
pl.FirstPageNumber = '';
% Remove first-page header (empty — hides StyleRef)
firstIdx = strcmp({pl.PageHeaders.PageType},"first");
pl.PageHeaders = pl.PageHeaders(~firstIdx);
append(ch,pl);
% Re-inject chapter title marker for header StyleRef
marker = CustomElement("fo:marker");
marker.CustomAttributes = CustomAttribute("marker-class-name","SectionTitle1");
append(marker,Text(chapterTitle));
anchor = Paragraph();
anchor.Style = {FontSize("1pt"),OuterMargin("0pt","0pt","0pt","0pt"),...
LineSpacing(0.01),Color("white")};
append(anchor,marker);
append(ch,anchor);
sec = Section("Title",subResult.Name);
d = getReporter(subResult);
d.Snapshot.ScaleToFit = true;
append(sec,d);
append(ch,sec);
endVariant: Introductory Content Before Diagrams
When text appears before diagrams, keep chapter in portrait and give the root diagram its own PDFPageLayout:
ch.Layout.Landscape = false; % Portrait for intro text
introSec = Section("Title","Introduction");
append(introSec,Paragraph("This report documents the " + modelName + " model."));
append(ch,introSec);
% Root diagram gets its OWN PDFPageLayout
rootPl = clone(chLayout);
rootOrientation = getSystemOrientation(get_param(modelName,"Handle"));
if rootOrientation == "landscape"
rotate(rootPl);
end
rootPl.FirstPageNumber = '';
firstIdx = strcmp({rootPl.PageHeaders.PageType},"first");
rootPl.PageHeaders = rootPl.PageHeaders(~firstIdx);
append(ch,rootPl);
% Re-inject marker (same pattern as subsystems)...Word (.docx) Orientation
Much simpler than PDF — no cloning, markers, or FirstPageNumber needed:
while finder.hasNext()
result = finder.next();
orientation = getSystemOrientation(result.Object);
if orientation == "landscape"
pl = DOCXPageLayout();
pl.PageSize.Orientation = "landscape";
pl.PageSize.Height = "8.5in";
pl.PageSize.Width = "11in";
else
pl = DOCXPageLayout();
pl.PageSize.Orientation = "portrait";
pl.PageSize.Height = "11in";
pl.PageSize.Width = "8.5in";
end
append(ch,pl);
sec = Section("Title",result.Name);
d = getReporter(result);
d.Snapshot.ScaleToFit = true;
append(sec,d);
append(ch,sec);
endWord section breaks preserve headers and numbering automatically. Always use rptview(rpt) to view Word output.
Centering Diagram Output
Reporters cannot be wrapped in DOM elements for centering. Customize the DiagramImage style in the Diagram template. Create once at script start, set TemplateSrc on every Diagram reporter.
PDF Centering
import mlreportgen.dom.*
srcPath = fullfile(tempdir,"diagram_src.pdftx");
slreportgen.report.Diagram.createTemplate(srcPath,"pdf");
centeredTemplatePath = fullfile(tempdir,"centered_diagram.pdftx");
tpl = Template(centeredTemplatePath,"pdf",srcPath);
open(tpl);
diagStyle = getStyle(tpl.Stylesheet,"DiagramImage");
diagStyle.RawFormats = strtrim(diagStyle.RawFormats) + " text-align: center;";
replaceStyle(tpl.Stylesheet,diagStyle);
close(tpl);Word Centering
import mlreportgen.dom.*
srcPath = fullfile(tempdir,"diagram_src.dotx");
slreportgen.report.Diagram.createTemplate(srcPath,"docx");
centeredTemplatePath = fullfile(tempdir,"centered_diagram.dotx");
tpl = Template(centeredTemplatePath,"docx",srcPath);
open(tpl);
% CRITICAL: Create fresh TemplateLinkedStyle — do NOT mutate TemplateDOCXStyle from getStyle
ss = tpl.Stylesheet;
for styleName = ["DiagramImage","DiagramCaption"]
newStyle = TemplateLinkedStyle(styleName);
newStyle.Formats = [HAlign("center")];
replaceStyle(ss,newStyle);
end
close(tpl);Centering Summary
| Aspect | Word | |
|---|---|---|
| Template extension | .pdftx | .dotx |
| Style type | TemplatePDFStyle | TemplateLinkedStyle (fresh) |
| How to center | RawFormats += " text-align: center;" | Formats = [HAlign("center")] |
| Style names | DiagramImage | DiagramImage AND DiagramCaption |
Then apply: d.TemplateSrc = centeredTemplatePath;
Verifying Word centering: Word applies centering via style reference, not inline. Check styles.xml (inside the unzipped DOCX) for <w:jc w:val="center"/> inside the DiagramImage style definition. In document.xml, paragraphs reference the style by name (w:val="DiagramImage") — you won't find w:jc inline in the body.
System I/O Documentation
SystemIO reports inputs and outputs. Requires model compilation. Guard against Simulink Functions:
finder = slreportgen.finder.SystemDiagramFinder(modelName);
finder.IncludeRoot = false;
finder.IncludeReferencedModels = false;
while finder.hasNext()
result = finder.next();
if slreportgen.utils.isSimulinkFunction(result.Object), continue; end
sec = mlreportgen.report.Section("Title",result.Name + " I/O");
append(sec,slreportgen.report.SystemIO(result.Path));
append(chapter,sec);
endExecution Order with Guards
ExecutionOrder only works on root model and nonvirtual subsystems. Two guards required:
while finder.hasNext()
result = finder.next();
if slreportgen.utils.isSimulinkFunction(result.Object), continue; end
if strcmp(get_param(result.Object,'IsSubsystemVirtual'),'on'), continue; end
append(sec,slreportgen.report.ExecutionOrder(result.Path));
endSet IncludeReferencedModels = false to avoid block_diagram objects that lack IsSubsystemVirtual.
LookupTable with Page-Fitting Plot
lutReporter = slreportgen.report.LookupTable(blockPath);
lutReporter.PlotReporter.Snapshot.ScaleToFit = true;
append(chapter,lutReporter);Property Table Customization
Use getReporter(result) to get a SimulinkObjectProperties reporter. Use a nested function (not local) for TableEntryUpdateFcn:
function generateCompactReport(modelName,outputPath)
arguments
modelName (1,1) string
outputPath (1,1) string
end
load_system(modelName);
rpt = slreportgen.report.Report(outputPath,"html");
ch = mlreportgen.report.Chapter("Title","Block Properties");
finder = slreportgen.finder.BlockFinder(modelName);
finder.SearchDepth = 1;
results = find(finder);
for i = 1:numel(results)
sec = mlreportgen.report.Section("Title",results(i).Name);
reporter = getReporter(results(i));
if isa(reporter,"slreportgen.report.SimulinkObjectProperties")
reporter.PropertyTable.TableEntryUpdateFcn = @compactEntry;
end
append(sec,reporter);
append(ch,sec);
end
append(rpt,ch);
close(rpt);
% Nested function — executes in getImpl scope reliably
function entry = compactEntry(entry)
for k = 1:numel(entry.Children)
child = entry.Children(k);
if isa(child,"mlreportgen.dom.Paragraph")
child.Style = [child.Style, ...
{mlreportgen.dom.OuterMargin("0pt","0pt","0pt","0pt")}];
end
end
end
endWhy nested functions? Local functions can silently fail during getImpl. For scripts, save the callback as a standalone .m file on the path.
Stateflow Chart Reporting
Use ChartDiagramFinder to discover Stateflow charts. Always use getReporter(result) — never construct Diagram(result.Path) directly, as chart finder results may contain paths that are invalid for the Diagram constructor.
chartFinder = slreportgen.finder.ChartDiagramFinder(modelName);
while chartFinder.hasNext()
result = chartFinder.next();
sec = mlreportgen.report.Section("Title",result.Name);
chartReporter = getReporter(result);
chartReporter.Snapshot.ScaleToFit = true;
append(sec,chartReporter);
append(ch,sec);
endStateflow Chart Elements (States, Transitions)
For detailed chart element reporting, use DiagramElementFinder on a known chart path:
sfFinder = slreportgen.finder.DiagramElementFinder(chartPath);
sfResults = find(sfFinder);
for i = 1:numel(sfResults)
append(sec,getReporter(sfResults(i)));
endFinding Blocks Across Referenced Models
BlockFinder does not have IncludeReferencedModels — it only searches within its container system. To find specific block types across the entire model hierarchy (including referenced models), combine SystemDiagramFinder with per-system BlockFinder:
% Find all Lookup_n-D blocks including those in referenced models
allSysFinder = slreportgen.finder.SystemDiagramFinder(modelName);
allSysFinder.IncludeRoot = true;
allSysFinder.IncludeReferencedModels = true;
while allSysFinder.hasNext()
sysResult = allSysFinder.next();
bf = slreportgen.finder.BlockFinder(sysResult.Object);
bf.BlockTypes = "Lookup_n-D";
bf.SearchDepth = 1;
while bf.hasNext()
result = bf.next();
lutReporter = slreportgen.report.LookupTable(result.BlockPath);
lutReporter.PlotReporter.Snapshot.ScaleToFit = true;
append(ch,lutReporter);
end
endFinding MATLAB Function Blocks
MATLAB Function blocks are internally SubSystem blocks — BlockFinder cannot search for them by type. Use BlockFinder for SubSystem + slreportgen.utils.isMATLABFunction to identify them:
allSysFinder = slreportgen.finder.SystemDiagramFinder(modelName);
allSysFinder.IncludeRoot = true;
allSysFinder.IncludeReferencedModels = true;
while allSysFinder.hasNext()
sysResult = allSysFinder.next();
bf = slreportgen.finder.BlockFinder(sysResult.Object);
bf.BlockTypes = "SubSystem";
bf.SearchDepth = 1;
while bf.hasNext()
result = bf.next();
if slreportgen.utils.isMATLABFunction(result.Object)
append(ch,slreportgen.report.MATLABFunction(result.BlockPath));
end
end
endSignal Documentation
Use SignalFinder to document named signals. Filter with IncludeUnnamedSignals = false to focus on intentionally named signals:
sigFinder = slreportgen.finder.SignalFinder(modelName);
sigFinder.IncludeUnnamedSignals = false;
sigResults = find(sigFinder);
for i = 1:numel(sigResults)
sigName = string(sigResults(i).Name);
% Use getReporter for detailed signal documentation
append(sec,getReporter(sigResults(i)));
endSignalFinder key properties: IncludeInputSignals, IncludeOutputSignals, IncludeControlSignals, IncludeInternalSignals, IncludeVirtualBlockSignals, IncludeUnnamedSignals, SearchDepth, SortType.
Common Mistakes
| Mistake | Correct Approach |
|---|---|
Using mlreportgen.report.Report | slreportgen.report.Report — needed for compilation |
find_system for diagram discovery | SystemDiagramFinder with filter properties |
find_system for block positions | BlockFinder(systemHandle) with SearchDepth=1 |
| Constructing reporters manually from results | getReporter(result) — returns specialized reporter |
Local function for TableEntryUpdateFcn | Nested function (or standalone .m file for scripts) |
Path string with get_param on finder results | Use .Object handle — path strings fail for Stateflow |
ExecutionOrder on virtual subsystem | Check IsSubsystemVirtual first |
ExecutionOrder/SystemIO on Simulink Functions | slreportgen.utils.isSimulinkFunction(result.Object) |
Not setting Diagram.Snapshot.ScaleToFit | Always set true unless native resolution needed |
| Wrapping reporter in Paragraph to center | Customize template style via Template API |
PDFPageLayout as first item in chapter | Blank page — put content first |
Bare PDFPageLayout without cloning | No headers — clone via getImpl |
Paragraph(marker) with CustomElement | Create Paragraph() first, then append(anchor,marker) |
| PDF centering approach for Word | Word uses HAlign("center") in Formats, not CSS |
Mutating getStyle result for Word | Create fresh TemplateLinkedStyle + replaceStyle |
Centering only DiagramImage in Word | Also center DiagramCaption |
DOCXPageLayout without explicit dimensions | Set both Height and Width explicitly |
BlockFinder with SearchDepth=inf to find blocks in referenced models | BlockFinder does not traverse Model Reference blocks. Use SystemDiagramFinder (with IncludeReferencedModels=true) + per-system BlockFinder (SearchDepth=1) |
Diagram(chartResult.Path) on ChartDiagramFinder results | Use getReporter(result) — chart paths may be invalid for Diagram constructor |
| No way to find MATLAB Function blocks via BlockFinder | They are SubSystem blocks internally. Use BlockFinder for SubSystem + slreportgen.utils.isMATLABFunction(result.Object) |
find(finder) + for loop to iterate results | Use while finder.hasNext() / finder.next() — enables memory-efficient processing and AutoCloseModel |
Conventions
Always
slreportgen.report.Reportfor Simulink contentAlways iterate finders with
while finder.hasNext()/finder.next()— neverfind()+ for loopDirect reporters when path known; finders +
getReporterfor discoveryAlways
SystemDiagramFinderfor diagram discoveryAlways
.Objecthandle (not path string) forget_paramAlways guard
SystemIO/ExecutionOrderwithisSimulinkFunctionAlways
Diagram.Snapshot.ScaleToFit = trueUse
result.Namefor display titlesNever unzip/zip templates — use Template API
Never local functions for
TableEntryUpdateFcnAlways
rptview(rpt)to open DOCX — neverwinopenNever
close_systembeforeclose(rpt)—slreportgen.report.Reportkeeps the model compiled during generationBlockFinder cannot traverse referenced models — combine with
SystemDiagramFinderfor full hierarchy search
Copyright 2026 The MathWorks, Inc.
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Needs an MCP server
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- MathWorks
- Publisher
- MathWorks (Official)
- Source
- matlab/matlab-agentic-toolkit · skills-catalog/reporting-and-database-access/matlab-generate-report · commit 2a7f215
- Licence
- BSD 2-Clause License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE.md)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by MathWorks or MathWorks.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download matlab-generate-report.zip