Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 4df967c

Browse files
committed
backend_svg: separate font attributes && use translate(x y) in RendedSVG._draw_text_as_path
fixed linting (flake8 test failing) Fixed checks in testing for svg.fonttype = none fixed flake8 && failing tests linting modified tspans && fix to svg tests Updated baseline images for svg tests Update lib/matplotlib/testing/compare.py nicer regex to check if font syling in svg is specified Co-authored-by: Tim Hoffmann <[email protected]> Apply suggestions from code review More concise font testing in test_backend_svg.py Co-authored-by: Tim Hoffmann <[email protected]> Update lib/matplotlib/tests/test_mathtext.py Co-authored-by: Tim Hoffmann <[email protected]> Update backend_svg.py inlining `style` restored test images update to baseline images Fix to regex for testing/compare.py::compare
1 parent 5ab5532 commit 4df967c

29 files changed

+13839
-13066
lines changed

lib/matplotlib/backends/backend_svg.py

Lines changed: 43 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,12 +1050,13 @@ def _draw_text_as_path(self, gc, x, y, s, prop, angle, ismath, mtext=None):
10501050
self._update_glyph_map_defs(glyph_map_new)
10511051

10521052
for glyph_id, xposition, yposition, scale in glyph_info:
1053-
attrib = {'xlink:href': f'#{glyph_id}'}
1054-
if xposition != 0.0:
1055-
attrib['x'] = _short_float_fmt(xposition)
1056-
if yposition != 0.0:
1057-
attrib['y'] = _short_float_fmt(yposition)
1058-
writer.element('use', attrib=attrib)
1053+
writer.element(
1054+
'use',
1055+
transform=_generate_transform([
1056+
('translate', (xposition, yposition)),
1057+
('scale', (scale,)),
1058+
]),
1059+
attrib={'xlink:href': f'#{glyph_id}'})
10591060

10601061
else:
10611062
if ismath == "TeX":
@@ -1093,25 +1094,26 @@ def _draw_text_as_text(self, gc, x, y, s, prop, angle, ismath, mtext=None):
10931094
writer = self.writer
10941095

10951096
color = rgb2hex(gc.get_rgb())
1096-
style = {}
1097+
font_style = {}
1098+
color_style = {}
10971099
if color != '#000000':
1098-
style['fill'] = color
1100+
color_style['fill'] = color
10991101

11001102
alpha = gc.get_alpha() if gc.get_forced_alpha() else gc.get_rgb()[3]
11011103
if alpha != 1:
1102-
style['opacity'] = _short_float_fmt(alpha)
1104+
color_style['opacity'] = _short_float_fmt(alpha)
11031105

11041106
if not ismath:
11051107
attrib = {}
11061108

1107-
font_parts = []
1109+
# Separate font style in their separate attributes
11081110
if prop.get_style() != 'normal':
1109-
font_parts.append(prop.get_style())
1111+
font_style['font-style'] = prop.get_style()
11101112
if prop.get_variant() != 'normal':
1111-
font_parts.append(prop.get_variant())
1113+
font_style['font-variant'] = prop.get_variant()
11121114
weight = fm.weight_dict[prop.get_weight()]
11131115
if weight != 400:
1114-
font_parts.append(f'{weight}')
1116+
font_style['font-weight'] = f'{weight}'
11151117

11161118
def _normalize_sans(name):
11171119
return 'sans-serif' if name in ['sans', 'sans serif'] else name
@@ -1134,15 +1136,15 @@ def _get_all_quoted_names(prop):
11341136
for entry in prop.get_family()
11351137
for name in _expand_family_entry(entry)]
11361138

1137-
font_parts.extend([
1138-
f'{_short_float_fmt(prop.get_size())}px',
1139-
# ensure expansion, quoting, and dedupe of font names
1140-
", ".join(dict.fromkeys(_get_all_quoted_names(prop)))
1141-
])
1142-
style['font'] = ' '.join(font_parts)
1139+
font_style['font-size'] = f'{_short_float_fmt(prop.get_size())}px'
1140+
# ensure expansion, quoting, and dedupe of font names
1141+
font_style['font-family'] = ", ".join(
1142+
dict.fromkeys(_get_all_quoted_names(prop))
1143+
)
1144+
11431145
if prop.get_stretch() != 'normal':
1144-
style['font-stretch'] = prop.get_stretch()
1145-
attrib['style'] = _generate_css(style)
1146+
font_style['font-stretch'] = prop.get_stretch()
1147+
attrib['style'] = _generate_css({**font_style, **color_style})
11461148

11471149
if mtext and (angle == 0 or mtext.get_rotation_mode() == "anchor"):
11481150
# If text anchoring can be supported, get the original
@@ -1164,11 +1166,11 @@ def _get_all_quoted_names(prop):
11641166

11651167
ha_mpl_to_svg = {'left': 'start', 'right': 'end',
11661168
'center': 'middle'}
1167-
style['text-anchor'] = ha_mpl_to_svg[mtext.get_ha()]
1169+
font_style['text-anchor'] = ha_mpl_to_svg[mtext.get_ha()]
11681170

11691171
attrib['x'] = _short_float_fmt(ax)
11701172
attrib['y'] = _short_float_fmt(ay)
1171-
attrib['style'] = _generate_css(style)
1173+
attrib['style'] = _generate_css({**font_style, **color_style})
11721174
attrib['transform'] = _generate_transform([
11731175
("rotate", (-angle, ax, ay))])
11741176

@@ -1188,7 +1190,7 @@ def _get_all_quoted_names(prop):
11881190
# Apply attributes to 'g', not 'text', because we likely have some
11891191
# rectangles as well with the same style and transformation.
11901192
writer.start('g',
1191-
style=_generate_css(style),
1193+
style=_generate_css({**font_style, **color_style}),
11921194
transform=_generate_transform([
11931195
('translate', (x, y)),
11941196
('rotate', (-angle,))]),
@@ -1200,43 +1202,32 @@ def _get_all_quoted_names(prop):
12001202
spans = {}
12011203
for font, fontsize, thetext, new_x, new_y in glyphs:
12021204
entry = fm.ttfFontProperty(font)
1203-
font_parts = []
1205+
font_style = {}
1206+
# Separate font style in its separate attributes
12041207
if entry.style != 'normal':
1205-
font_parts.append(entry.style)
1208+
font_style['font-style'] = entry.style
12061209
if entry.variant != 'normal':
1207-
font_parts.append(entry.variant)
1210+
font_style['font-variant'] = entry.variant
12081211
if entry.weight != 400:
1209-
font_parts.append(f'{entry.weight}')
1210-
font_parts.extend([
1211-
f'{_short_float_fmt(fontsize)}px',
1212-
f'{entry.name!r}', # ensure quoting
1213-
])
1214-
style = {'font': ' '.join(font_parts)}
1212+
font_style['font-weight'] = f'{entry.weight}'
1213+
font_style['font-size'] = f'{_short_float_fmt(fontsize)}px'
1214+
font_style['font-family'] = f'{entry.name!r}' # ensure quoting
12151215
if entry.stretch != 'normal':
1216-
style['font-stretch'] = entry.stretch
1217-
style = _generate_css(style)
1216+
font_style['font-stretch'] = entry.stretch
1217+
style = _generate_css({**font_style, **color_style})
12181218
if thetext == 32:
12191219
thetext = 0xa0 # non-breaking space
12201220
spans.setdefault(style, []).append((new_x, -new_y, thetext))
12211221

12221222
for style, chars in spans.items():
1223-
chars.sort()
1224-
1225-
if len({y for x, y, t in chars}) == 1: # Are all y's the same?
1226-
ys = str(chars[0][1])
1227-
else:
1228-
ys = ' '.join(str(c[1]) for c in chars)
1229-
1230-
attrib = {
1231-
'style': style,
1232-
'x': ' '.join(_short_float_fmt(c[0]) for c in chars),
1233-
'y': ys
1234-
}
1235-
1236-
writer.element(
1237-
'tspan',
1238-
''.join(chr(c[2]) for c in chars),
1239-
attrib=attrib)
1223+
chars.sort() # Sort by increasing x position
1224+
for x, y, t in chars: # Output one tspan for each character
1225+
writer.element(
1226+
'tspan',
1227+
chr(t),
1228+
x=_short_float_fmt(x),
1229+
y=_short_float_fmt(y),
1230+
style=style)
12401231

12411232
writer.end('text')
12421233

lib/matplotlib/testing/compare.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import sys
1414
from tempfile import TemporaryDirectory, TemporaryFile
1515
import weakref
16+
import re
1617

1718
import numpy as np
1819
from PIL import Image
@@ -305,7 +306,15 @@ def convert(filename, cache):
305306
# re-generate any SVG test files using this mode, or else such tests will
306307
# fail to use the converter for the expected images (but will for the
307308
# results), and the tests will fail strangely.
308-
if 'style="font:' in contents:
309+
if re.search(
310+
# searches for attributes :
311+
# style=[font|font-size|font-weight|
312+
# font-family|font-variant|font-style]
313+
# taking care of the possibility of multiple style attributes
314+
# before the font styling (i.e. opacity)
315+
r'style="[^"]*font(|-size|-weight|-family|-variant|-style):',
316+
contents # raw contents of the svg file
317+
):
309318
# for svg.fonttype = none, we explicitly patch the font search
310319
# path so that fonts shipped by Matplotlib are found.
311320
convert = _svg_with_matplotlib_fonts_converter

0 commit comments

Comments
 (0)