MATLAB设置图窗所有文字字体为【中文宋体+英文Times New Roman】
学位论文的要求图片中英文字体不同,而MATLAB默认只能设置单一字体,参考网上的MATLAB字体设置的文章1 2,设计了个函数figFont(fig)来读取图窗fig上的所有字符,然后将所有中文字体全部修改为宋体,英文字体为Times New Roman。
背景
默认情况下,MATLAB默认字体为Helvetica,中文显示是宋体:
如果设置坐标区字体为宋体,set(gca, ‘FontName’,‘宋体’);,则英文显示很丑:
如果设置坐标区字体为Times New Roman,set(gca, ‘FontName’,‘Times New Roman’),则中文乱码:
在网上浏览相关信息后,对混排字体大体可以分为两个思路:
- 对文本进行切分,补充字体设置。
- MATLAB或者系统底层字体库替换。
由于对底层的知识不太熟,我选择写一个函数对所有文本的字体进行设置。
实现过程
- 找到图窗中的所有文字
- 对文字进行切分
- 对切分后的文字设置字体,然后重组
找到图窗所有文字
图窗fig中的文字内容有两种格式:
- Text文本对象
- Cell元胞数组
找到以上两种元素有两种思路
- 遍历所有元素
- 使用函数findall找Text+遍历每个坐标区找坐标轴相关的Cell元胞数组
文字切分
假设图窗fig中已有文字元素为
'中文内容一 English Content 2 中文内容三 English Content 4'
后,将该段文字切分,并补充字体设置
使得文字内容转化为
'\fontname{宋体}中文内容一 \fontname{Times New Roman}English Content 2 \fontname{宋体}中文内容三 \fontname{Times New Roman}English Content 4'
就能在不更换默认以及系统字体的情况下实现中英文字体混排。
使用指南
把下面的figFont或者figFont3函数保存为.m文件,然后您画好自己的图后,并获得图窗的句柄fig后,在你自己的代码最后,补充以下任意一句内容,即可实现图片字体混排:
figFont(fig);
或
figFont3(fig);
figFont(fig)和figFont3(fig),这俩功能是一样的,读取图窗fig后就会将fig中的所有文字都进行修改,区别在于:
- figFont遍历了图窗中的所有元素;
- figFont3是我把代码再交给通义灵码再次进行优化后写的,只读取图窗中Axes坐标区元素和Text文本元素;
当图窗fig中显示的内容较多,figFont3()运行速度较快,但可能有一些我不知道的文字元素可能需要您使用的时候自己来修改代码。
下面是figFont()函数:
%% 测试
% close all;clear;
% % Figure
% plot(cos(0:0.01:pi));hold on;
% fig=figure(1);
% set(fig, 'Name', 'My Figure', 'NumberTitle', 'off', 'MenuBar', 'none');
% title('hfdsaa范德萨’');
%
% % 添加一些 Text 对象
% text1 = text(0.5, 0.5, 'Hello哈哈', 'Color', 'red');
% text2 = text(0.6, 0.6, 'World', 'Color', 'blue');
% text3 = text(0.7, 0.7, 'Axes Text', 'Color', 'green');
%
% legend('fdsaf')
% xlabel('alskk')
%
% figFont(fig)
%%
function figFont(fig)
% 调用递归函数,从 figure 开始搜索
[textObjects, cellArrays,childArrays,nameArrays] = findTextAndCell(fig);
for itxt=1:length(textObjects)
% 转化:
strChgd={stringChg(textObjects{itxt}.String )};
% 替换:
textObjects{itxt}.String =strChgd;
end
for icel=1:length(cellArrays)
% 转化:
strChgds={};
for jcel=1:length(cellArrays{icel})
strChgd={stringChg(cellArrays{icel}(jcel))};
strChgds{end+1}=strChgd;
end
% 替换:
set(childArrays{icel},nameArrays{icel},string(strChgds'))
end
end
% 递归函数,用于遍历所有子对象
function [textObjects, cellArrays,childArrays,nameArrays] = findTextAndCell(obj)
% 初始化结果变量
textObjects = {};
cellArrays = {};
childArrays={};
nameArrays ={};
% 获取当前对象的所有子对象
children = get(obj, 'Children');
% 遍历所有子对象
for i = 1:length(children)
child = children(i);
% 检查子对象是否为 Text 对象
if strcmp(get(child, 'Type'), 'text')
textObjects{end+1} = child;
end
% 检查子对象的属性值是否为元胞数组或Text对象
props = properties(child);
for j = 1:length(props)
propName = props{j};
propValue = get(child, propName);
if iscell(propValue)
cellArrays{end+1} = propValue;
childArrays{end+1} = child;
nameArrays{end+1} = propName;
end
try
if strcmp(get(propValue, 'Type'), 'text')
textObjects{end+1} = propValue;
end
end
end
% 递归调用,继续搜索子对象的子对象
[subTextObjects, subCellArrays] = findTextAndCell(child);
textObjects = [textObjects, subTextObjects];
cellArrays = [cellArrays, subCellArrays];
end
end
function textCont=stringChg(textCont_String)
if strcmp(textCont_String,char);textCont=char;else
chiFontname='宋体';
engFontname='Times New Roman';
% textCont = string(textObjs.String);
% set(textObjs, 'Interpreter', 'tex'); % 设置解释器为 TeX (LaTeX解析式,关键代码"\fontname{}"不会生效)
% 中英字段分割
result = splitChinese(textCont_String);
% 设置中文字段字体
result.Data(result.flag == 1) = strcat(['\fontname{',chiFontname,'}'],result.Data(result.flag == 1));
% 设置英文字段字体
result.Data(result.flag == 0) = strcat(['\fontname{',engFontname,'}'],result.Data(result.flag == 0));
% 重新连接字符
textCont = [result.Data{:}];
end
end
function result = splitChinese(label)
% 确定汉字的位置
label = char(label);
% 目前为多行字符向量(char 1*11*6)形成矩阵,不好串联
log = arrayfun(@(x) (x >= '一' && x <= '龥')||...
(x>=8212&&x<=8230)||(x>=12290&&x<=12305)||(x>=65281&&x<=65311),label);
Indxs = find(diff(log) ~= 0);
result.Data = arrayfun(@(x,y) extractBetween(label,x,y),[0 Indxs]'+1,[Indxs length(label)]');
result.flag = [log(Indxs),log(end)];
end
下面是优化后的figFont3():
%% 测试
% close all; clear;
% % Figure
% plot(cos(0:0.01:pi)); hold on;
% fig = figure(1);
% set(fig, 'Name', 'My Figure', 'NumberTitle', 'off', 'MenuBar', 'none');
% title('hfdsaa范德萨’');
%
% % 添加一些 Text 对象
% text1 = text(0.5, 0.5, 'Hello哈哈', 'Color', 'red');
% text2 = text(0.6, 0.6, 'World', 'Color', 'blue');
% text3 = text(0.7, 0.7, 'Axes Text', 'Color', 'green');
%
% legend('fdsaf')
% xlabel('alskk')
%
% figFont(fig)
function figFont3(fig)
% 获取图窗中的所有文本对象
allTextObjects = findall(fig, 'Type', 'text');
% 遍历每个文本对象
for i = 1:length(allTextObjects)
textObj = allTextObjects(i);
originalString = textObj.String;
% 分割字符串,区分中文和英文/数字
modifiedString = stringChg(originalString);
% 设置修改后的字符串
textObj.String = modifiedString;
end
% 获取图窗中的所有坐标轴对象
allAxes = findall(fig, 'Type', 'axes');
% 遍历每个坐标轴对象
for i = 1:length(allAxes)
ax = allAxes(i);
% % 设置坐标轴标题的字体
% if ~isempty(ax.Title)
% ax.Title.String = stringChg(ax.Title.String);
% end
%
% % 设置 x 轴标签的字体
% if ~isempty(ax.XLabel)
% ax.XLabel.String = stringChg(ax.XLabel.String);
% end
%
% % 设置 y 轴标签的字体
% if ~isempty(ax.YLabel)
% ax.YLabel.String = stringChg(ax.YLabel.String);
% end
%
% % 设置 z 轴标签的字体
% if ~isempty(ax.ZLabel)
% ax.ZLabel.String = stringChg(ax.ZLabel.String);
% end
% 设置 x 轴刻度标签的字体
if ~isempty(ax.XTickLabel)
ax.XTickLabel = cellfun(@stringChg, ax.XTickLabel, 'UniformOutput', false);
end
% 设置 y 轴刻度标签的字体
if ~isempty(ax.YTickLabel)
ax.YTickLabel = cellfun(@stringChg, ax.YTickLabel, 'UniformOutput', false);
end
% 设置 z 轴刻度标签的字体
if ~isempty(ax.ZTickLabel)
ax.ZTickLabel = cellfun(@stringChg, ax.ZTickLabel, 'UniformOutput', false);
end
end
% 获取图窗中的所有极坐标轴对象
allPolarAxes = findall(fig, 'Type', 'polaraxes');
% 遍历每个极坐标轴对象
for i = 1:length(allPolarAxes)
ax = allPolarAxes(i);
% % 设置坐标轴标题的字体
% if ~isempty(ax.Title)
% ax.Title.String = stringChg(ax.Title.String);
% end
%
% % 设置 r 轴标签的字体
% if ~isempty(ax.RLabel)
% ax.RLabel.String = stringChg(ax.RLabel.String);
% end
% % 设置 theta 轴标签的字体
% if ~isempty(ax.ThetaLabel)
% ax.ThetaLabel.String = stringChg(ax.ThetaLabel.String);
% end
% 设置 r 轴刻度标签的字体
if ~isempty(ax.RTickLabel)
ax.RTickLabel = cellfun(@stringChg, ax.RTickLabel, 'UniformOutput', false);
end
% 设置 theta 轴刻度标签的字体
if ~isempty(ax.ThetaTickLabel)
ax.ThetaTickLabel = cellfun(@stringChg, ax.ThetaTickLabel, 'UniformOutput', false);
end
end
allLegend=findall(fig,'Type','Legend');
% 遍历每个图例对象
for i=1:length(allLegend)
lg=allLegend(i);
% 设置坐标轴标题的字体
if ~isempty(lg.String)
lg.String = cellfun(@stringChg,lg.String, 'UniformOutput', false);
end
end
end
function modifiedString = stringChg(textCont_String)
if strcmp(textCont_String,char);modifiedString=char;else
chiFontname = '宋体';
engFontname = 'Times New Roman';
% 分割中英文
result = splitChinese(textCont_String);
% 设置中文字段字体
result.Data(result.flag == 1) = strcat(['\fontname{', chiFontname, '}'], result.Data(result.flag == 1));
% 设置英文字段字体
result.Data(result.flag == 0) = strcat(['\fontname{', engFontname, '}'], result.Data(result.flag == 0));
% 重新连接字符
modifiedString = [result.Data{:}];
end
end
function result = splitChinese(label)
% 确定汉字的位置
label = char(label);
% 检查是否为中文字符
log = arrayfun(@(x) (x >= '一' && x <= '龥') || ...
(x >= 8212 && x <= 8230) || ...
(x >= 12290 && x <= 12305) || ...
(x >= 65281 && x <= 65311), label);
% 找到分隔点
Indxs = find(diff(log) ~= 0);
% 提取分段
result.Data = arrayfun(@(x, y) extractBetween(label, x, y), [0, Indxs]' + 1, [Indxs, length(label)]');
result.flag = [log(Indxs), log(end)];
end
案例
原图
%% 测试
close all; clear;
% Figure
plot(cos(0:0.01:pi)); hold on;
fig = figure(1);
set(fig, 'Name', 'My Figure', 'NumberTitle', 'off', 'MenuBar', 'none');
title('hfdsaa范德萨’');
% 添加一些 Text 对象
text1 = text(0.5, -0.5, 'Hello哈哈', 'Color', 'red');
text2 = text(0.6, 0, 'World', 'Color', 'blue');
text3 = text(0.7, 0.5, 'Axes Text', 'Color', 'green');
legend('fdsaf')
xlabel('alskk')
修改字体:
figFont(fig)
figFont3案例的完整代码:
%% 测试
close all; clear;
% Figure
plot(cos(0:0.01:pi)); hold on;
fig = figure(1);
set(fig, 'Name', 'My Figure', 'NumberTitle', 'off', 'MenuBar', 'none');
title('hfdsaa范德萨’');
% 添加一些 Text 对象
text1 = text(0.5, -0.5, 'Hello哈哈Oreo', 'Color', 'red');
text2 = text(0.6, 0, 'World', 'Color', 'blue');
text3 = text(0.7, 0.5, 'Axes Text', 'Color', 'green');
legend('fdsaf')
xlabel('alskk')
disp('Oreo');
figFont3(fig)
function figFont3(fig)
% 获取图窗中的所有文本对象
allTextObjects = findall(fig, 'Type', 'text');
% 遍历每个文本对象
for i = 1:length(allTextObjects)
textObj = allTextObjects(i);
originalString = textObj.String;
% 分割字符串,区分中文和英文/数字
modifiedString = stringChg(originalString);
% 设置修改后的字符串
textObj.String = modifiedString;
end
% 获取图窗中的所有坐标轴对象
allAxes = findall(fig, 'Type', 'axes');
% 遍历每个坐标轴对象
for i = 1:length(allAxes)
ax = allAxes(i);
% % 设置坐标轴标题的字体
% if ~isempty(ax.Title)
% ax.Title.String = stringChg(ax.Title.String);
% end
%
% % 设置 x 轴标签的字体
% if ~isempty(ax.XLabel)
% ax.XLabel.String = stringChg(ax.XLabel.String);
% end
%
% % 设置 y 轴标签的字体
% if ~isempty(ax.YLabel)
% ax.YLabel.String = stringChg(ax.YLabel.String);
% end
%
% % 设置 z 轴标签的字体
% if ~isempty(ax.ZLabel)
% ax.ZLabel.String = stringChg(ax.ZLabel.String);
% end
% 设置 x 轴刻度标签的字体
if ~isempty(ax.XTickLabel)
ax.XTickLabel = cellfun(@stringChg, ax.XTickLabel, 'UniformOutput', false);
end
% 设置 y 轴刻度标签的字体
if ~isempty(ax.YTickLabel)
ax.YTickLabel = cellfun(@stringChg, ax.YTickLabel, 'UniformOutput', false);
end
% 设置 z 轴刻度标签的字体
if ~isempty(ax.ZTickLabel)
ax.ZTickLabel = cellfun(@stringChg, ax.ZTickLabel, 'UniformOutput', false);
end
end
% 获取图窗中的所有极坐标轴对象
allPolarAxes = findall(fig, 'Type', 'polaraxes');
% 遍历每个极坐标轴对象
for i = 1:length(allPolarAxes)
disp('Oreo');
ax = allPolarAxes(i);
% % 设置坐标轴标题的字体
% if ~isempty(ax.Title)
% ax.Title.String = stringChg(ax.Title.String);
% end
%
% % 设置 r 轴标签的字体
% if ~isempty(ax.RLabel)
% ax.RLabel.String = stringChg(ax.RLabel.String);
% end
% % 设置 theta 轴标签的字体
% if ~isempty(ax.ThetaLabel)
% ax.ThetaLabel.String = stringChg(ax.ThetaLabel.String);
% end
% 设置 r 轴刻度标签的字体
if ~isempty(ax.RTickLabel)
ax.RTickLabel = cellfun(@stringChg, ax.RTickLabel, 'UniformOutput', false);
end
% 设置 theta 轴刻度标签的字体
if ~isempty(ax.ThetaTickLabel)
ax.ThetaTickLabel = cellfun(@stringChg, ax.ThetaTickLabel, 'UniformOutput', false);
end
end
allLegend=findall(fig,'Type','Legend');
% 遍历每个图例对象
for i=1:length(allLegend)
lg=allLegend(i);
% 设置坐标轴标题的字体
if ~isempty(lg.String)
lg.String = cellfun(@stringChg,lg.String, 'UniformOutput', false);
end
end
end
function modifiedString = stringChg(textCont_String)
if strcmp(textCont_String,char);modifiedString=char;else
chiFontname = '宋体';
engFontname = 'Times New Roman';
% 分割中英文
result = splitChinese(textCont_String);
% 设置中文字段字体
result.Data(result.flag == 1) = strcat(['\fontname{', chiFontname, '}'], result.Data(result.flag == 1));
% 设置英文字段字体
result.Data(result.flag == 0) = strcat(['\fontname{', engFontname, '}'], result.Data(result.flag == 0));
% 重新连接字符
modifiedString = [result.Data{:}];
end
end
function result = splitChinese(label)
% 确定汉字的位置
label = char(label);
% 检查是否为中文字符
log = arrayfun(@(x) (x >= '一' && x <= '龥') || ...
(x >= 8212 && x <= 8230) || ...
(x >= 12290 && x <= 12305) || ...
(x >= 65281 && x <= 65311), label);
% 找到分隔点
Indxs = find(diff(log) ~= 0);
% 提取分段
result.Data = arrayfun(@(x, y) extractBetween(label, x, y), [0, Indxs]' + 1, [Indxs, length(label)]');
result.flag = [log(Indxs), log(end)];
end