本文將介紹Matlab的兩個實用技巧。一鍵生成Word版本的報告和PDF版本的數學試卷。其中第一個技巧Matlab之前都是通過調用COM接口來實現的,類似於VBA,雖然可做的事情很多,但並不適合一般的童鞋。第二個技巧,靈感來源於一位研究僧同學。大致意思是根據現有的數學題庫來科學快捷的生成一份試卷。本文提供的只是初稿,如果需求大的話,作者會在Github上保持更新。
文/JSong 轉載請注明出處! 原文地址
1. 自動化報告
測試平台: MATLAB 2015b
先來看一個最簡單的例子(demo1.m)
% demo1.m
import mlreportgen.dom.*;
d = Document('demo1','docx');
open(d);
append(d,'hello world!');
close(d);
rptview(d.OutputPath);
import mlreportgen.dom.*;
第一行是將所需要的類和函數導入工作空間。這里我們最常用的類就是Document.
d = Document('test','docx');
open(d);
在第二、三行中我們新建一個文檔,其中文件類型docx
可以替換成html
或者pdf
. Document類的相關屬性可以通過命令查看 (doc mlreportgen.dom.Document)
append(d,'hello world!');
在第四行我們給文檔添加了一句經典的話,我們還可以自定義它們的樣式。比如加粗、斜體、改成藍色、字體大小等等。
% 替換上面的一行代碼
p=Text('hello world');
p.Style={Bold(true),FontSize('16pt'),Color('blue')};
p.Strike='double';
append(d,p)
這里出現了第一個文檔類:Text
,即文本。Matlab提供了很多可調節的屬性,如下表。修改起來也很方便,如要把文本改為斜體,則添加:p.Italic=1;
即可。
Text 的屬性 |
取值 | 備注 |
---|---|---|
Bold | true/false | 加粗 |
Color | str('red'、'blue'等) | 顏色 |
Italic | true/false | 斜體 |
BackgroundColor | str | 背景色 |
Underline | str('single'、'dotdash'等) | 下划線 |
FontFamilyName | str | 字體 |
FontSize | str('12pt') | 字體大小 |
Strike | str | 刪除線 |
StyleName | str | 模板中的樣式名 |
接下來我們將生成一個更復雜的文檔。首先想想一個word文檔一班都有哪些元素。MATLAB提供了很多(下面的表格僅列出了部分)。本文主要介紹其中的五個:頁面設置、標題、段落、表格、圖片。
屬性 | 含義 |
---|---|
CustomAttribute | Custom element attribute |
CustomElement | Custom element of a document |
CustomText | Plain text to be appended to a custom element |
DOCXPageFooter | Page footer for a Word document. |
DOCXPageHdrFtr | Page Base class for page header and footer |
DOCXPageHeader | Page header for a Word document. |
DOCXPageMargins | Margins of pages in a Word page layout |
DOCXPageSize | Size, orientation of pages in a Word layout |
DOCXSection | Page layout section of a Word document |
Document | Create a dom document |
ExternalLink | Create a hyperlink to an external target |
Form | Defines a form |
FormalTable | Create a formal table |
Group | Group of document objects |
Heading | Create a heading paragraph. |
HorizontalRule | Create a horizontal rule. |
Image | Create an image to be included in a report. |
ImageArea | Defines an image area as a hyperlink |
InternalLink | Create a hyperlink to a target in this |
LinkTarget | Create a target for a hyperlink. |
ListItem | Item in a list |
Node | Defines a document node |
Object | Defines a document object |
OrderedList | Ordered (numbered) list |
Paragraph | Create a formatted block of text, i.e., a paragraph. |
Table | Create a table. |
TableColSpecGroup | Defines style of a group of table columns |
TableEntry | Create a table Entry |
TableRow | Creates a table row |
Template | Create a template for a document |
Text | Create a text object |
接下來我們做一個完整的模板。首先新建空白文檔。
% demo2.m
import mlreportgen.dom.*;
d=Document('demo2','docx');
open(d);
1.1 頁面
頁面設置包括頁面大小('A4'等)、頁面方向、頁邊距.
% 頁面設置
s = d.CurrentDOCXSection;
s.PageSize.Orientation ='landscape'; % portrait(default)
s.PageSize.Height = '8.5in';
s.PageSize.Width = '11in';
s.PageMargins.Left = '3.0cm';
s.PageMargins.Right = '3.0cm';
s.PageMargins.Top = '2.5cm';
s.PageMargins.Bottom = '2.5cm';
% 中文字體樣式設置
heiti=FontFamily;
heiti.FamilyName='Arial';
heiti.EastAsiaFamilyName='黑體';
songti=FontFamily;
songti.FamilyName='Arial';
songti.EastAsiaFamilyName='宋體';
1.2 標題
標題的初始格式由模板中自帶的標題樣式決定,當然也可以自己修改。
%% 標題
p=Heading(1,'Matlab 自動化報告模板');% 一級標題
%p.Color='red';
%p.HAlign='center';
p.Style={heiti,Color('red'),HAlign('center')};
append(d,p);
1.3 段落
與文本不同,段落除下文本的屬性外,還有邊距、對齊、首行縮進、行間距、段前、段后等屬性需要調節。在下面的代碼框中,FirstLineIndent代表首行縮進的寬度,LineSpacing代表行間距,OuterMargin代表邊距。在這里我們還引入了一個新的類:ExternalLink(外部鏈接),當然Matlab也提供文檔內部鏈接:InternalLink.
%% 段落
append(d,Heading(2,'一、段落模板'));
s='這里是段落。';
s=repmat(s,[1,12]);
p = Paragraph(s);
% 中文字體樣式自定義
p.Style={songti,Color('blue'),...
LineSpacing(1.5),...
OuterMargin('10pt','0pt','0pt','10pt')};
p1=Text('下划線。');%同段落差不多.
p1.Underline='single';
p1.Color='red';
append(p,p1);
append(p,s);
p2=ExternalLink('http://github.com/gasongjian/', '超鏈接');
append(p,p2);
p.FontSize='14pt';
p.FirstLineIndent='28pt';%這里差不多就是2個字符大小
append(d,p);
1.4 簡易表格
Matlab 支持直接從數組矩陣和元胞矩陣建立表格。如t=Table(magic(5))
或者
t=Table(cell(5))
. 也可以利用TableRow一行一行添加。一個單元格可以填充的元素很多(文本、圖像等),所以可調節的就是表格的邊框、單元格的大小、對齊等。本文給出一個簡易的例子和一個復雜的例子。一件很遺憾的事就是不能合並單元格。當寫完demo2后,本文還將提供一種更為簡便的方式。
%% 簡易表格
append(d,Heading(2,'二、簡單表格'));
t={'志明','語文','數學','英語'; ...
'成績','70','98','89'; ...
'等級','B','A','A'};
p=Table(t);
% 格式化單元格中的段落
for ii=1:p.NRows
for jj=1:p.NCols
t=entry(p,ii,jj);
t.Children(1).Style={songti,...
Color('green'),...
FontSize('12pt'),...
LineSpacing(1.0),...
OuterMargin('0pt','0pt','0pt','0pt')};
end
end
p.Style = {Border('single','blue','3px'), ...
ColSep('single','blue','1px'), ...
RowSep('single','blue','1px')};
p.Width = '50%';
p.HAlign='center';% 居中對齊
p.TableEntriesHAlign='center';
p.TableEntriesVAlign='middle';
append(d,p);
1.5 復雜表格
%% 復雜表格
append(d,Heading(2,'三、復雜表格'));
q = Table(5);
q.Border = 'single';
q.ColSep = 'single';
q.RowSep = 'single';
row = TableRow;
te = TableEntry('算法名稱');
te.RowSpan = 2;
append(row, te);
te = TableEntry('第一類');
te.ColSpan = 2;
%te.Border = 'single';
append(row, te);
te = TableEntry('第二類');
te.ColSpan = 2;
%te.Border = 'single';
append(row, te);
append(q,row);
% 第二行
row=TableRow;
append(row,TableEntry('T1'));
append(row,TableEntry('T2'));
append(row,TableEntry('T3'));
append(row,TableEntry('T4'));
append(q,row);
% 其他行
t=TableRow;
append(t,TableEntry('條目'));
for i=1:4
append(t,TableEntry(' '));
end
append(q,t);
append(q,clone(t));
append(q,clone(t));
append(q,clone(t));
q.TableEntriesStyle={Width('80'),Height('40')};
q.Style = {Border('single','green','3px'), ...
ColSep('single','green','1px'), ...
RowSep('single','green','1px')};
q.HAlign='center';% 居中對齊
q.TableEntriesHAlign='center';
q.TableEntriesVAlign='middle';
append(d,q);
1.6 圖片
%% 插入圖片
append(d,Heading(2,'四、圖片模板'));
p1 = Image('myPlot_img.png');
% ScaleToFit是為了使圖片大小適應頁面,也可以換成下方的自定義大小設置
%p1.Style={HAlign('center'),ScaleToFit(1)};
p1.Style={HAlign('center'),Width('600px'),Height('400px')};
append(d,p1);
close(d);
rptview(d.OutputPath);
作為一個懶人,我希望寫得更極致一點, 即我只想關注內容而忽略這些格式。這時候我們可以利用模板來實現這一切,把所需要的樣式都存在模板里。事實上新建Word文檔都是基於模板建立的,Matlab也是。通過在模板里修改默認樣式或者新建樣式,我們可以極大簡化上述代碼,從而使得上述工作不那么像編程。
1.7 巧用模板來簡化代碼
% demo3.m
% 利用模板中的樣式來生成報告
% 如果是中文版Word,自帶樣式名稱請參見目錄下的pdf文檔
import mlreportgen.dom.*
% 模板文件 mytemplate.dotx 在文末會附下載鏈接
d=Document('demo3','docx',fullfile(pwd,'mytemplate'));
open(d);
%% 標題
p=Paragraph('成績報告單','Heading 1');
append(d,p);
%% 文字段落(doc mlreportgen.dom.Paragraph)
append(d,Heading(2,'一、段落模板'));
s='這里是段落';
s=repmat(s,[1,30]);
p = Paragraph(s,'mypara1');%自定義段落樣式
append(d,p);
%% 添加空的段落行
for i=1:8
append(d,' ');
end
%% 插入表格
append(d,Heading(2,'二、表格模板'));
t={'姓名','語文','數學','英語'; ...
'成績','70','94','82'; ...
'等級','C','A','B'};
p=Table(t,'mytable1');% 自定義表格樣式
append(d,p);
close(d);
rptview(d.OutputPath);
到這一個完整的模板就差不多了,還有一些新的類需要讀者自己去探索。 接下來才是本文的正題,我們來玩一點好玩的事情。
2. 批量生成成績單
數據集和目標:
- 班級所有人的成績表(成績.xlsx):姓名、語文、數學、總分;
- 給每個同學生一張成績單,其中只有自己一個人的分數和相對應的等級。
% SchoolReport.m
% n=學生人數
% 為使得程序可讀性加強,我們需要格式化成績單
% 1. 第一行格式:姓名,各個學科,總分
% 2. 只有學生成績,沒有其他很雜的信息。
% 3. 部分成績若空缺,請不要用數字填充,可以空着或者文字(缺考)填充。
%% 數據導入
filename='成績.xlsx';
savename='成績單';
[score,textdata]=xlsread(filename);
m=3; %學科數
n=size(score,1);% 學生人數
name=textdata(2:n+1,1);
mean_score=mean(score,'omitnan');
max_score=max(score,[],'omitnan');
grade=Gradegen(score); %Gradegen是自定義函數,生成各個同學的等級
%模板,實考對應變量score,等級對應變量grade
template=cell(5,m+1);
template(1,1:m+1)={'姓名','語文','數學','總分'};
template(2:5,1)={'實考成績';'平均成績';'最高成績';'等級'};
%% 相關接口
import mlreportgen.dom.*;
d = Document(savename,'docx',fullfile(pwd,'mytemplate'));
open(d);
%% 開始生成word成績單列表
% 添加分割線
hr = HorizontalRule();
hr.Style={Border('dotdash','blue','2px')};
append(d,hr);
% n是學生人數,m是學科數
for i=1:n
% 填充表格
template{1,1}=name{i};
for jj=2:m+1
s=score(i,jj-1);
if isnan(s)
s='缺考';
else
s=num2str(s);
end
template{2,jj}=s;% 具體分數
template{3,jj}=sprintf('%4.2f',mean_score(jj-1));%學科平均分數
template{4,jj}=num2str(max_score(jj-1));%學科最高分數
template{5,jj}=grade{i,jj-1};% 等級
end
q=Table(template,'mytable2');
q.TableEntriesStyle={Width('100'),Height('50')};
append(d,q);
append(d,clone(hr));
end
close(d);
rptview(d.OutputPath);
成果預覽:
除此之外,本文還提供了一個批量生成獎狀的模板(在Word里也可以通過郵件合並功能實現)供參考。
相關文件下載鏈接: 自動化報告 github 項目地址
3. 中學數學試卷生成
在寫這個之前,首先要感謝一位數學系學長鮑宏昌。接下來要介紹的項目就是基於學長開發的中學試卷包:bhcexam
項目名稱: MathExamGen
項目平台: Windows+Matlab+Texlive(含bhcexam包)
項目地址: http://github.com/gasongjian/mathexamgen/
項目介紹:大體思路就是利用Matlab科學的整合數學題庫中的題目,然后生成相應的tex文件,最后借助自帶的xelatex編譯器編譯成pdf文件。
3.1 數學題庫
存儲類型:csv或者數據庫
變量列表:
變量 | 變量名 | 描述 | 取值 |
---|---|---|---|
1 | ID | 題目編號 | 6位數字 |
2 | qtype | 題目類型 | 1代表填空題,2代表選擇題等 |
3 | question | 題目內容 | 題目的latex代碼 |
4 | options | 題目相關信息 | 選擇題的四個選項等信息 |
5 | answer | 題目答案 | |
6 | topic | 題目的考點 | 分級考點,如:高二-數列-遞推 |
3.2 主要思路
結合Matlab的數據處理與分析功能,我們可以做很多事,例如
- 根據給定的類型要求和考點要求,隨機生成一張試卷;
- 結合單個同學的歷史數據,生成適合他/她的試卷,在這份試卷中易錯點出現的頻次更高一些;
- 由於所有試卷都是生成的,我們可以更科學快捷的評估單次考試。
再次附上項目鏈接: 自動化報告 github 項目地址, 數學試卷生成 github 項目地址
本人公眾號,文章首發於此,歡迎關注