Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commite66a701

Browse files
committed
Improve font spec for SVG font referencing.
The 'font: ...' shorthand is much more concise than setting eachproperty separately: This replaces e.g.`"font-family:DejaVu Sans;font-size:12px;font-style:book;font-weight:book;"`by `"font: 400 12px 'DejaVu Sans'"`.Note that the previous font weight was plain wrong...Also this revealed a bug in generate_css (we shouldn't run it throughescape_attrib, as quotes (e.g. around the font family name) getmangled); and we don't need to load the font at all (we should justreport whatever font the user actually requested).
1 parent792fc13 commite66a701

File tree

3 files changed

+53
-38
lines changed

3 files changed

+53
-38
lines changed

‎lib/matplotlib/backends/backend_svg.py

Lines changed: 41 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@
2121
frommatplotlib.backends.backend_mixedimportMixedModeRenderer
2222
frommatplotlib.colorsimportrgb2hex
2323
frommatplotlib.datesimportUTC
24-
frommatplotlib.font_managerimportfindfont,get_font
25-
frommatplotlib.ft2fontimportLOAD_NO_HINTING
24+
frommatplotlib.font_managerimportfindfont,get_font,ttfFontProperty
2625
frommatplotlib.mathtextimportMathTextParser
2726
frommatplotlib.pathimportPath
2827
frommatplotlibimport_path
@@ -94,6 +93,12 @@ def escape_attrib(s):
9493
returns
9594

9695

96+
def_quote_escape_attrib(s):
97+
return ('"'+escape_cdata(s)+'"'if'"'notinselse
98+
"'"+escape_cdata(s)+"'"if"'"notinselse
99+
'"'+escape_attrib(s)+'"')
100+
101+
97102
defshort_float_fmt(x):
98103
"""
99104
Create a short string representation of a float, which is %f
@@ -159,8 +164,8 @@ def start(self, tag, attrib={}, **extra):
159164
fork,vinsorted({**attrib,**extra}.items()):
160165
ifv:
161166
k=escape_cdata(k)
162-
v=escape_attrib(v)
163-
self.__write(' %s="%s"'% (k,v))
167+
v=_quote_escape_attrib(v)
168+
self.__write(' %s=%s'% (k,v))
164169
self.__open=1
165170
returnlen(self.__tags)-1
166171

@@ -262,15 +267,7 @@ def generate_transform(transform_list=[]):
262267

263268

264269
defgenerate_css(attrib={}):
265-
ifattrib:
266-
output=StringIO()
267-
attrib=sorted(attrib.items())
268-
fork,vinattrib:
269-
k=escape_attrib(k)
270-
v=escape_attrib(v)
271-
output.write("%s:%s;"% (k,v))
272-
returnoutput.getvalue()
273-
return''
270+
return'; '.join(f'{k}:{v}'fork,vinsorted(attrib.items()))
274271

275272

276273
_capstyle_d= {'projecting':'square','butt':'butt','round':'round'}
@@ -1128,16 +1125,22 @@ def _draw_text_as_text(self, gc, x, y, s, prop, angle, ismath, mtext=None):
11281125
style['opacity']=short_float_fmt(alpha)
11291126

11301127
ifnotismath:
1131-
font=self._get_font(prop)
1132-
font.set_text(s,0.0,flags=LOAD_NO_HINTING)
1133-
11341128
attrib= {}
1135-
style['font-family']=str(font.family_name)
1136-
style['font-weight']=str(prop.get_weight()).lower()
1137-
style['font-stretch']=str(prop.get_stretch()).lower()
1138-
style['font-style']=prop.get_style().lower()
1139-
# Must add "px" to workaround a Firefox bug
1140-
style['font-size']=short_float_fmt(prop.get_size())+'px'
1129+
1130+
font_parts= []
1131+
ifprop.get_style()!='normal':
1132+
font_parts.append(prop.get_style())
1133+
ifprop.get_variant()!='normal':
1134+
font_parts.append(prop.get_variant())
1135+
ifprop.get_weight()notin ['normal','regular',400]:
1136+
font_parts.append(prop.get_weight())
1137+
font_parts.extend([
1138+
f'{short_float_fmt(prop.get_size())}px',
1139+
f'{prop.get_family()[0]!r}',# ensure quoting
1140+
])
1141+
style['font']=' '.join(font_parts)
1142+
ifprop.get_stretch()!='normal':
1143+
style['font-stretch']=prop.get_stretch()
11411144
attrib['style']=generate_css(style)
11421145

11431146
ifmtextand (angle==0ormtext.get_rotation_mode()=="anchor"):
@@ -1197,11 +1200,22 @@ def _draw_text_as_text(self, gc, x, y, s, prop, angle, ismath, mtext=None):
11971200
# Sort the characters by font, and output one tspan for each.
11981201
spans=OrderedDict()
11991202
forfont,fontsize,thetext,new_x,new_yinglyphs:
1200-
style=generate_css({
1201-
'font-size':short_float_fmt(fontsize)+'px',
1202-
'font-family':font.family_name,
1203-
'font-style':font.style_name.lower(),
1204-
'font-weight':font.style_name.lower()})
1203+
entry=ttfFontProperty(font)
1204+
font_parts= []
1205+
ifentry.style!='normal':
1206+
font_parts.append(entry.style)
1207+
ifentry.variant!='normal':
1208+
font_parts.append(entry.variant)
1209+
ifentry.weight!=400:
1210+
font_parts.append(f'{entry.weight}')
1211+
font_parts.extend([
1212+
f'{short_float_fmt(fontsize)}px',
1213+
f'{entry.name!r}',# ensure quoting
1214+
])
1215+
style= {'font':' '.join(font_parts)}
1216+
ifentry.stretch!='normal':
1217+
style['font-stretch']=entry.stretch
1218+
style=generate_css(style)
12051219
ifthetext==32:
12061220
thetext=0xa0# non-breaking space
12071221
spans.setdefault(style, []).append((new_x,-new_y,thetext))

‎lib/matplotlib/tests/test_backend_svg.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ def test_unicode_won():
216216

217217

218218
deftest_svgnone_with_data_coordinates():
219-
plt.rcParams['svg.fonttype']='none'
219+
plt.rcParams.update({'svg.fonttype':'none','font.stretch':'condensed'})
220220
expected='Unlikely to appear by chance'
221221

222222
fig,ax=plt.subplots()
@@ -229,9 +229,7 @@ def test_svgnone_with_data_coordinates():
229229
fd.seek(0)
230230
buf=fd.read().decode()
231231

232-
assertexpectedinbuf
233-
forpropin ["family","weight","stretch","style","size"]:
234-
assertf"font-{prop}:"inbuf
232+
assertexpectedinbufand"condensed"inbuf
235233

236234

237235
deftest_gid():

‎lib/matplotlib/tests/test_mathtext.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
importio
2-
importos
2+
frompathlibimportPath
33
importre
4+
importshlex
5+
fromxml.etreeimportElementTreeasET
46

57
importnumpyasnp
68
importpytest
@@ -328,7 +330,7 @@ def test_mathtext_fallback_to_cm_invalid():
328330
("stix", ['DejaVu Sans','mpltest','STIXGeneral'])])
329331
deftest_mathtext_fallback(fallback,fontlist):
330332
mpl.font_manager.fontManager.addfont(
331-
os.path.join((os.path.dirname(os.path.realpath(__file__))),'mpltest.ttf'))
333+
str(Path(__file__).resolve().parent/'mpltest.ttf'))
332334
mpl.rcParams["svg.fonttype"]='none'
333335
mpl.rcParams['mathtext.fontset']='custom'
334336
mpl.rcParams['mathtext.rm']='mpltest'
@@ -342,12 +344,13 @@ def test_mathtext_fallback(fallback, fontlist):
342344
fig,ax=plt.subplots()
343345
fig.text(.5,.5,test_str,fontsize=40,ha='center')
344346
fig.savefig(buff,format="svg")
345-
char_fonts= [
346-
line.split("font-family:")[-1].split(";")[0]
347-
forlineinstr(buff.getvalue()).split(r"\n")if"tspan"inline
348-
]
347+
tspans= (ET.fromstring(buff.getvalue())
348+
.findall(".//{http://www.w3.org/2000/svg}tspan[@style]"))
349+
# Getting the last element of the style attrib is a close enough
350+
# approximation for parsing the font property.
351+
char_fonts= [shlex.split(tspan.attrib["style"])[-1]fortspanintspans]
349352
assertchar_fonts==fontlist
350-
mpl.font_manager.fontManager.ttflist=mpl.font_manager.fontManager.ttflist[:-1]
353+
mpl.font_manager.fontManager.ttflist.pop()
351354

352355

353356
deftest_math_to_image(tmpdir):

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp