@@ -1209,65 +1209,10 @@ class Text(PrimitiveObject):
12091209 center = (float (0 ), float (0 ), float (0 ))
12101210 if render_params.transform is not None :
12111211 center = render_params.transform.transform_point(center)
1212-
12131212 color = ' #' + str (self .texture.hex_rgb())
12141213 string = str (self .string)
1215-
1216- default_size = 14.0
1217- size = self ._extra_kwds.get(' fontsize' , default_size)
1218- try :
1219- size = float (size)
1220- except (TypeError , ValueError ):
1221- scale = str (size).lower()
1222- if scale.endswith(' %' ):
1223- try :
1224- scale = float (scale[:- 1 ]) / 100.0
1225- size = default_size * scale
1226- except ValueError :
1227- import warnings
1228- warnings.warn(f" invalid fontsize: {size}, using: {default_size}" )
1229- size = default_size
1230- else :
1231- from matplotlib.font_manager import font_scalings
1232- try :
1233- size = default_size * font_scalings[scale]
1234- except KeyError :
1235- import warnings
1236- warnings.warn(f" unknown fontsize: {size}, using: {default_size}" )
1237- size = default_size
1238-
1239- font = self ._extra_kwds.get(' fontfamily' , [' monospace' ])
1240- if isinstance (font, str ):
1241- font = font.split(' ,' )
1242- font = [str (f).strip() for f in font]
1243-
1244- default_style = ' normal'
1245- style = str (self ._extra_kwds.get(' fontstyle' , default_style))
1246- if style not in [' normal' , ' italic' ] and not style.startswith(' oblique' ): # ex: oblique 30deg
1247- import warnings
1248- warnings.warn(f" unknown style: {style}, using: {default_style}" )
1249- style = default_style
1250-
1251- default_weight = ' normal'
1252- weight = self ._extra_kwds.get(' fontweight' , default_weight)
1253- if weight not in [' normal' , ' bold' ]:
1254- try :
1255- weight = int (weight)
1256- except :
1257- from matplotlib.font_manager import weight_dict
1258- try :
1259- weight = weight_dict[weight]
1260- except KeyError :
1261- import warnings
1262- warnings.warn(f" unknown fontweight: {weight}, using: {default_weight}" )
1263- weight = default_weight
1264-
1265- opacity = float (self ._extra_kwds.get(' opacity' , 1.0 ))
1266-
1267- text = dict (text = string, x = center[0 ], y = center[1 ], z = center[2 ], color = color,
1268- fontSize = size, fontFamily = font, fontStyle = style, fontWeight = weight,
1269- opacity = opacity)
1270-
1214+ text = _validate_threejs_text_style(self ._extra_kwds)
1215+ text.update(dict (text = string, x = center[0 ], y = center[1 ], z = center[2 ], color = color))
12711216 return [(' text' , text)]
12721217
12731218 def bounding_box (self ):
@@ -1279,3 +1224,152 @@ class Text(PrimitiveObject):
12791224 ((0, 0, 0), (0, 0, 0))
12801225 """
12811226 return (0 ,0 ,0 ), (0 ,0 ,0 )
1227+
1228+
1229+ def _validate_threejs_text_style (style ):
1230+ """
1231+ Validate a combination of text styles for use in the Three.js viewer.
1232+
1233+ INPUT:
1234+
1235+ - ``style`` -- a dict optionally containing keys: 'color', 'fontSize',
1236+ 'fontFamily', 'fontStyle', 'fontWeight', and 'opacity'
1237+
1238+ OUTPUT:
1239+
1240+ A corrected version of the dict, having printed out warning messages for
1241+ any problems found
1242+
1243+ TESTS:
1244+
1245+ Default values::
1246+
1247+ sage: from sage.plot.plot3d.shapes import _validate_threejs_text_style as validate
1248+ sage: validate(dict())
1249+ {'color': '#000000',
1250+ 'fontFamily': ['monospace'],
1251+ 'fontSize': 14.0,
1252+ 'fontStyle': 'normal',
1253+ 'fontWeight': 'normal',
1254+ 'opacity': 1.0}
1255+
1256+ Color by name or by HTML hex code::
1257+
1258+ sage: validate(dict(color='red'))
1259+ {'color': '#ff0000',...}
1260+ sage: validate(dict(color='#ff0000'))
1261+ {'color': '#ff0000',...}
1262+ sage: validate(dict(color='octarine'))
1263+ ...UserWarning: invalid color: octarine...
1264+
1265+ Font size in absolute units or in percentage/keyword relative to default::
1266+
1267+ sage: validate(dict(fontsize=20.5))
1268+ {...'fontSize': 20.5...}
1269+ sage: validate(dict(fontsize="200%"))
1270+ {...'fontSize': 28...}
1271+ sage: validate(dict(fontsize="x%"))
1272+ ...UserWarning: invalid fontsize: x%...
1273+ sage: validate(dict(fontsize="large"))
1274+ {...'fontSize': 16.8...}
1275+ sage: validate(dict(fontsize="ginormous"))
1276+ ...UserWarning: unknown fontsize: ginormous...
1277+
1278+ Font family as list or comma-delimited string::
1279+
1280+ sage: validate(dict(fontfamily=[" Times New Roman ", " Georgia", "serif "]))
1281+ {...'fontFamily': ['Times New Roman', 'Georgia', 'serif']...}
1282+ sage: validate(dict(fontfamily=" Times New Roman , Georgia,serif "))
1283+ {...'fontFamily': ['Times New Roman', 'Georgia', 'serif']...}
1284+
1285+ Font style keywords including the special syntax for 'oblique' angle::
1286+
1287+ sage: validate(dict(fontstyle='italic'))
1288+ {...'fontStyle': 'italic'...}
1289+ sage: validate(dict(fontstyle='oblique 30deg'))
1290+ {...'fontStyle': 'oblique 30deg'...}
1291+ sage: validate(dict(fontstyle='garrish'))
1292+ ...UserWarning: unknown style: garrish...
1293+
1294+ Font weight as keyword or integer::
1295+
1296+ sage: validate(dict(fontweight='bold'))
1297+ {...'fontWeight': 'bold'...}
1298+ sage: validate(dict(fontweight=500))
1299+ {...'fontWeight': 500...}
1300+ sage: validate(dict(fontweight='roman'))
1301+ {...'fontWeight': 500...}
1302+ sage: validate(dict(fontweight='bold & beautiful'))
1303+ ...UserWarning: unknown fontweight: bold & beautiful...
1304+
1305+ Opacity::
1306+
1307+ sage: validate(dict(opacity=0.5))
1308+ {...'opacity': 0.5}
1309+
1310+ """
1311+ default_color = ' #000000' # black
1312+ color = style.get(' color' , default_color)
1313+ from .texture import Texture
1314+ try :
1315+ texture = Texture(color = color)
1316+ except ValueError :
1317+ import warnings
1318+ warnings.warn(f" invalid color: {color}, using: {default_color}" )
1319+ color = default_color
1320+ else :
1321+ color = ' #' + str (texture.hex_rgb())
1322+
1323+ default_size = 14.0
1324+ size = style.get(' fontsize' , default_size)
1325+ try :
1326+ size = float (size)
1327+ except (TypeError , ValueError ):
1328+ scale = str (size).lower()
1329+ if scale.endswith(' %' ):
1330+ try :
1331+ scale = float (scale[:- 1 ]) / 100.0
1332+ size = default_size * scale
1333+ except ValueError :
1334+ import warnings
1335+ warnings.warn(f" invalid fontsize: {size}, using: {default_size}" )
1336+ size = default_size
1337+ else :
1338+ from matplotlib.font_manager import font_scalings
1339+ try :
1340+ size = default_size * font_scalings[scale]
1341+ except KeyError :
1342+ import warnings
1343+ warnings.warn(f" unknown fontsize: {size}, using: {default_size}" )
1344+ size = default_size
1345+
1346+ font = style.get(' fontfamily' , [' monospace' ])
1347+ if isinstance (font, str ):
1348+ font = font.split(' ,' )
1349+ font = [str (f).strip() for f in font]
1350+
1351+ default_style = ' normal'
1352+ fontstyle = str (style.get(' fontstyle' , default_style))
1353+ if fontstyle not in [' normal' , ' italic' ] and not fontstyle.startswith(' oblique' ): # ex: oblique 30deg
1354+ import warnings
1355+ warnings.warn(f" unknown style: {fontstyle}, using: {default_style}" )
1356+ fontstyle = default_style
1357+
1358+ default_weight = ' normal'
1359+ weight = style.get(' fontweight' , default_weight)
1360+ if weight not in [' normal' , ' bold' ]:
1361+ try :
1362+ weight = int (weight)
1363+ except :
1364+ from matplotlib.font_manager import weight_dict
1365+ try :
1366+ weight = weight_dict[weight]
1367+ except KeyError :
1368+ import warnings
1369+ warnings.warn(f" unknown fontweight: {weight}, using: {default_weight}" )
1370+ weight = default_weight
1371+
1372+ opacity = float (style.get(' opacity' , 1.0 ))
1373+
1374+ return dict (color = color, fontSize = size, fontFamily = font, fontStyle = fontstyle,
1375+ fontWeight = weight, opacity = opacity)
0 commit comments