看數學老師是如何一鍵搞定報告和試卷的


本文將介紹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. 批量生成成績單

數據集和目標:

  1. 班級所有人的成績表(成績.xlsx):姓名、語文、數學、總分;
  2. 給每個同學生一張成績單,其中只有自己一個人的分數和相對應的等級。
% 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);

成果預覽:

schoolreport.png

除此之外,本文還提供了一個批量生成獎狀的模板(在Word里也可以通過郵件合並功能實現)供參考。

獎狀.png

相關文件下載鏈接: 自動化報告 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的數據處理與分析功能,我們可以做很多事,例如

  1. 根據給定的類型要求和考點要求,隨機生成一張試卷;
  2. 結合單個同學的歷史數據,生成適合他/她的試卷,在這份試卷中易錯點出現的頻次更高一些;
  3. 由於所有試卷都是生成的,我們可以更科學快捷的評估單次考試。

exam.png

再次附上項目鏈接: 自動化報告 github 項目地址數學試卷生成 github 項目地址


本人公眾號,文章首發於此,歡迎關注


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM