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

Commiteae2cbf

Browse files
committed
Add language parameter to Text objects
1 parent0da372b commiteae2cbf

File tree

17 files changed

+250
-18
lines changed

17 files changed

+250
-18
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
Specifying text language
2+
------------------------
3+
4+
OpenType fonts may support language systems which can be used to select different
5+
typographic conventions, e.g., localized variants of letters that share a single Unicode
6+
code point, or different default font features. The text API now supports setting a
7+
language to be used and may be set/get with:
8+
9+
- `matplotlib.text.Text.set_language` / `matplotlib.text.Text.get_language`
10+
- Any API that creates a `.Text` object by passing the *language* argument (e.g.,
11+
``plt.xlabel(..., language=...)``)
12+
13+
The language of the text must be in a format accepted by libraqm, namely `a BCP47
14+
language code <https://www.w3.org/International/articles/language-tags/>`_. If None or
15+
unset, then no particular language will be implied, and default font settings will be
16+
used.
17+
18+
For example, Matplotlib's default font ``DejaVu Sans`` supports language-specific glyphs
19+
in the Serbian and Macedonian languages in the Cyrillic alphabet, or the Sámi family of
20+
languages in the Latin alphabet.
21+
22+
..plot::
23+
:include-source:
24+
25+
fig = plt.figure(figsize=(7, 3))
26+
27+
char = '\U00000431'
28+
fig.text(0.5, 0.8, f'\\U{ord(char):08x}', fontsize=40, horizontalalignment='center')
29+
fig.text(0, 0.6, f'Serbian: {char}', fontsize=40, language='sr')
30+
fig.text(1, 0.6, f'Russian: {char}', fontsize=40, language='ru',
31+
horizontalalignment='right')
32+
33+
char = '\U0000014a'
34+
fig.text(0.5, 0.3, f'\\U{ord(char):08x}', fontsize=40, horizontalalignment='center')
35+
fig.text(0, 0.1, f'English: {char}', fontsize=40, language='en')
36+
fig.text(1, 0.1, f'Inari Sámi: {char}', fontsize=40, language='smn',
37+
horizontalalignment='right')

‎lib/matplotlib/_text_helpers.py‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def warn_on_missing_glyph(codepoint, fontnames):
2626
f"missing from font(s){fontnames}.")
2727

2828

29-
deflayout(string,font,*,kern_mode=Kerning.DEFAULT):
29+
deflayout(string,font,*,kern_mode=Kerning.DEFAULT,language=None):
3030
"""
3131
Render *string* with *font*.
3232
@@ -41,14 +41,17 @@ def layout(string, font, *, kern_mode=Kerning.DEFAULT):
4141
The font.
4242
kern_mode : Kerning
4343
A FreeType kerning mode.
44+
language : str, optional
45+
The language of the text in a format accepted by libraqm, namely `a BCP47
46+
language code <https://www.w3.org/International/articles/language-tags/>`_.
4447
4548
Yields
4649
------
4750
LayoutItem
4851
"""
4952
x=0
5053
prev_glyph_index=None
51-
char_to_font=font._get_fontmap(string)
54+
char_to_font=font._get_fontmap(string)# TODO: Pass in language.
5255
base_font=font
5356
forcharinstring:
5457
# This has done the fallback logic

‎lib/matplotlib/backends/backend_agg.py‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,8 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
190190
font=self._prepare_font(prop)
191191
# We pass '0' for angle here, since it will be rotated (in raster
192192
# space) in the following call to draw_text_image).
193-
font.set_text(s,0,flags=get_hinting_flag())
193+
font.set_text(s,0,flags=get_hinting_flag(),
194+
language=mtext.get_language()ifmtextisnotNoneelseNone)
194195
font.draw_glyphs_to_bitmap(
195196
antialiased=gc.get_antialiased())
196197
d=font.get_descent()/64.0

‎lib/matplotlib/backends/backend_pdf.py‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2338,6 +2338,7 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
23382338
returnself.draw_mathtext(gc,x,y,s,prop,angle)
23392339

23402340
fontsize=prop.get_size_in_points()
2341+
language=mtext.get_language()ifmtextisnotNoneelseNone
23412342

23422343
ifmpl.rcParams['pdf.use14corefonts']:
23432344
font=self._get_font_afm(prop)
@@ -2348,7 +2349,7 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
23482349
fonttype=mpl.rcParams['pdf.fonttype']
23492350

23502351
ifgc.get_url()isnotNone:
2351-
font.set_text(s)
2352+
font.set_text(s,language=language)
23522353
width,height=font.get_width_height()
23532354
self.file._annotations[-1][1].append(_get_link_annotation(
23542355
gc,x,y,width/64,height/64,angle))
@@ -2382,7 +2383,8 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
23822383
multibyte_glyphs= []
23832384
prev_was_multibyte=True
23842385
prev_font=font
2385-
foritemin_text_helpers.layout(s,font,kern_mode=Kerning.UNFITTED):
2386+
foritemin_text_helpers.layout(s,font,kern_mode=Kerning.UNFITTED,
2387+
language=language):
23862388
if_font_supports_glyph(fonttype,ord(item.char)):
23872389
ifprev_was_multibyteoritem.ft_object!=prev_font:
23882390
singlebyte_chunks.append((item.ft_object,item.x, []))

‎lib/matplotlib/backends/backend_ps.py‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -791,9 +791,10 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
791791
thisx+=width*scale
792792

793793
else:
794+
language=mtext.get_language()ifmtextisnotNoneelseNone
794795
font=self._get_font_ttf(prop)
795796
self._character_tracker.track(font,s)
796-
foritemin_text_helpers.layout(s,font):
797+
foritemin_text_helpers.layout(s,font,language=language):
797798
ps_name= (item.ft_object.postscript_name
798799
.encode("ascii","replace").decode("ascii"))
799800
glyph_name=item.ft_object.get_glyph_name(item.glyph_index)

‎lib/matplotlib/ft2font.pyi‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,12 @@ class FT2Font(Buffer):
243243
defset_charmap(self,i:int)->None: ...
244244
defset_size(self,ptsize:float,dpi:float)->None: ...
245245
defset_text(
246-
self,string:str,angle:float= ...,flags:LoadFlags= ...
246+
self,
247+
string:str,
248+
angle:float= ...,
249+
flags:LoadFlags= ...,
250+
*,
251+
language:str|list[tuple[str,int,int]]|None= ...,
247252
)->NDArray[np.float64]: ...
248253
@property
249254
defascender(self)->int: ...

‎lib/matplotlib/mpl-data/matplotlibrc‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,11 @@
292292
## for more information on text properties
293293
#text.color: black
294294

295+
## The language of the text in a format accepted by libraqm, namely `a BCP47 language
296+
## code <https://www.w3.org/International/articles/language-tags/>`_. If None, then no
297+
## particular language will be implied, and default font settings will be used.
298+
#text.language: None
299+
295300
## FreeType hinting flag ("foo" corresponds to FT_LOAD_FOO); may be one of the
296301
## following (Proprietary Matplotlib-specific synonyms are given in parentheses,
297302
## but their use is discouraged):

‎lib/matplotlib/rcsetup.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1045,6 +1045,7 @@ def _convert_validator_spec(key, conv):
10451045
"text.kerning_factor":validate_int_or_None,
10461046
"text.antialiased":validate_bool,
10471047
"text.parse_math":validate_bool,
1048+
"text.language":validate_string_or_None,
10481049

10491050
"mathtext.cal":validate_font_properties,
10501051
"mathtext.rm":validate_font_properties,

‎lib/matplotlib/tests/test_ft2font.py‎

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -783,6 +783,37 @@ def test_ft2font_set_text():
783783
assertfont.get_bitmap_offset()== (6,0)
784784

785785

