为什么 matplotlib 将右括号替换为“!”在乳胶表达?
Why matplotlib replace a right parenthesis with "!" in latex expression?
我处于必须将 python 表达式转换为最终用户的 Latex 位图的情况(他们有足够的信心自己编写 python 函数,但更喜欢在 Latex 中观察结果).
我正在使用 Matplotlib.mathtext 通过以下代码完成这项工作(从翻译的乳胶原始字符串)。
import wx
import wx.lib.scrolledpanel as scrolled
import matplotlib as mpl
from matplotlib import cm
from matplotlib import mathtext
class LatexBitmapFactory():
""" Latex Expression to Bitmap """
mpl.rc('image', origin='upper')
parser = mathtext.MathTextParser("Bitmap")
mpl.rc('text', usetex=True)
DefaultProps = mpl.font_manager.FontProperties(family = "sans-serif",\
style = "normal",\
weight = "medium",\
size = 6)
# size is changed from 6 to 7
#-------------------------------------------------------------------------------
def SetBitmap(self, _parent, _line, dpi = 150, prop = DefaultProps):
bmp = self.mathtext_to_wxbitmap(_line, dpi, prop = prop)
w,h = bmp.GetWidth(), bmp.GetHeight()
return wx.StaticBitmap(_parent, -1, bmp, (80, 50), (w, h))
#-------------------------------------------------------------------------------
def mathtext_to_wxbitmap(self, _s, dpi = 150, prop = DefaultProps):
ftimage, depth = self.parser.parse(_s, dpi, prop)
w,h = ftimage.get_width(), ftimage.get_height()
return wx.BitmapFromBufferRGBA(w, h, ftimage.as_rgba_str())
EXP = r'$\left(\frac{A \cdot \left(vds \cdot rs + \operatorname{Vdp}\left(ri, Rn, Hr, Hd\right) \cdot rh\right) \cdot \left(rSurf + \left(1.0 - rSurf\right) \cdot ft\right) \cdot \left(1.0 - e^{- \left(\left(lr + \frac{\operatorname{Log}\left(2\right)}{tem \cdot 86400.0}\right)\right) \cdot tFr \cdot 3600.0}\right)}{rc \cdot \left(lr + \frac{\operatorname{Log}\left(2\right)}{tem \cdot 86400.0}\right) \cdot tFr \cdot 3600.0} + 1\right)$'
class aFrame(wx.Frame):
def __init__(self, title="Edition"):
wx.Frame.__init__(self, None, wx.ID_ANY, title=title, size=(600,400),
style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
self.SetBackgroundColour(wx.Colour(255,255,255))
sizer = wx.FlexGridSizer(cols=25, vgap=4, hgap=4)
panel = scrolled.ScrolledPanel(self)
image_latex = LatexBitmapFactory().SetBitmap(panel, EXP)
sizer.Add(image_latex, flag=wx.EXPAND|wx.ALL)
panel.SetSizer(sizer)
panel.SetAutoLayout(1)
panel.SetupScrolling()
app = wx.App(redirect=True, filename="latexlog.txt")
frame = aFrame()
frame.Show()
app.MainLoop()
with size=6,显示如下图
尺寸=7,我有这个
latex表达式正确,第二张图正确。我没有任何错误消息,只是用“!”替换了右括号。
如果我继续写表达式我仍然有“!”尺码 6.
如果表达式更简单,则正确显示右括号。
有解决办法吗?
TL;DR mathtext.py
Line 727 的以下行中存在错误。它将大小为 Bigg
的右括号与索引 '\x21'
相关联,但这是感叹号的索引。有一点上下文的行是
_size_alternatives = {
'(' : [('rm', '('), ('ex', '\xa1'), ('ex', '\xb3'),
('ex', '\xb5'), ('ex', '\xc3')],
')' : [('rm', ')'), ('ex', '\xa2'), ('ex', '\xb4'),
('ex', '\xb6'), ('ex', '\x21')],
我不确定要更改到哪个索引,但我建议您将 mathtext.py
的本地副本更改为如下内容:
_size_alternatives = {
'(' : [('rm', '('), ('ex', '\xa1'), ('ex', '\xb3'),
('ex', '\xb5'), ('ex', '\x28')],
')' : [('rm', ')'), ('ex', '\xa2'), ('ex', '\xb4'),
('ex', '\xb6'), ('ex', '\x29')]
这产生的括号有点圆润,因为它们是基本的括号,但它们有效。同样 - 您可以替换为 bigg
尺寸的 - '\xb5'
和 'xb6'
关于matplotlib的报道githubIssue 5210
我可以使用提供的代码通过 size=6
重现这个问题
(如果是宽度问题,请使常量大一点)。我不能
通过设置 size = 7
重现 "fix",但如果我达到 size = 8
或更高,我可以 - 这表明这可能是一个令人讨厌的边缘案例错误并且可能依赖于系统...
我做了很多调查/诊断(见下文),但似乎有一个错误 - 在 matplotlib github here.
上报告
然而,减少到 matplotlib
唯一的例子产生了一个非常好的
渲染如下。注意我已经将我的 matplotlib 设置为使用乳胶
默认呈现 - 但您可以为
相同的结果。
代码
import matplotlib.pyplot as plt
import matplotlib as mpl
mpl.rc('image', origin='upper')
mpl.rc('text', usetex=True)
DefaultProps = mpl.font_manager.FontProperties(family = "sans-serif",\
style = "normal",\
weight = "medium",\
size = 6)
EXP = r'$\left(\frac{A \cdot \left(vds \cdot rs + \operatorname{Vdp}\left(ri, Rn, Hr, Hd\right) \cdot rh\right) \cdot \left(rSurf + \left(1.0 - rSurf\right) \cdot ft\right) \cdot \left(1.0 - e^{- \left(\left(lr + \frac{\operatorname{Log}\left(2\right)}{tem \cdot 86400.0}\right)\right) \cdot tFr \cdot 3600.0}\right)}{rc \cdot \left(lr + \frac{\operatorname{Log}\left(2\right)}{tem \cdot 86400.0}\right) \cdot tFr \cdot 3600.0} + 10589 \right)$'
plt.title(EXP, fontsize=6)
plt.gca().set_axis_off() # Get rid of the plotting axis for clarity
plt.show()
输出
输出 window 为清晰起见进行了裁剪和缩放,但您可以看到
括号渲染正常
这表明问题出在matplotlib的方式上
正在使用渲染引擎,输出到位图,或者交互
wxPython
根据实验,我注意到如果将 dpi 增加到 300,代码在 size = 6
时运行良好,但在 size = 3
时再次开始失败。这意味着问题在于其中一个库认为它无法以一定数量的像素呈现元素。
根本原因
诊断哪个位正在执行此操作 hard (IMO)
首先,我添加了
self.parser.to_png('D:\math_out.png', _s, color=u'black', dpi=150)
作为mathtext_to_wxbitmap(self, _s, dpi = 150, prop = DefaultProps)
的第一行。这给出了一个很好的输出 png
,让我觉得这可能不是 matplotlib 解析器的错误...... EDIT 基于,我对此进行了更多测试。实际上 - 如果我明确地将 fontsize
传递给此调用,我可以复制感叹号的外观。此外,传递给此调用的 dpi
被忽略 - 因此在我的测试中,我实际上处理的是 300 dpi 图像。所以,重点应该放在 MathTextParser
上,这可能是 dpi 问题。
进一步调查
进一步调查 - 我猴子修补了我的 matplotlib 安装 - 在调用 parseString()
here 后直接放入 print(result)
。使用可以正常工作的表达式并打印出文本表示。在有问题的情况下,我看到:
Traceback (most recent call last):
File "D:\baptiste_test.py", line 9, in <module>
parser.to_png(filename, s, fontsize=size)
File "C:\Python27\lib\site-packages\matplotlib\mathtext.py", line 3101, in to_
png
rgba, depth = self.to_rgba(texstr, color=color, dpi=dpi, fontsize=fontsize)
File "C:\Python27\lib\site-packages\matplotlib\mathtext.py", line 3066, in to_
rgba
x, depth = self.to_mask(texstr, dpi=dpi, fontsize=fontsize)
File "C:\Python27\lib\site-packages\matplotlib\mathtext.py", line 3039, in to_
mask
ftimage, depth = self.parse(texstr, dpi=dpi, prop=prop)
File "C:\Python27\lib\site-packages\matplotlib\mathtext.py", line 3012, in par
se
box = self._parser.parse(s, font_output, fontsize, dpi)
File "C:\Python27\lib\site-packages\matplotlib\mathtext.py", line 2339, in par
se
print(result[0])
File "C:\Python27\lib\site-packages\matplotlib\mathtext.py", line 1403, in __r
epr__
' '.join([repr(x) for x in self.children]))
File "C:\Python27\lib\site-packages\matplotlib\mathtext.py", line 1403, in __r
epr__
' '.join([repr(x) for x in self.children]))
File "C:\Python27\lib\site-packages\matplotlib\mathtext.py", line 1403, in __r
epr__
' '.join([repr(x) for x in self.children]))
File "C:\Python27\lib\site-packages\matplotlib\mathtext.py", line 1403, in __r
epr__
' '.join([repr(x) for x in self.children]))
UnicodeEncodeError: 'ascii' codec can't encode character u'\xb3' in position 1:
ordinal not in range(128)
这表明该错误可能源于翻译错误的字符 - 可能是字体中缺少代码点?
我还注意到,在 Baptiste 的最小示例中,您可以在没有 N
字母的情况下进行复制。
进一步进一步调查
在 BakomaFonts class 中的 _get_glyph 中粘贴一些调试打印。在失败的情况下,代码似乎在查找感叹号 (u'!'),而您希望它查找 u'\xc4' 并返回 parenrightBigg(即相应的左括号查找 u' 的位置) \xc3' 并返回 parenleftBigg)。在它只使用 parenrightbigg 的情况下,没有问题(在给定示例中 fontsize=5 时会出现这种情况,其他情况不会)。我放入 _get_glyph 的调试行是:
print('Getting glyph for symbol',repr(unicode(sym)))
print('Returning',cached_font, num, symbol_name, fontsize, slanted)
我猜它是否需要 bigg 或 Bigg 版本是基于 fontsize 和 dpi 的组合
好的 - 我认为问题出在这一行:https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/mathtext.py#L727
这是(有一点上下文):
_size_alternatives = {
'(' : [('rm', '('), ('ex', '\xa1'), ('ex', '\xb3'),
('ex', '\xb5'), ('ex', '\xc3')],
')' : [('rm', ')'), ('ex', '\xa2'), ('ex', '\xb4'),
('ex', '\xb6'), ('ex', '\x21')], ## <---- Incorrect line.
'\x21'
是错误的 - 但我不知道正确的是什么 '\x29'
很接近,但是 "too curved"。我猜 '\xc4'
遵循该模式,但那是一个向下箭头。希望核心开发人员之一可以根据它呈现的字形轻松查找此数字(十进制 195)并进行更正。
这是我为实现这种意外行为而编写的最短代码:
import matplotlib.mathtext as mt
s = r'$\left(\frac{\frac{\frac{M}{I}}{N}}' \
r'{\frac{\frac{B}{U}}{G}}\right)$'
parser = mt.MathTextParser("Bitmap")
for size in range(1, 30):
filename = "figure{0}.png".format(size)
parser.to_png(filename, s, fontsize=size)
输出看起来像这样(选择 6-12):
这个post更多的是共享重现错误的最少代码,而不是问题的答案
我还有“!” dpi='300' 大小为 9,但在 9 左右,除了 3,没问题。
我制作了一个新框架,可以同时使用 dpi 和大小以及“()”和“[]”。只需重复使用 'LatexBitmapFactory' 即可玩。
我使用 windows XP,使用 python 2.7。我在 Windows 7.
上有同样的错误
class aFrame(wx.Frame):
def __init__(self, title="Edition"):
wx.Frame.__init__(self, None, wx.ID_ANY, title=title, size=(1300,600),
style=wx.DEFAULT_DIALOG_STYLE)
self.SetBackgroundColour(wx.Colour(255,255,255))
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.panel = scrolled.ScrolledPanel(self)
init_dpi = 300
min_dpi, max_dpi = 100, 500
self.dpi_slider = wx.Slider(self.panel, wx.ID_ANY,
init_dpi, min_dpi, max_dpi, (30, 60), (250, -1),
wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | wx.SL_LABELS)
init_size = 9
min_size, max_size = 3, 40
self.size_slider = wx.Slider(
self.panel, wx.ID_ANY, init_size, min_size, max_size, (30, 60), (250, -1),
wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | wx.SL_LABELS)
self.log = wx.StaticText(self.panel, wx.ID_ANY, "DPI:%d SIZE:%d" %(init_dpi, init_size))
image_latex1 = self.create_lateximage(init_dpi, init_size)
image_latex2 = self.create_lateximage(init_dpi, init_size, replace_parenthesis=True)
self.sizer.Add(image_latex1, 1, flag=wx.ALIGN_CENTER|wx.EXPAND|wx.ALL)
self.sizer.Add(image_latex2, 1, flag=wx.ALIGN_CENTER|wx.EXPAND|wx.ALL)
self.sizer.Add(self.dpi_slider, 0, wx.ALIGN_CENTER)
self.sizer.Add(self.size_slider, 0, wx.ALIGN_CENTER)
self.sizer.Add(self.log, 0, wx.ALIGN_CENTER)
self.dpi_slider.Bind(wx.EVT_SCROLL_CHANGED, self.OnSliderChanged)
self.size_slider.Bind(wx.EVT_SCROLL_CHANGED, self.OnSliderChanged)
self.panel.SetSizer(self.sizer)
self.panel.SetAutoLayout(1)
self.panel.SetupScrolling()
def create_lateximage(self, dpi, size, replace_parenthesis=False):
updatedProps = mpl.font_manager.FontProperties(family = "sans-serif",\
style = "normal",\
weight = "medium",\
size = size)
if replace_parenthesis:
tp_exp = EXP.replace("right)", "right]")
tp_exp = tp_exp.replace("left(", "left[")
return LatexBitmapFactory().SetBitmap(self.panel, tp_exp, dpi=dpi, prop=updatedProps)
return LatexBitmapFactory().SetBitmap(self.panel, EXP, dpi=dpi, prop=updatedProps)
def OnSliderChanged(self, evt):
dpi = int(self.dpi_slider.GetValue())
size = int(self.size_slider.GetValue())
self.log.SetLabel("DPI:%d SIZE:%d" %(dpi, size))
self.Freeze()
new_image_latex1 = self.create_lateximage(dpi, size)
new_image_latex2 = self.create_lateximage(dpi, size, True)
prev_image_latex1 = self.sizer.Remove(0)
prev_image_latex2 = self.sizer.Remove(0)
del prev_image_latex1
del prev_image_latex2
self.sizer.Insert(0, new_image_latex2, 1, flag=wx.ALIGN_CENTER|wx.EXPAND|wx.ALL)
self.sizer.Insert(0, new_image_latex1, 1, flag=wx.ALIGN_CENTER|wx.EXPAND|wx.ALL)
self.sizer.Layout()
assert len(self.sizer.GetChildren()) == 5,\
" must have len 5, now %d"%len(self.sizer.GetChildren())
self.panel.SetupScrolling()
self.panel.SetScrollRate(100,100)
self.Thaw()
app = wx.App(redirect=True, filename="latexlog.txt")
frame = aFrame()
frame.Show()
app.MainLoop()
我处于必须将 python 表达式转换为最终用户的 Latex 位图的情况(他们有足够的信心自己编写 python 函数,但更喜欢在 Latex 中观察结果).
我正在使用 Matplotlib.mathtext 通过以下代码完成这项工作(从翻译的乳胶原始字符串)。
import wx
import wx.lib.scrolledpanel as scrolled
import matplotlib as mpl
from matplotlib import cm
from matplotlib import mathtext
class LatexBitmapFactory():
""" Latex Expression to Bitmap """
mpl.rc('image', origin='upper')
parser = mathtext.MathTextParser("Bitmap")
mpl.rc('text', usetex=True)
DefaultProps = mpl.font_manager.FontProperties(family = "sans-serif",\
style = "normal",\
weight = "medium",\
size = 6)
# size is changed from 6 to 7
#-------------------------------------------------------------------------------
def SetBitmap(self, _parent, _line, dpi = 150, prop = DefaultProps):
bmp = self.mathtext_to_wxbitmap(_line, dpi, prop = prop)
w,h = bmp.GetWidth(), bmp.GetHeight()
return wx.StaticBitmap(_parent, -1, bmp, (80, 50), (w, h))
#-------------------------------------------------------------------------------
def mathtext_to_wxbitmap(self, _s, dpi = 150, prop = DefaultProps):
ftimage, depth = self.parser.parse(_s, dpi, prop)
w,h = ftimage.get_width(), ftimage.get_height()
return wx.BitmapFromBufferRGBA(w, h, ftimage.as_rgba_str())
EXP = r'$\left(\frac{A \cdot \left(vds \cdot rs + \operatorname{Vdp}\left(ri, Rn, Hr, Hd\right) \cdot rh\right) \cdot \left(rSurf + \left(1.0 - rSurf\right) \cdot ft\right) \cdot \left(1.0 - e^{- \left(\left(lr + \frac{\operatorname{Log}\left(2\right)}{tem \cdot 86400.0}\right)\right) \cdot tFr \cdot 3600.0}\right)}{rc \cdot \left(lr + \frac{\operatorname{Log}\left(2\right)}{tem \cdot 86400.0}\right) \cdot tFr \cdot 3600.0} + 1\right)$'
class aFrame(wx.Frame):
def __init__(self, title="Edition"):
wx.Frame.__init__(self, None, wx.ID_ANY, title=title, size=(600,400),
style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
self.SetBackgroundColour(wx.Colour(255,255,255))
sizer = wx.FlexGridSizer(cols=25, vgap=4, hgap=4)
panel = scrolled.ScrolledPanel(self)
image_latex = LatexBitmapFactory().SetBitmap(panel, EXP)
sizer.Add(image_latex, flag=wx.EXPAND|wx.ALL)
panel.SetSizer(sizer)
panel.SetAutoLayout(1)
panel.SetupScrolling()
app = wx.App(redirect=True, filename="latexlog.txt")
frame = aFrame()
frame.Show()
app.MainLoop()
with size=6,显示如下图
尺寸=7,我有这个
latex表达式正确,第二张图正确。我没有任何错误消息,只是用“!”替换了右括号。
如果我继续写表达式我仍然有“!”尺码 6.
如果表达式更简单,则正确显示右括号。
有解决办法吗?
TL;DR mathtext.py
Line 727 的以下行中存在错误。它将大小为 Bigg
的右括号与索引 '\x21'
相关联,但这是感叹号的索引。有一点上下文的行是
_size_alternatives = {
'(' : [('rm', '('), ('ex', '\xa1'), ('ex', '\xb3'),
('ex', '\xb5'), ('ex', '\xc3')],
')' : [('rm', ')'), ('ex', '\xa2'), ('ex', '\xb4'),
('ex', '\xb6'), ('ex', '\x21')],
我不确定要更改到哪个索引,但我建议您将 mathtext.py
的本地副本更改为如下内容:
_size_alternatives = {
'(' : [('rm', '('), ('ex', '\xa1'), ('ex', '\xb3'),
('ex', '\xb5'), ('ex', '\x28')],
')' : [('rm', ')'), ('ex', '\xa2'), ('ex', '\xb4'),
('ex', '\xb6'), ('ex', '\x29')]
这产生的括号有点圆润,因为它们是基本的括号,但它们有效。同样 - 您可以替换为 bigg
尺寸的 - '\xb5'
和 'xb6'
关于matplotlib的报道githubIssue 5210
我可以使用提供的代码通过 size=6
重现这个问题
(如果是宽度问题,请使常量大一点)。我不能
通过设置 size = 7
重现 "fix",但如果我达到 size = 8
或更高,我可以 - 这表明这可能是一个令人讨厌的边缘案例错误并且可能依赖于系统...
我做了很多调查/诊断(见下文),但似乎有一个错误 - 在 matplotlib github here.
上报告然而,减少到 matplotlib
唯一的例子产生了一个非常好的
渲染如下。注意我已经将我的 matplotlib 设置为使用乳胶
默认呈现 - 但您可以为
相同的结果。
代码
import matplotlib.pyplot as plt
import matplotlib as mpl
mpl.rc('image', origin='upper')
mpl.rc('text', usetex=True)
DefaultProps = mpl.font_manager.FontProperties(family = "sans-serif",\
style = "normal",\
weight = "medium",\
size = 6)
EXP = r'$\left(\frac{A \cdot \left(vds \cdot rs + \operatorname{Vdp}\left(ri, Rn, Hr, Hd\right) \cdot rh\right) \cdot \left(rSurf + \left(1.0 - rSurf\right) \cdot ft\right) \cdot \left(1.0 - e^{- \left(\left(lr + \frac{\operatorname{Log}\left(2\right)}{tem \cdot 86400.0}\right)\right) \cdot tFr \cdot 3600.0}\right)}{rc \cdot \left(lr + \frac{\operatorname{Log}\left(2\right)}{tem \cdot 86400.0}\right) \cdot tFr \cdot 3600.0} + 10589 \right)$'
plt.title(EXP, fontsize=6)
plt.gca().set_axis_off() # Get rid of the plotting axis for clarity
plt.show()
输出
输出 window 为清晰起见进行了裁剪和缩放,但您可以看到 括号渲染正常
这表明问题出在matplotlib的方式上
正在使用渲染引擎,输出到位图,或者交互
wxPython
根据实验,我注意到如果将 dpi 增加到 300,代码在 size = 6
时运行良好,但在 size = 3
时再次开始失败。这意味着问题在于其中一个库认为它无法以一定数量的像素呈现元素。
根本原因
诊断哪个位正在执行此操作 hard (IMO)
首先,我添加了
self.parser.to_png('D:\math_out.png', _s, color=u'black', dpi=150)
作为mathtext_to_wxbitmap(self, _s, dpi = 150, prop = DefaultProps)
的第一行。这给出了一个很好的输出 png
,让我觉得这可能不是 matplotlib 解析器的错误...... EDIT 基于fontsize
传递给此调用,我可以复制感叹号的外观。此外,传递给此调用的 dpi
被忽略 - 因此在我的测试中,我实际上处理的是 300 dpi 图像。所以,重点应该放在 MathTextParser
上,这可能是 dpi 问题。
进一步调查
进一步调查 - 我猴子修补了我的 matplotlib 安装 - 在调用 parseString()
here 后直接放入 print(result)
。使用可以正常工作的表达式并打印出文本表示。在有问题的情况下,我看到:
Traceback (most recent call last):
File "D:\baptiste_test.py", line 9, in <module>
parser.to_png(filename, s, fontsize=size)
File "C:\Python27\lib\site-packages\matplotlib\mathtext.py", line 3101, in to_
png
rgba, depth = self.to_rgba(texstr, color=color, dpi=dpi, fontsize=fontsize)
File "C:\Python27\lib\site-packages\matplotlib\mathtext.py", line 3066, in to_
rgba
x, depth = self.to_mask(texstr, dpi=dpi, fontsize=fontsize)
File "C:\Python27\lib\site-packages\matplotlib\mathtext.py", line 3039, in to_
mask
ftimage, depth = self.parse(texstr, dpi=dpi, prop=prop)
File "C:\Python27\lib\site-packages\matplotlib\mathtext.py", line 3012, in par
se
box = self._parser.parse(s, font_output, fontsize, dpi)
File "C:\Python27\lib\site-packages\matplotlib\mathtext.py", line 2339, in par
se
print(result[0])
File "C:\Python27\lib\site-packages\matplotlib\mathtext.py", line 1403, in __r
epr__
' '.join([repr(x) for x in self.children]))
File "C:\Python27\lib\site-packages\matplotlib\mathtext.py", line 1403, in __r
epr__
' '.join([repr(x) for x in self.children]))
File "C:\Python27\lib\site-packages\matplotlib\mathtext.py", line 1403, in __r
epr__
' '.join([repr(x) for x in self.children]))
File "C:\Python27\lib\site-packages\matplotlib\mathtext.py", line 1403, in __r
epr__
' '.join([repr(x) for x in self.children]))
UnicodeEncodeError: 'ascii' codec can't encode character u'\xb3' in position 1:
ordinal not in range(128)
这表明该错误可能源于翻译错误的字符 - 可能是字体中缺少代码点?
我还注意到,在 Baptiste 的最小示例中,您可以在没有 N
字母的情况下进行复制。
进一步进一步调查
在 BakomaFonts class 中的 _get_glyph 中粘贴一些调试打印。在失败的情况下,代码似乎在查找感叹号 (u'!'),而您希望它查找 u'\xc4' 并返回 parenrightBigg(即相应的左括号查找 u' 的位置) \xc3' 并返回 parenleftBigg)。在它只使用 parenrightbigg 的情况下,没有问题(在给定示例中 fontsize=5 时会出现这种情况,其他情况不会)。我放入 _get_glyph 的调试行是:
print('Getting glyph for symbol',repr(unicode(sym)))
print('Returning',cached_font, num, symbol_name, fontsize, slanted)
我猜它是否需要 bigg 或 Bigg 版本是基于 fontsize 和 dpi 的组合
好的 - 我认为问题出在这一行:https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/mathtext.py#L727
这是(有一点上下文):
_size_alternatives = {
'(' : [('rm', '('), ('ex', '\xa1'), ('ex', '\xb3'),
('ex', '\xb5'), ('ex', '\xc3')],
')' : [('rm', ')'), ('ex', '\xa2'), ('ex', '\xb4'),
('ex', '\xb6'), ('ex', '\x21')], ## <---- Incorrect line.
'\x21'
是错误的 - 但我不知道正确的是什么 '\x29'
很接近,但是 "too curved"。我猜 '\xc4'
遵循该模式,但那是一个向下箭头。希望核心开发人员之一可以根据它呈现的字形轻松查找此数字(十进制 195)并进行更正。
这是我为实现这种意外行为而编写的最短代码:
import matplotlib.mathtext as mt
s = r'$\left(\frac{\frac{\frac{M}{I}}{N}}' \
r'{\frac{\frac{B}{U}}{G}}\right)$'
parser = mt.MathTextParser("Bitmap")
for size in range(1, 30):
filename = "figure{0}.png".format(size)
parser.to_png(filename, s, fontsize=size)
输出看起来像这样(选择 6-12):
这个post更多的是共享重现错误的最少代码,而不是问题的答案
我还有“!” dpi='300' 大小为 9,但在 9 左右,除了 3,没问题。
我制作了一个新框架,可以同时使用 dpi 和大小以及“()”和“[]”。只需重复使用 'LatexBitmapFactory' 即可玩。
我使用 windows XP,使用 python 2.7。我在 Windows 7.
上有同样的错误class aFrame(wx.Frame):
def __init__(self, title="Edition"):
wx.Frame.__init__(self, None, wx.ID_ANY, title=title, size=(1300,600),
style=wx.DEFAULT_DIALOG_STYLE)
self.SetBackgroundColour(wx.Colour(255,255,255))
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.panel = scrolled.ScrolledPanel(self)
init_dpi = 300
min_dpi, max_dpi = 100, 500
self.dpi_slider = wx.Slider(self.panel, wx.ID_ANY,
init_dpi, min_dpi, max_dpi, (30, 60), (250, -1),
wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | wx.SL_LABELS)
init_size = 9
min_size, max_size = 3, 40
self.size_slider = wx.Slider(
self.panel, wx.ID_ANY, init_size, min_size, max_size, (30, 60), (250, -1),
wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | wx.SL_LABELS)
self.log = wx.StaticText(self.panel, wx.ID_ANY, "DPI:%d SIZE:%d" %(init_dpi, init_size))
image_latex1 = self.create_lateximage(init_dpi, init_size)
image_latex2 = self.create_lateximage(init_dpi, init_size, replace_parenthesis=True)
self.sizer.Add(image_latex1, 1, flag=wx.ALIGN_CENTER|wx.EXPAND|wx.ALL)
self.sizer.Add(image_latex2, 1, flag=wx.ALIGN_CENTER|wx.EXPAND|wx.ALL)
self.sizer.Add(self.dpi_slider, 0, wx.ALIGN_CENTER)
self.sizer.Add(self.size_slider, 0, wx.ALIGN_CENTER)
self.sizer.Add(self.log, 0, wx.ALIGN_CENTER)
self.dpi_slider.Bind(wx.EVT_SCROLL_CHANGED, self.OnSliderChanged)
self.size_slider.Bind(wx.EVT_SCROLL_CHANGED, self.OnSliderChanged)
self.panel.SetSizer(self.sizer)
self.panel.SetAutoLayout(1)
self.panel.SetupScrolling()
def create_lateximage(self, dpi, size, replace_parenthesis=False):
updatedProps = mpl.font_manager.FontProperties(family = "sans-serif",\
style = "normal",\
weight = "medium",\
size = size)
if replace_parenthesis:
tp_exp = EXP.replace("right)", "right]")
tp_exp = tp_exp.replace("left(", "left[")
return LatexBitmapFactory().SetBitmap(self.panel, tp_exp, dpi=dpi, prop=updatedProps)
return LatexBitmapFactory().SetBitmap(self.panel, EXP, dpi=dpi, prop=updatedProps)
def OnSliderChanged(self, evt):
dpi = int(self.dpi_slider.GetValue())
size = int(self.size_slider.GetValue())
self.log.SetLabel("DPI:%d SIZE:%d" %(dpi, size))
self.Freeze()
new_image_latex1 = self.create_lateximage(dpi, size)
new_image_latex2 = self.create_lateximage(dpi, size, True)
prev_image_latex1 = self.sizer.Remove(0)
prev_image_latex2 = self.sizer.Remove(0)
del prev_image_latex1
del prev_image_latex2
self.sizer.Insert(0, new_image_latex2, 1, flag=wx.ALIGN_CENTER|wx.EXPAND|wx.ALL)
self.sizer.Insert(0, new_image_latex1, 1, flag=wx.ALIGN_CENTER|wx.EXPAND|wx.ALL)
self.sizer.Layout()
assert len(self.sizer.GetChildren()) == 5,\
" must have len 5, now %d"%len(self.sizer.GetChildren())
self.panel.SetupScrolling()
self.panel.SetScrollRate(100,100)
self.Thaw()
app = wx.App(redirect=True, filename="latexlog.txt")
frame = aFrame()
frame.Show()
app.MainLoop()