Set alt attribute when publishing a figure

I am using Publish to write some documentation that will be included in a larger website. I would like to be able to properly caption my figures:
function testAlt
figure(1);
x=0:.1:2*pi;
y=sin(x);
plot(x,y);
set(gcf,'Tag','Sine wave');
Produces:
<img vspace="5" hspace="5" src="testAlt_01.png" alt="">
What I want is:
<figure>
<img vspace="5" hspace="5" src="testAlt_01.png" alt="">
<figcaption>Sine wave</figcaption>
</figure>
Which would render as:
Looking at toolbox/matlab/codetools/private/mxdom2simplehtml.xsl, the <img> template contains:
<xsl:attribute name="alt"><xsl:value-of select="@alt"/></xsl:attribute>
I can modify this file to include:
<figure>
...
<figcaption><xsl:value-of select="@alt"/></figcaption>
</figure>
and I'll get my caption. Only problem is that there doesn't seem to be a way to propogate any property of gcf into the XML. @alt seems like the natural choice, and since someone wrote the code to consume it, perhaps someone could write the code to produce it.
My other suggestion on this is that embedding the css style sheet in an xsl file in a folder named "private" is painful. Why not provide a configuration parameter "cssfile" that would import the specified file into the document's head?
<link rel="stylesheet" type="text/css"><xsl:attribute name="href">u<xsl:value-of select="@cssfile"/></xsl:attribute></link>
Where I can put:
figure {
display: inline-block;
margin: 20px;
}
figure img {
vertical-align: top;
}
figure figcaption {
caption-side: bottom;
padding: 10px;
font-weight: bold;
font-size: 110%;
text-align: center;
}

1 Comment

A bit of a kludge, but until @alt is available, change the xsl to:
<figcaption>Figure <xsl:value-of select="substring(@src,string-length($title)+2,2)"/></figcaption>
This takes the name of the image file (myfunction-xx.png) and pulls out the xx, so the first figure will be "Figure 01". Yes, I could probably figure out how to suppress the leading zero.
What would be a nice feature would be the ability to define an XML variable in the script, so you could cross reference to the figure, something like:
setXMLtag('fignum', 1);
setXMLtag('caption', 'Money as a function of time');
%%
% As can be seen in Figure @fignum, time is money
plot(time,money)

Sign in to comment.

 Accepted Answer

OK, I came back to this a year later, and here's the solution. Not pretty, but it works. Several steps:
1) For every figure, create the figure with a name:
figure('Name', 'Money as a function of time');
2) Make a copy of the file $MATLABROOT/toolbox/matlab/codetools/private/mxdom2simplehtml.xsl
3) Add this line to the <HEAD> section:
<link rel="stylesheet" type="text/css"><xsl:attribute name="href">user.css</xsl:attribute></link>
4) Create the file user.css in the directory that your html file will be written and add some css:
figure {
display: inline-block;
margin: 20px;
}
figure img {
vertical-align: top;
}
figure figcaption {
caption-side: bottom;
padding: 10px;
font-weight: bold;
font-size: 18pt;
text-align: center;
}
5) In mxdom2simplehtml.xsl, search for the line
<xsl:template match="img">
Change this to
<xsl:template match="img">
<figure>
6) Change
</img>
To
</img>
<figcaption><xsl:value-of select="@alt"/></figcaption>
</figure>
7) Create this script:
function domNode = publishWithXML(fname)
% Usage:
% fname - the name of the command (no file extension)
% domNode - the DOM structure that was used to generate the HTML
% An empty cell array that holds the captions
figdata = {};
% The DefaultFigureCreateFcn that populates the cell array
set(groot,'DefaultFigureCreateFcn',@myCreateCallback);
% Call publish and get the xml without applying an XSLT
thexmlfile= publish(sprintf("%s.m",fname),"format","xml","showCode",false,"codeToEvaluate",fname);
close all;
% Read the XML into a domNode
domNode=xmlread(thexmlfile);
% Get all the img nodes
allimg = domNode.getElementsByTagName("img");
for i=0:allimg.getLength-1
% Get the src attribute of the img tag, scan for the figure
% number, and find the row of figdata that contains the caption
imgsrc = string(allimg.item(i).getAttribute("src"));
fignum = sscanf(imgsrc,sprintf("%s_%%d",fname));
[row,~] = find(cellfun(@(x) isequal(fignum,x),figdata));
% Create the string for the alt tag and add this to the img node
alttext = sprintf("Figure %d - %s", fignum, string(figdata(row,2)));
allimg.item(i).setAttribute("alt", alttext);
end
% Transform the domNode to html using our modified xsl file. The
% original is in $MATLABROOT/toolbox/matlab/codetools/private/mxdom2simplehtml.xsl
xslt(domNode,"mxdom2simplehtml.xsl",sprintf("html/%s.html",fname),"-web");
function myCreateCallback(src,~)
% Add the properties of the figure handle to the cell array
if ~isempty(src.Number)
figdata(src.Number,:) = {[src.Number], src.Name};
end
end
end
Calling publishWithXML("myscript") will create a <figcaption> within the <figure> that contains your <img>, sequentially numbering them.
Now MathWorks could modify $MATLABROOT/toolbox/matlab/codetools/+internal/+matlab/+publish/PublishFigures.m to write the alt tag from the Number and Name of the figure, but isn't this way more fun?

4 Comments

This seems like a reasonable enhancement request to send to Technical Support directly using this link.
An enhancement request has been forwarded to the relevant development team for consideration for a future update or release of MATLAB.
Thank you. My other suggestion regarding figures is to have exportgraphics add the name of the figure to the image file's metadata (when possible), much as imwrite can do.
Thank you for the additional feedback. The enhancement request has been forwarded to the relevant development team for consideration for a future update or release of MATLAB.

Sign in to comment.

More Answers (0)

Categories

Find more on Interactive Control and Callbacks in Help Center and File Exchange

Products

Release

R2024b

Asked:

on 20 Feb 2025

Commented:

3 minutes ago

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!