786+
@pytest.mark.parametrize(
787+
'input',
788+
[
789+
[1,2,3],
790+
[(1,2)],
791+
[('en','foo',2)],
792+
[('en',1,'foo')],
793+
],
794+
ids=[
795+
'nontuple',
796+
'wrong length',
797+
'wrong start type',
798+
'wrong end type',
799+
],
800+
)
801+
deftest_ft2font_language_invalid(input):
802+
file=fm.findfont('DejaVu Sans')
803+
font=ft2font.FT2Font(file,hinting_factor=1)
804+
withpytest.raises(TypeError):
805+
font.set_text('foo',language=input)
806+
807+
808+
deftest_ft2font_language():
809+
# This is just a smoke test.
810+
file=fm.findfont('DejaVu Sans')
811+
font=ft2font.FT2Font(file,hinting_factor=1)
812+
font.set_text('foo')
813+
font.set_text('foo',language='en')
814+
font.set_text('foo',language=[('en',1,2)])
815+
816+
786817
deftest_ft2font_loading():
787818
file=fm.findfont('DejaVu Sans')
788819
font=ft2font.FT2Font(file,hinting_factor=1)

‎lib/matplotlib/tests/test_text.py‎

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,3 +1202,60 @@ def test_ytick_rotation_mode():
12021202
tick.set_rotation(angle)
12031203

12041204
plt.subplots_adjust(left=0.4,right=0.6,top=.99,bottom=.01)
1205+
1206+
1207+
@pytest.mark.parametrize(
1208+
'input, match',
1209+
[
1210+
([1,2,3],'must be list of tuple'),
1211+
([(1,2)],'must be list of tuple'),
1212+
([('en','foo',2)],'start location must be int'),
1213+
([('en',1,'foo')],'end location must be int'),
1214+
],
1215+
)
1216+
deftest_text_language_invalid(input,match):
1217+
withpytest.raises(TypeError,match=match):
1218+
Text(0,0,'foo',language=input)
1219+
1220+
1221+
@image_comparison(baseline_images=['language.png'],remove_text=False,style='mpl20')
1222+
deftest_text_language():
1223+
fig=plt.figure(figsize=(5,3))
1224+
1225+
t=fig.text(0,0.8,'Default',fontsize=32)
1226+
assertt.get_language()isNone
1227+
t=fig.text(0,0.55,'Lang A',fontsize=32)
1228+
assertt.get_language()isNone
1229+
t=fig.text(0,0.3,'Lang B',fontsize=32)
1230+
assertt.get_language()isNone
1231+
t=fig.text(0,0.05,'Mixed',fontsize=32)
1232+
assertt.get_language()isNone
1233+
1234+
# DejaVu Sans supports language-specific glyphs in the Serbian and Macedonian
1235+
# languages in the Cyrillic alphabet.
1236+
cyrillic='\U00000431'
1237+
t=fig.text(0.4,0.8,cyrillic,fontsize=32)
1238+
assertt.get_language()isNone
1239+
t=fig.text(0.4,0.55,cyrillic,fontsize=32,language='sr')
1240+
assertt.get_language()=='sr'
1241+
t=fig.text(0.4,0.3,cyrillic,fontsize=32)
1242+
t.set_language('ru')
1243+
assertt.get_language()=='ru'
1244+
t=fig.text(0.4,0.05,cyrillic*4,fontsize=32,
1245+
language=[('ru',0,1), ('sr',1,2), ('ru',2,3), ('sr',3,4)])
1246+
assertt.get_language()== (('ru',0,1), ('sr',1,2), ('ru',2,3), ('sr',3,4))
1247+
1248+
# Or the Sámi family of languages in the Latin alphabet.
1249+
latin='\U0000014a'
1250+
t=fig.text(0.7,0.8,latin,fontsize=32)
1251+
assertt.get_language()isNone
1252+
withplt.rc_context({'text.language':'en'}):
1253+
t=fig.text(0.7,0.55,latin,fontsize=32)
1254+
assertt.get_language()=='en'
1255+
t=fig.text(0.7,0.3,latin,fontsize=32,language='smn')
1256+
assertt.get_language()=='smn'
1257+
# Tuples are not documented, but we'll allow it.
1258+
t=fig.text(0.7,0.05,latin*4,fontsize=32)
1259+
t.set_language((('en',0,1), ('smn',1,2), ('en',2,3), ('smn',3,4)))
1260+
assertt.get_language()== (
1261+
('en',0,1), ('smn',1,2), ('en',2,3), ('smn',3,4))

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp