Generated banner for Matlab Generate Report
Generated logo for Matlab Generate Report

Matlab Generate Report

MathWorksOfficialCreated by MathWorks

  • Skill
  • Tool integration
  • Science and research
  • BSD-2-Clause
  • No issues found

From the author

Unified skill for all MATLAB and Simulink report generation tasks. Covers report generation, PDF report, document generation, mlreportgen, Report Generator, template, TitlePage, Chapter, multipage HTML, HTMLPage, html-multipage, custom reporter, customizeReporter, template hole, page header, page border, company style package, branded reporters, buildTemplates, Simulink report, model documentation, slreportgen, block diagram report, model report, subsystem documentation, SystemDiagramFinder, SystemIO, ExecutionOrder, LookupTable, template style, page footer, TemplateSrc, report package, table variants, multiple HTML pages, PDF report generation, Word report, DOM API, FormalTable, BaseTable, Figure, FormalImage, Section.
— the description by MathWorks

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

  1. Download the skill as a ZIP:

    https://mp-staging.autogineer.com/agent-skills/matlab/matlab-generate-report/download
  2. Unzip 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, writematrix

  • Live 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);
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:

  1. List all content/format requirements — title page fields, page borders, headers/footers, branded styling

  2. Check built-in reporters. Built-in TitlePage has: Title, Subtitle, Author, Publisher, PubDate, Image. Built-in Chapter/Section provide headings, auto-numbering, and a Content hole.

  3. If built-in reporters meet all requirements, use them directly

  4. If any requirement is unmet, create custom reporters:

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, verificationreferences/report-api-patterns.md
Work with DOM tables, HTML inclusion, multipage HTML, Number/NumberFormatreferences/dom-api-patterns.md
Understand template file types, locate/inspect templatesreferences/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 buildTemplatesreferences/report-package.md
Generate Simulink model reports (finders, orientation, centering)references/simulink-report.md
Look up all Simulink finders and reportersreferences/finders-and-reporters.md
Iterate struct arrays into chapters with custom reportersreferences/data-driven-report-pattern.md
Edit template styles (colors, fonts, headers, footers, TOC)references/template-system.md

Key Functions

ClassPurposePackage
ReportTop-level report containermlreportgen.report
TitlePageTitle page with title, subtitle, authormlreportgen.report
TableOfContentsAuto-generated TOCmlreportgen.report
Chapter / SectionDocument structuremlreportgen.report
FigureAuto-numbered figure from MATLAB figuremlreportgen.report
FormalImageAuto-numbered image from file with captionmlreportgen.report
BaseTableAuto-numbered table wrapper (pass FormalTable)mlreportgen.report
FormalTableTable with header/body/footer from cell arraysmlreportgen.dom
Template (3-arg)Edit templates: Template(out,fmt,src)mlreportgen.dom
HTMLFile / HTMLInclude HTML content in any output formatmlreportgen.dom
HTMLPagePage in multipage HTML document (R2024a+)mlreportgen.dom
NumberNumeric DOM object (use with NumberFormat)mlreportgen.dom
TemplateHolePlaceholder filled at report timemlreportgen.dom
Page / NumPagesPage number / total pagesmlreportgen.dom
*.customizeReporterScaffold custom reporter + templatesmlreportgen.report
getStyle / replaceStyleModify template stylesmlreportgen.dom
slreportgen.report.ReportReport container for Simulink contentslreportgen.report
slreportgen.report.DiagramDiagram snapshot of a systemslreportgen.report
slreportgen.finder.SystemDiagramFinderFind system/subsystem diagramsslreportgen.finder
slreportgen.report.SystemIOReport inputs/outputs (requires compilation)slreportgen.report
slreportgen.report.ExecutionOrderReport block execution orderslreportgen.report
slreportgen.report.LookupTableReport lookup table data + plotslreportgen.report
rptviewDisplay report (updates DOCX fields)function
docviewProcess Word documents (update fields, convert)function

Common Mistakes

MistakeCorrect Approach
Using mlreportgen.dom.Document as report containerUse mlreportgen.report.Report. Exception: multipage HTML requires Document with "html-multipage"
Using mlreportgen.report.Report for Simulink contentUse slreportgen.report.Report — needed for model compilation
Using Report with "html" for multipage outputUse 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 cellsUse 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 headersCustomize ALL page types: "first", "default", "even" — but differentiate content (see below)
Putting StyleRef (chapter title) in the first-page headerFirst page already displays the chapter heading — omit StyleRef from "first" header. Use it only in "default"/"even" for wayfinding
Opening DOCX with winopen/open/startUse rptview(rpt) or docview(file,"updatefields") — triggers field update
Using ColSpec/ColSpecGroup for widthsUse 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 template2-arg creates blank. Use 3-arg: Template(out,"pdf",src)
Same path for source and output in Template constructorOPC 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 WidthDOCX does not auto-swap — set both explicitly
Page numbers resetting after PDFPageLayoutSet pl.FirstPageNumber = '' (empty string) to continue numbering
Wrapping reporter in Paragraph to center itCustomize the reporter's template style via Template API
Using RawText(html) for HTML in PDFUse HTMLFile(path) or HTML(string) — works for any format
Using Group in a Table cell arrayUse nested cell arrays: Table({{img,caption},desc})
Passing MATLAB table() to BaseTablePass 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.SubtitleCreate a custom title page reporter via customizeReporter
Writing custom reporter class from scratchUse customizeReporter to scaffold — creates required binary templates
Writing classdef before running customizeReporterScaffolding overwrites classdef files. Scaffold first, then edit
Unqualified TitlePage.getClassFolder() in packageUse fully-qualified: mypkg.TitlePage.getClassFolder()
getStyle(ss,name,type) for PDF/HTMLType arg returns []. Use getStyle(ss,name) without type
OuterMargin("12pt","6pt","0","0") for vertical spacingArgs are (left,right,top,bottom) — NOT CSS order. Use OuterMargin("0","0","12pt","6pt") for top/bottom spacing
Using TemplateCharacterStyleDoes not exist. Use TemplateTextStyle for character/inline styles in PDF/HTML
Unzipping .pdftx/.htmtx/.dotx to edit with fileread/regexprepALWAYS use DOM Template API — Template(out,fmt,src) + open + modify objects + close. Raw edits bypass framework validation
find_system + DiagramFinder for discoveryUse SystemDiagramFinder with filter properties
Diagram(result.Path) on ChartDiagramFinder resultsUse getReporter(result) — chart paths are invalid for Diagram constructor
find() + for loop on findersAlways use iterator: while finder.hasNext() / result = finder.next()
BlockFinder with SearchDepth=inf expecting referenced modelsBlockFinder does NOT traverse Model References. Use SystemDiagramFinder (IncludeReferencedModels=true) + per-system BlockFinder (SearchDepth=1)
ExecutionOrder on virtual subsystemCheck get_param(obj,'IsSubsystemVirtual') first
ExecutionOrder/SystemIO on Simulink FunctionsGuard with slreportgen.utils.isSimulinkFunction(result.Object)

Conventions

  • Always close(rpt) after appending all content — generates the output file

  • Always rptview or docview to open DOCX — never winopen or open

  • Use figure("Visible","off") for plots destined for reports

  • Use exportgraphics (not print) when saving figures to files

  • One Chapter = one numbering scope — figures/tables numbered Chapter-Sequence (e.g., "Figure 2-1")

  • BaseTable wraps FormalTable — pass FormalTable(headers,body), not a MATLAB table()

  • Cell-level styling: Use entry(t,row,col) after construction, not during

  • Template styles use [] arrays; inline .Style properties use {}

  • Reporters in @ClassName directories — each needs its own resources/templates/

  • Scaffold ALL reporters before editing ANY — customizeReporter creates binary templates + overwrites classdef

  • Fix unqualified class names after scaffolding — use package-qualified names

  • Customize all output formats — PDF/Word/HTML templates are independent

  • Simulink: Always slreportgen.report.Report; always Diagram.Snapshot.ScaleToFit = true

  • Simulink finders: Use .Object handle (not path string) for get_param; use result.Name for titles

  • JSON 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 display

Verification: Running without error does NOT confirm correctness. After close(rpt):

  • Check isfile(rpt.OutputPath) and dir(rpt.OutputPath).bytes > 1000

  • For PDF: call open(rpt), then set rpt.Document.RetainFO = true before appending content, search *_FO/*.fo files

  • For DOCX: unzip and search word/document.xml

  • Assert 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

references/report-package.md

Multi-Reporter Report Package

Create a cohesive package of custom reporters that share a centralized style config and produce branded reports in PDF, Word, and HTML.


Architecture Overview

+company/
├── styles.json                    ← Single source of truth
├── buildTemplates.m               ← Thin orchestrator
├── setOrAddCss.m                  ← CSS helper utility
├── demo.m                         ← Exercises all reporters, all formats
├── @Report/Report.m               ← Subclasses mlreportgen.report.Report
├── @TitlePage/TitlePage.m
├── @Chapter/Chapter.m
├── @Section/Section.m
├── @DataTable/DataTable.m         ← Table variant: teal header
├── @SpecTable/SpecTable.m         ← Table variant: gold header
├── @SummaryTable/SummaryTable.m   ← Table variant: navy header
└── @FormalImage/FormalImage.m

Each @Reporter/ directory contains resources/templates/{pdf,docx,html}/ with scaffolded template copies that buildTemplates edits in place.

HTML has two templates: default.htmtx (packaged multi-file, used for "html" output type) and default.htmt (single-file, used for "html-file" output type). Edit both.


Workflow

1. Define the Style Config

Create a JSON file as the single source of truth for all visual constants:

{
  "fonts": {"heading": "Segoe UI", "body": "Palatino Linotype"},
  "colors": {"navy": "#1B3A5C", "teal": "#2A7B88", "gold": "#C4952D"},
  "sizes": {"heading1": "20pt", "body": "11pt", "tableHeader": "10pt"},
  "tables": {
    "data": {"headerBackground": "#2A7B88", "headerColor": "#FFFFFF"},
    "spec": {"headerBackground": "#C4952D", "headerColor": "#FFFFFF"},
    "summary": {"headerBackground": "#1B3A5C", "headerColor": "#FFFFFF"},
    "borderColor": "#E2E8F0"
  }
}
Full JSON Schema
{
  "fonts": {
    "heading": "Font family for headings, titles, table titles",
    "body": "Font family for body text and table content",
    "code": "Font family for code blocks"
  },
  "colors": {
    "navy": "#hex — primary brand color (headings, title page)",
    "teal": "#hex — secondary brand color (H3, accent)",
    "gold": "#hex — tertiary brand color (spec tables)",
    "darkGray": "#hex — body text color",
    "lightGray": "#hex — borders, subtle backgrounds",
    "white": "#FFFFFF — table header text",
    "footerGray": "#hex — footer text color"
  },
  "sizes": {
    "heading1": "20pt",
    "heading2": "16pt",
    "heading3": "13pt",
    "body": "11pt",
    "tableHeader": "10pt",
    "tableBody": "10pt",
    "caption": "10pt"
  },
  "page": {
    "size": "letter | A4",
    "orientation": "portrait | landscape",
    "margins": {"top": "0.5in", "bottom": "0.5in", "left": "1in", "right": "1in"}
  },
  "tables": {
    "<variant>": {"headerBackground": "#hex", "headerColor": "#hex"},
    "borderColor": "#hex — shared border color for all variants"
  }
}

Naming conventions: camelCase keys, CSS-compatible values ("11pt", "#1B3A5C"), table variants named by semantic purpose (data, spec, summary) not color.

2. Scaffold All Reporters (MUST Be Done First via MATLAB)

CRITICAL: Run ALL scaffolding commands in MATLAB (via mcp__matlab__evaluate_matlab_code) BEFORE writing any classdef code.

% Run in MATLAB via MCP tool — scaffold ALL reporters before editing ANY
mlreportgen.report.Report.customizeReport("+company/@Report/Report.m");
mlreportgen.report.TitlePage.customizeReporter("+company/@TitlePage/TitlePage.m");
mlreportgen.report.Chapter.customizeReporter("+company/@Chapter/Chapter.m");
mlreportgen.report.Section.customizeReporter("+company/@Section/Section.m");
mlreportgen.report.BaseTable.customizeReporter("+company/@DataTable/DataTable.m");
mlreportgen.report.BaseTable.customizeReporter("+company/@SpecTable/SpecTable.m");
mlreportgen.report.BaseTable.customizeReporter("+company/@SummaryTable/SummaryTable.m");
mlreportgen.report.FormalImage.customizeReporter("+company/@FormalImage/FormalImage.m");

Always use @ClassName directories. Without them, reporters share a single resources/templates/ and overwrite each other's templates.

3. Inspect Scaffolded Templates

Do not assume style names. Inspect the actual templates:

import mlreportgen.dom.*
classDir = company.Chapter.getClassFolder();
tpl = Template(fullfile(tempdir,"inspect.pdftx"),"pdf", ...
    fullfile(classDir,"resources","templates","pdf","default.pdftx"));
open(tpl);
styles = tpl.Stylesheet.TemplateStyles;
for i = 1:numel(styles)
    fprintf("%s | %s\n",styles(i).Name,styles(i).Selector);
end
close(tpl);

Common findings:

  • Chapter/Section: SectionTitle1–SectionTitle6 and SectionContent

  • BaseTable: BaseTableContent (with th and td compound selectors) and BaseTableTitle

  • HTML templates may lack styles that PDF templates have

  • Report templates have no named body style

4. Design Table Variant Subclasses

Create a separate reporter subclass for each table visual variant. Do NOT use a single class with a Variant property.

ConcernSingle class + VariantSeparate subclasses
Template editingMust branch in buildTemplatesEach owns its template tree
IndependenceVariants can't divergeEach can evolve separately
User codeDataTable("Variant","data","Content",ft)DataTable("Content",ft) — simpler
New variantAdd case to switch statementScaffold new class
5. Write buildTemplates Static Methods

Each reporter class owns a static buildTemplates(styles) method. Group formats by editing mechanism:

  • editPdfHtml — PDF and HTML (both use CSS/RawFormats)

  • editDocx — Word (uses TemplateLinkedStyle/TemplateTableStyle + replaceStyle)

methods (Static)
    function buildTemplates(styles)
        classDir = company.Chapter.getClassFolder();
        company.Chapter.editPdfHtml(classDir,"pdf","default.pdftx",styles);
        company.Chapter.editPdfHtml(classDir,"html","default.htmtx",styles);
        company.Chapter.editPdfHtml(classDir,"html","default.htmt",styles);
        company.Chapter.editDocx(classDir,styles);
    end

    function editPdfHtml(classDir,fmt,filename,styles)
        import mlreportgen.dom.*
        srcPath = fullfile(classDir,"resources","templates",fmt,filename);
        tmpPath = fullfile(tempdir,"company_Chapter_" + filename);
        tpl = Template(tmpPath,fmt,srcPath);
        open(tpl);

        entries = getStyle(tpl.Stylesheet,"SectionTitle1");
        for i = 1:numel(entries)
            raw = entries(i).RawFormats;
            raw = company.setOrAddCss(raw,"font-family",styles.fonts.heading);
            raw = company.setOrAddCss(raw,"color",styles.colors.navy);
            raw = company.setOrAddCss(raw,"font-size",styles.sizes.heading1);
            raw = company.setOrAddCss(raw,"font-weight","bold");
            entries(i).RawFormats = raw;
        end

        close(tpl);
        movefile(tmpPath,srcPath);
    end

    function editDocx(classDir,styles)
        import mlreportgen.dom.*
        srcPath = fullfile(classDir,"resources","templates","docx","default.dotx");
        tmpPath = fullfile(tempdir,"company_Chapter.dotx");
        tpl = Template(tmpPath,"docx",srcPath);
        open(tpl);

        s1 = TemplateLinkedStyle("SectionTitle1");
        s1.Formats = [Bold(true),FontSize(styles.sizes.heading1), ...
            FontFamily(styles.fonts.heading),Color(styles.colors.navy), ...
            OutlineLevel(1)];  % REQUIRED — preserves TOC heading discovery
        replaceStyle(tpl.Stylesheet,s1);

        close(tpl);
        movefile(tmpPath,srcPath);
    end
end

Critical rules for editPdfHtml:

  • Use getStyle(stylesheet, name) with NO type argument — type arg returns [] for PDF/HTML

  • Filter by Selector property when multiple entries match

  • Modify RawFormats directly — style objects are handles

Critical rules for editDocx:

  • Use TemplateLinkedStyle for linked styles (titles, headings)

  • Use TemplateTableStyle with HeaderFormats for table header row styling

  • Always replaceStyle(tpl.Stylesheet, newStyle) — DOCX styles are read-only objects

  • Always include OutlineLevel(N) for heading styles to preserve TOC

6. CSS Helper Utility

Safe CSS property replacement using negative lookbehind (prevents matching border-color when editing color):

function raw = setOrAddCss(raw,prop,value)
%setOrAddCss Replace a CSS property in a style string, or append it.
    arguments
        raw string
        prop string
        value string
    end
    pattern = "(?<![a-zA-Z-])" + regexptranslate("escape",prop) + ":\s*[^;]+";
    replacement = prop + ": " + value;
    if ~isempty(regexp(raw,pattern,"once"))
        raw = regexprep(raw,pattern,replacement);
    else
        raw = raw + " " + prop + ": " + value + ";";
    end
end
7. Thin Orchestrator
function buildTemplates()
    pkgDir = fileparts(mfilename("fullpath"));
    styles = jsondecode(fileread(fullfile(pkgDir,"styles.json")));

    company.Chapter.buildTemplates(styles);
    company.Section.buildTemplates(styles);
    company.TitlePage.buildTemplates(styles);
    company.DataTable.buildTemplates(styles);
    company.SpecTable.buildTemplates(styles);
    company.SummaryTable.buildTemplates(styles);

    fprintf("buildTemplates: All templates updated.\n");
end
8. Table Variant Template Editing

Each table subclass implements the same pattern with its variant-specific config:

function buildTemplates(styles)
    classDir = company.DataTable.getClassFolder();
    variant = styles.tables.data;  % ← variant-specific config
    company.DataTable.editTablePdfHtml(classDir,"pdf","default.pdftx",variant,styles);
    company.DataTable.editTablePdfHtml(classDir,"html","default.htmtx",variant,styles);
    company.DataTable.editTableDocx(classDir,variant,styles);
end

function editTablePdfHtml(classDir,fmt,filename,variant,styles)
    import mlreportgen.dom.*
    srcPath = fullfile(classDir,"resources","templates",fmt,filename);
    tmpPath = fullfile(tempdir,"company_DataTable_" + filename);
    tpl = Template(tmpPath,fmt,srcPath);
    open(tpl);

    entries = getStyle(tpl.Stylesheet,"BaseTableContent");
    for i = 1:numel(entries)
        if contains(entries(i).Selector,"th")
            raw = entries(i).RawFormats;
            raw = company.setOrAddCss(raw,"background-color",variant.headerBackground);
            raw = company.setOrAddCss(raw,"color",variant.headerColor);
            raw = company.setOrAddCss(raw,"font-size",styles.sizes.tableHeader);
            entries(i).RawFormats = raw;
        elseif contains(entries(i).Selector,"td")
            raw = entries(i).RawFormats;
            raw = company.setOrAddCss(raw,"font-size",styles.sizes.tableBody);
            raw = company.setOrAddCss(raw,"border-color",styles.tables.borderColor);
            entries(i).RawFormats = raw;
        end
    end

    close(tpl);
    movefile(tmpPath,srcPath);
end

function editTableDocx(classDir,variant,styles)
    import mlreportgen.dom.*
    srcPath = fullfile(classDir,"resources","templates","docx","default.dotx");
    tmpPath = fullfile(tempdir,"company_DataTable.dotx");
    tpl = Template(tmpPath,"docx",srcPath);
    open(tpl);

    ts = TemplateTableStyle("BaseTableContent");
    ts.Formats = [Border("solid",styles.tables.borderColor,"0.5pt"), ...
        FontSize(styles.sizes.tableBody),FontFamily(styles.fonts.body)];
    ts.HeaderFormats = [Bold(true), ...
        BackgroundColor(variant.headerBackground), ...
        Color(variant.headerColor), ...
        FontSize(styles.sizes.tableHeader)];
    replaceStyle(tpl.Stylesheet,ts);

    close(tpl);
    movefile(tmpPath,srcPath);
end

SpecTable and SummaryTable are identical except they reference styles.tables.spec and styles.tables.summary.

Adding a New Table Variant
  1. Add entry in JSON: "alert": {"headerBackground": "#DC2626", "headerColor": "#FFFFFF"}

  2. Scaffold: mlreportgen.report.BaseTable.customizeReporter("+company/@AlertTable/AlertTable.m")

  3. Add buildTemplates(styles) reading styles.tables.alert

  4. Add company.AlertTable.buildTemplates(styles) to orchestrator

9. Demo Script
function demo(fmt)
    arguments
        fmt (1,1) string {mustBeMember(fmt,["pdf","docx","html"])} = "pdf"
    end
    import mlreportgen.report.*
    import mlreportgen.dom.*

    company.buildTemplates;
    rpt = company.Report(fullfile(tempdir,"CompanyDemo"),fmt);

    tp = company.TitlePage();
    tp.Title = "Q3 2026 Engineering Report";
    tp.Author = "J. Smith";
    add(rpt,tp);

    ch = company.Chapter("Title","Test Results");
    sec = company.Section("Title","Tensile Data");
    add(sec,Paragraph("Specimens tested per ASTM E8."));

    header = ["Specimen","UTS (MPa)","Elongation"];
    body = {num(1,"%.0f"),num(250,"%.0f"),num(0.12,"%.2f"); ...
            num(2,"%.0f"),num(275,"%.0f"),num(0.15,"%.2f")};
    ft = FormalTable(header,body);
    dt = company.DataTable("Content",ft,"Title","Tensile Results");
    add(sec,dt);
    add(ch,sec);
    add(rpt,ch);

    close(rpt);
    rptview(rpt);
end

function n = num(value,fmt)
    import mlreportgen.dom.*
    n = Number(value);
    n.Style = [n.Style {NumberFormat(fmt)}];
end
10. Build and Verify
company.buildTemplates;
for fmt = ["pdf","docx","html"]
    company.demo(fmt);
end

Verify:

  • All three formats produce output without errors

  • Styles are applied symmetrically (same elements styled in PDF, DOCX, and HTML)

  • Table headers show correct variant colors

  • Numbers display with specified precision


Common Mistakes

MistakeCorrect Approach
Using table() objects for report tablesUse FormalTable(headerCells, bodyCells)
Raw numeric literals in cell arraysUse Number + NumberFormat style
Number(value, NumberFormat(...)) constructorn = Number(value); n.Style = [n.Style {NumberFormat(fmt)}];
getStyle(ss, name, type) for PDF/HTMLUse getStyle(ss, name) without type; filter by Selector
Unqualified Chapter.getClassFolder() in packageUse company.Chapter.getClassFolder() (package-qualified)
Single table class with Variant propertySeparate subclass per variant, each with own template tree
Monolithic buildTemplates.m with all logicEach reporter owns a static buildTemplates(styles) method
Runtime style class (AcmeStyle.HeadingFont)Use template stylesheets edited by buildTemplates
tmpPath without file extensionInclude extension: fullfile(tempdir,"prefix_" + filename)
Assuming style names without inspectingAlways inspect scaffolded templates first
Styling in DOCX but not PDF/HTMLUse editPdfHtml + editDocx symmetrically
DataTable(data,"Title","name") positional+NVUse all name-value: ("Content",ft,"Title","name")
Only editing default.htmtx for HTMLEdit both .htmtx and .htmt
regexprep(raw,"color:","navy") without lookbehindUse setOrAddCss with negative lookbehind
Replacing heading styles without OutlineLevel(N)Always include OutlineLevel(N) in TemplateLinkedStyle.Formats

Conventions

  • Package-qualified static calls — always pkg.Class.method() inside the package

  • Format symmetry — if you style in DOCX, style in PDF and HTML too

  • Inspect before editing — getStyle on scaffolded templates to discover real style names

  • tmpPath includes extension — preserve template file extension

  • JSON is the single source of truth — never hardcode style values in reporter methods

  • One table subclass per visual variant — not one class with runtime switching

  • editPdfHtml + editDocx — group by editing mechanism, not by format count

  • Handle missing styles gracefully — getStyle returns empty if style doesn't exist


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.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download matlab-generate-report.zip