@@ -45,6 +45,71 @@ class ColorError(ValueError):
4545 pass
4646
4747
48+ # Recognise pieces of a dimension string.
49+ dimension_pieces = re .compile (r"^\s*(?P<size>\d+(?:\.\d*)?)\s*(?P<unit>.+?)?\s*$" )
50+
51+ # Divisors to convert from a unit to inches.
52+ dimension_divisor = {
53+ "cm" : 2.54 ,
54+ "centimetre" : 2.54 ,
55+ "centimeter" : 2.54 ,
56+ "centimetres" : 2.54 ,
57+ "centimeters" : 2.54 ,
58+ "mm" : 25.4 ,
59+ "millimetre" : 25.4 ,
60+ "millimeter" : 25.4 ,
61+ "millimetres" : 25.4 ,
62+ "millimeters" : 25.4 ,
63+ "in" : 1 ,
64+ "inch" : 1 ,
65+ "inches" : 1 ,
66+ "pt" : 72.27 , # Printers points, not the 1/72 Postscript/PDF points.
67+ "point" : 72.27 ,
68+ "points" : 72.27 ,
69+ }
70+
71+
72+ def parse_dimension (spec : str ) -> float :
73+ """Parse a dimension specification to TeX points.
74+
75+ Matplotlib uses inches for physical sizes. This function allows other units to be
76+ specified and converts them to inches. Note that points are assumed to be TeX points
77+ (72.27 per inch) rather than Postscript points (72 per inch).
78+
79+ Parameters
80+ ----------
81+ spec
82+ A dimension specification. This should be in the format "<value><unit>" where
83+ the unit can be any of the keys from the `dimension_divisor` dictionary.
84+ Whitespace is allowed between the value and unit. If no unit is given, it is
85+ assumed to be inches.
86+
87+ Returns
88+ -------
89+ float
90+ The dimension in inches.
91+
92+ """
93+ match = dimension_pieces .match (spec )
94+ if not match :
95+ raise DimensionError (f"could not parse { spec } as a dimension" )
96+
97+ # Get the components.
98+ groups = match .groupdict ()
99+ size = float (groups ["size" ])
100+ unit : str = (groups .get ("unit" ) or "" ).lower ()
101+
102+ # Assume already in inches.
103+ if not unit :
104+ return size
105+
106+ # Convert with the divisor.
107+ factor = dimension_divisor .get (unit )
108+ if factor is None :
109+ raise DimensionError (f"unknown unit in { spec } " )
110+ return size / factor
111+
112+
48113class PgfutilsParser (configparser .ConfigParser ):
49114 """Custom configuration parser with Matplotlib dimension and color support."""
50115
@@ -136,63 +201,6 @@ def read_kwargs(self, **kwargs):
136201 # And then read the dictionary in.
137202 return self .read_dict (d )
138203
139- def parsedimension (self , dim ):
140- """Convert a dimension to inches.
141-
142- The dimension should be in the format '<value><unit>', where the unit can be
143- 'mm', 'cm', 'in', or 'pt'. If no unit is specified, it is assumed to be in
144- inches. Note that points refer to TeX points (72.27 per inch) rather than
145- Postscript points (72 per inch).
146-
147- Parameters
148- ----------
149- dim: string
150- The dimension to parse.
151-
152- Returns
153- -------
154- float: The dimension in inches.
155-
156- Raises
157- ------
158- DimensionError:
159- The dimension is empty or not recognised.
160-
161- """
162- # Need a string.
163- if dim is None :
164- raise DimensionError ("Cannot be set to an empty value." )
165-
166- # Check for an empty string.
167- dim = dim .strip ().lower ()
168- if not dim :
169- raise DimensionError ("Cannot be set to an empty value." )
170-
171- # Try to parse it.
172- m = self ._dimre .match (dim )
173- if not m :
174- raise DimensionError (f"Could not parse { dim } as a dimension." )
175-
176- # Pull out the pieces.
177- groups = m .groupdict ()
178- size = float (groups ["size" ])
179- unit = groups .get ("unit" , "" ) or ""
180- unit = unit .lower ()
181-
182- # No unit: already in inches.
183- if not unit :
184- return size
185-
186- # Pick out the divisor to convert into inches.
187- factor = self ._dimconv .get (unit , None )
188-
189- # Unknown unit.
190- if factor is None :
191- raise DimensionError (f"Unknown unit { unit } ." )
192-
193- # Do the conversion.
194- return size / factor
195-
196204 def getdimension (self , section , option , ** kwargs ):
197205 """Return a configuration entry as a dimension in inches.
198206
@@ -222,7 +230,7 @@ def getdimension(self, section, option, **kwargs):
222230 # And parse it; modify any parsing exception to include
223231 # the section and option we were parsing.
224232 try :
225- return self . parsedimension (dim )
233+ return parse_dimension (dim )
226234 except DimensionError as e :
227235 raise DimensionError (f"{ section } .{ option } : { e } " ) from None
228236
@@ -848,15 +856,15 @@ def setup_figure(
848856 try :
849857 w = float (width )
850858 except ValueError :
851- w = _config . parsedimension (width )
859+ w = parse_dimension (width )
852860 else :
853861 w *= available_width
854862
855863 # And the figure height.
856864 try :
857865 h = float (height )
858866 except ValueError :
859- h = _config . parsedimension (height )
867+ h = parse_dimension (height )
860868 else :
861869 h *= _config ["tex" ].getdimension ("text_height" )
862870
0 commit comments