|
| 1 | +import os |
| 2 | + |
| 3 | +class ValidateInStrings: |
| 4 | + def __init__(self, key, valid, ignorecase=False): |
| 5 | + 'valid is a list of legal strings' |
| 6 | + self.key = key |
| 7 | + self.ignorecase = ignorecase |
| 8 | + def func(s): |
| 9 | + if ignorecase: return s.lower() |
| 10 | + else: return s |
| 11 | + self.valid = dict([(func(k),k) for k in valid]) |
| 12 | + |
| 13 | + def __call__(self, s): |
| 14 | + if self.ignorecase: s = s.lower() |
| 15 | + if s in self.valid: return self.valid[s] |
| 16 | + raise ValueError('Unrecognized %s string "%s": valid strings are %s'%(self.key, s, self.valid.values())) |
| 17 | + |
| 18 | +def validate_path_exists(s): |
| 19 | + 'If s is a path, return s, else False' |
| 20 | + if os.path.exists(s): return s |
| 21 | + else: |
| 22 | + raise RuntimeError('"%s" should be a path but it does not exist'%s) |
| 23 | + |
| 24 | +def validate_bool(b): |
| 25 | + 'Convert b to a boolean or raise' |
| 26 | + bl = b.lower() |
| 27 | + if bl in ('f', 'no', 'false', '0', 0): return False |
| 28 | + elif bl in ('t', 'yes', 'true', '1', 1): return True |
| 29 | + else: |
| 30 | + raise ValueError('Could not convert "%s" to boolean' % b) |
| 31 | + |
| 32 | +def validate_float(s): |
| 33 | + 'convert s to float or raise' |
| 34 | + try: return float(s) |
| 35 | + except ValueError: |
| 36 | + raise ValueError('Could not convert "%s" to float' % s) |
| 37 | + |
| 38 | +def validate_int(s): |
| 39 | + 'convert s to int or raise' |
| 40 | + try: return int(s) |
| 41 | + except ValueError: |
| 42 | + raise ValueError('Could not convert "%s" to int' % s) |
| 43 | + |
| 44 | +validate_backend = ValidateInStrings('backend',[ |
| 45 | + 'Agg2', 'Agg', 'Aqt', 'Cairo', 'CocoaAgg', 'EMF', 'GD', 'GDK', |
| 46 | + 'GTK', 'GTKAgg', 'GTKCairo', 'FltkAgg', 'Paint', 'Pdf', 'PS', |
| 47 | + 'QtAgg', 'Qt4Agg', 'SVG', 'Template', 'TkAgg', 'WX', 'WXAgg', |
| 48 | + ], ignorecase=True) |
| 49 | + |
| 50 | +validate_numerix = ValidateInStrings('numerix',[ |
| 51 | + 'Numeric','numarray','numpy', |
| 52 | + ], ignorecase=True) |
| 53 | + |
| 54 | +validate_toolbar = ValidateInStrings('toolbar',[ |
| 55 | + 'None','classic','toolbar2', |
| 56 | + ], ignorecase=True) |
| 57 | + |
| 58 | +class validate_nseq_float: |
| 59 | + def __init__(self, n): |
| 60 | + self.n = n |
| 61 | + def __call__(self, s): |
| 62 | + 'return a seq of n floats or raise' |
| 63 | + ss = s.split(',') |
| 64 | + if len(ss) != self.n: |
| 65 | + raise ValueError('You must use exactly %d comma separated values'%self.n) |
| 66 | + try: return [float(val) for val in ss] |
| 67 | + except ValueError: |
| 68 | + raise ValueError('Could not convert all entries to floats') |
| 69 | + |
| 70 | +class validate_nseq_int: |
| 71 | + def __init__(self, n): |
| 72 | + self.n = n |
| 73 | + def __call__(self, s): |
| 74 | + 'return a seq of n ints or raise' |
| 75 | + ss = s.split(',') |
| 76 | + if len(ss) != self.n: |
| 77 | + raise ValueError('You must use exactly %d comma separated values'%self.n) |
| 78 | + try: return [int(val) for val in ss] |
| 79 | + except ValueError: |
| 80 | + raise ValueError('Could not convert all entries to ints') |
| 81 | + |
| 82 | + |
| 83 | +def validate_color(s): |
| 84 | + 'return a valid color arg' |
| 85 | + if s.lower() == 'none': return 'None' |
| 86 | + if len(s)==1 and s.isalpha(): return s |
| 87 | + if s.find(',')>=0: # looks like an rgb |
| 88 | + # get rid of grouping symbols |
| 89 | + s = ''.join([ c for c in s if c.isdigit() or c=='.' or c==',']) |
| 90 | + vals = s.split(',') |
| 91 | + if len(vals)!=3: |
| 92 | + raise ValueError('Color tuples must be length 3') |
| 93 | + |
| 94 | + try: return [float(val) for val in vals] |
| 95 | + except ValueError: |
| 96 | + raise ValueError('Could not convert all entries "%s" to floats'%s) |
| 97 | + |
| 98 | + if s.replace('.', '').isdigit(): # looks like scalar (grayscale) |
| 99 | + return s |
| 100 | + |
| 101 | + if len(s)==6 and s.isalnum(): # looks like hex |
| 102 | + return '#' + s |
| 103 | + |
| 104 | + if s.isalpha(): |
| 105 | + #assuming a color name, hold on |
| 106 | + return s |
| 107 | + |
| 108 | + raise ValueError('"s" does not look like color arg') |
| 109 | + |
| 110 | +def validate_comma_sep_str(s): |
| 111 | + 'return a list' |
| 112 | + ss = s.split(',') |
| 113 | + try: |
| 114 | + return [val.strip() for val in ss] |
| 115 | + except ValueError: |
| 116 | + raise ValueError('Could not convert all entries to strings') |
| 117 | + |
| 118 | +validate_orientation = ValidateInStrings('orientation',[ |
| 119 | + 'landscape', 'portrait', |
| 120 | + ]) |
| 121 | + |
| 122 | +def validate_latex_preamble(s): |
| 123 | + 'return a list' |
| 124 | + preamble_list = validate_comma_sep_str(s) |
| 125 | + if not preamble_list == ['']: |
| 126 | + verbose.report(""" |
| 127 | +***************************************************************** |
| 128 | +You have the following UNSUPPORTED LaTeX preamble customizations: |
| 129 | +%s |
| 130 | +Please do not ask for support with these customizations active. |
| 131 | +***************************************************************** |
| 132 | +"""% '\n'.join(preamble_list), 'helpful') |
| 133 | + return preamble_list |
| 134 | + |
| 135 | + |
| 136 | + |
| 137 | +def validate_aspect(s): |
| 138 | + if s in ('auto', 'equal'): |
| 139 | + return s |
| 140 | + try: |
| 141 | + return float(s) |
| 142 | + except ValueError: |
| 143 | + raise ValueError('not a valid aspect specification') |
| 144 | + |
| 145 | +def validate_fontsize(s): |
| 146 | + if s.lower() in ['xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', |
| 147 | + 'xx-large', 'smaller', 'larger']: |
| 148 | + return s.lower() |
| 149 | + try: |
| 150 | + return float(s) |
| 151 | + except ValueError: |
| 152 | + raise ValueError('not a valid font size') |
| 153 | + |
| 154 | +validate_verbose = ValidateInStrings('verbose',[ |
| 155 | + 'silent', 'helpful', 'debug', 'debug-annoying', |
| 156 | + ]) |
| 157 | + |
| 158 | +validate_ps_papersize = ValidateInStrings('ps_papersize',[ |
| 159 | + 'auto', 'letter', 'legal', 'ledger', |
| 160 | + 'a0', 'a1', 'a2','a3', 'a4', 'a5', 'a6', 'a7', 'a8', 'a9', 'a10', |
| 161 | + 'b0', 'b1', 'b2', 'b3', 'b4', 'b5', 'b6', 'b7', 'b8', 'b9', 'b10', |
| 162 | + ], ignorecase=True) |
| 163 | + |
| 164 | +def validate_ps_distiller(s): |
| 165 | + s = s.lower() |
| 166 | + |
| 167 | + if s == 'none': |
| 168 | + return None |
| 169 | + elif s == 'false': |
| 170 | + return False |
| 171 | + elif s in ('ghostscript', 'xpdf'): |
| 172 | + return s |
| 173 | + else: |
| 174 | + raise ValueError('matplotlibrc ps.usedistiller must either be none, ghostscript or xpdf') |
| 175 | + |
| 176 | +validate_joinstyle = ValidateInStrings('joinstyle',['miter', 'round', 'bevel'], ignorecase=True) |
| 177 | + |
| 178 | +validate_capstyle = ValidateInStrings('capstyle',['butt', 'round', 'projecting'], ignorecase=True) |
| 179 | + |
| 180 | +def validate_linecol_linestyle(s): |
| 181 | + try: |
| 182 | + dashes = validate_nseq_float(2)(s) |
| 183 | + warnings.warn("Deprecated negative_linestyle specification; use 'solid' or 'dashed'") |
| 184 | + return (0, dashes) # (offset, (solid, blank)) |
| 185 | + except ValueError: |
| 186 | + V = ValidateInStrings('linecol_linestyle',['solid', 'dashed'], ignorecase=True) |
| 187 | + return(V(s)) |
| 188 | + |
| 189 | +class ValidateInterval: |
| 190 | + """ |
| 191 | + Value must be in interval |
| 192 | + """ |
| 193 | + def __init__(self, vmin, vmax, closedmin=True, closedmax=True): |
| 194 | + self.vmin = vmin |
| 195 | + self.vmax = vmax |
| 196 | + self.cmin = closedmin |
| 197 | + self.cmax = closedmax |
| 198 | + |
| 199 | + def __call__(self, s): |
| 200 | + try: s = float(s) |
| 201 | + except: raise RuntimeError('Value must be a float; found "%s"'%s) |
| 202 | + |
| 203 | + if self.cmin and s<self.vmin: |
| 204 | + raise RuntimeError('Value must be >= %f; found "%f"'%(self.vmin, s)) |
| 205 | + elif not self.cmin and s<=self.vmin: |
| 206 | + raise RuntimeError('Value must be > %f; found "%f"'%(self.vmin, s)) |
| 207 | + |
| 208 | + if self.cmax and s>self.vmax: |
| 209 | + raise RuntimeError('Value must be <= %f; found "%f"'%(self.vmax, s)) |
| 210 | + elif not self.cmax and s>=self.vmax: |
| 211 | + raise RuntimeError('Value must be < %f; found "%f"'%(self.vmax, s)) |
| 212 | + return s |
| 213 | + |
| 214 | + |
| 215 | + |
| 216 | +# a map from key -> value, converter |
| 217 | +defaultParams = { |
| 218 | + 'backend' : ['WXAgg', validate_backend], |
| 219 | + 'numerix' : ['numpy', validate_numerix], |
| 220 | + 'maskedarray' : [False, validate_bool], |
| 221 | + 'toolbar' : ['toolbar2', validate_toolbar], |
| 222 | + 'datapath' : [None, validate_path_exists], # handled by _get_data_path_cached |
| 223 | + 'units' : [False, validate_bool], |
| 224 | + 'interactive' : [False, validate_bool], |
| 225 | + 'timezone' : ['UTC', str], |
| 226 | + |
| 227 | + # the verbosity setting |
| 228 | + 'verbose.level' : ['silent', validate_verbose], |
| 229 | + 'verbose.fileo' : ['sys.stdout', str], |
| 230 | + |
| 231 | + # line props |
| 232 | + 'lines.linewidth' : [1.0, validate_float], # line width in points |
| 233 | + 'lines.linestyle' : ['-', str], # solid line |
| 234 | + 'lines.color' : ['b', validate_color], # blue |
| 235 | + 'lines.marker' : ['None', str], # black |
| 236 | + 'lines.markeredgewidth' : [0.5, validate_float], |
| 237 | + 'lines.markersize' : [6, validate_float], # markersize, in points |
| 238 | + 'lines.antialiased' : [True, validate_bool], # antialised (no jaggies) |
| 239 | + 'lines.dash_joinstyle' : ['miter', validate_joinstyle], |
| 240 | + 'lines.solid_joinstyle' : ['miter', validate_joinstyle], |
| 241 | + 'lines.dash_capstyle' : ['butt', validate_capstyle], |
| 242 | + 'lines.solid_capstyle' : ['projecting', validate_capstyle], |
| 243 | + |
| 244 | + # patch props |
| 245 | + 'patch.linewidth' : [1.0, validate_float], # line width in points |
| 246 | + 'patch.edgecolor' : ['k', validate_color], # black |
| 247 | + 'patch.facecolor' : ['b', validate_color], # blue |
| 248 | + 'patch.antialiased' : [True, validate_bool], # antialised (no jaggies) |
| 249 | + |
| 250 | + |
| 251 | + # font props |
| 252 | + 'font.family' : ['serif', str], # used by text object |
| 253 | + 'font.style' : ['normal', str], # |
| 254 | + 'font.variant' : ['normal', str], # |
| 255 | + 'font.stretch' : ['normal', str], # |
| 256 | + 'font.weight' : ['normal', str], # |
| 257 | + 'font.size' : [12.0, validate_float], # |
| 258 | + 'font.serif' : ['Bitstream Vera Serif, New Century Schoolbook, Century Schoolbook L, Utopia, ITC Bookman, Bookman, Nimbus Roman No9 L, Times New Roman, Times, Palatino, Charter, serif', validate_comma_sep_str], |
| 259 | + 'font.sans-serif' : ['Bitstream Vera Sans, Lucida Grande, Verdana, Geneva, Lucid, Arial, Helvetica, Avant Garde, sans-serif', validate_comma_sep_str], |
| 260 | + 'font.cursive' : ['Apple Chancery, Textile, Zapf Chancery, Sand, cursive', validate_comma_sep_str], |
| 261 | + 'font.fantasy' : ['Comic Sans MS, Chicago, Charcoal, Impact, Western, fantasy', validate_comma_sep_str], |
| 262 | + 'font.monospace' : ['Bitstream Vera Sans Mono, Andale Mono, Nimbus Mono L, Courier New, Courier, Fixed, Terminal, monospace', validate_comma_sep_str], |
| 263 | + |
| 264 | + # text props |
| 265 | + 'text.color' : ['k', validate_color], # black |
| 266 | + 'text.usetex' : [False, validate_bool], |
| 267 | + 'text.latex.unicode': [False, validate_bool], |
| 268 | + 'text.latex.preamble': ['', validate_latex_preamble], |
| 269 | + 'text.dvipnghack' : [False, validate_bool], |
| 270 | + 'text.fontstyle' : ['normal', str], |
| 271 | + 'text.fontangle' : ['normal', str], |
| 272 | + 'text.fontvariant' : ['normal', str], |
| 273 | + 'text.fontweight' : ['normal', str], |
| 274 | + 'text.fontsize' : ['medium', validate_fontsize], |
| 275 | + |
| 276 | + |
| 277 | + 'image.aspect' : ['equal', validate_aspect], # equal, auto, a number |
| 278 | + 'image.interpolation' : ['bilinear', str], |
| 279 | + 'image.cmap' : ['jet', str], # one of gray, jet, etc |
| 280 | + 'image.lut' : [256, validate_int], # lookup table |
| 281 | + 'image.origin' : ['upper', str], # lookup table |
| 282 | + |
| 283 | + 'contour.negative_linestyle' : ['dashed', validate_linecol_linestyle], |
| 284 | + |
| 285 | + # axes props |
| 286 | + 'axes.axisbelow' : [False, validate_bool], |
| 287 | + 'axes.hold' : [True, validate_bool], |
| 288 | + 'axes.facecolor' : ['w', validate_color], # background color; white |
| 289 | + 'axes.edgecolor' : ['k', validate_color], # edge color; black |
| 290 | + 'axes.linewidth' : [1.0, validate_float], # edge linewidth |
| 291 | + 'axes.titlesize' : [14, validate_fontsize], # fontsize of the axes title |
| 292 | + 'axes.grid' : [False, validate_bool], # display grid or not |
| 293 | + 'axes.labelsize' : [12, validate_fontsize], # fontsize of the x any y labels |
| 294 | + 'axes.labelcolor' : ['k', validate_color], # color of axis label |
| 295 | + 'axes.formatter.limits' : [(-7, 7), validate_nseq_int(2)], |
| 296 | + # use scientific notation if log10 |
| 297 | + # of the axis range is smaller than the |
| 298 | + # first or larger than the second |
| 299 | + |
| 300 | + |
| 301 | + 'polaraxes.grid' : [True, validate_bool], # display polar grid or not |
| 302 | + |
| 303 | + #legend properties |
| 304 | + 'legend.isaxes' : [True,validate_bool], |
| 305 | + 'legend.numpoints' : [ 2,validate_int], # the number of points in the legend line |
| 306 | + 'legend.fontsize' : [14,validate_fontsize], |
| 307 | + 'legend.pad' : [ 0.2, validate_float], # the fractional whitespace inside the legend border |
| 308 | + 'legend.markerscale' : [ 1.0, validate_float], # the relative size of legend markers vs. original |
| 309 | + |
| 310 | + # the following dimensions are in axes coords |
| 311 | + 'legend.labelsep' : [ 0.010, validate_float], # the vertical space between the legend entries |
| 312 | + 'legend.handlelen' : [ 0.05, validate_float], # the length of the legend lines |
| 313 | + 'legend.handletextsep' : [ 0.02, validate_float], # the space between the legend line and legend text |
| 314 | + 'legend.axespad' : [ 0.02, validate_float], # the border between the axes and legend edge |
| 315 | + 'legend.shadow' : [ False, validate_bool ], |
| 316 | + |
| 317 | + |
| 318 | + # tick properties |
| 319 | + 'xtick.major.size' : [4, validate_float], # major xtick size in points |
| 320 | + 'xtick.minor.size' : [2, validate_float], # minor xtick size in points |
| 321 | + 'xtick.major.pad' : [4, validate_float], # distance to label in points |
| 322 | + 'xtick.minor.pad' : [4, validate_float], # distance to label in points |
| 323 | + 'xtick.color' : ['k', validate_color], # color of the xtick labels |
| 324 | + 'xtick.labelsize' : [12, validate_fontsize], # fontsize of the xtick labels |
| 325 | + 'xtick.direction' : ['in', str], # direction of xticks |
| 326 | + |
| 327 | + 'ytick.major.size' : [4, validate_float], # major ytick size in points |
| 328 | + 'ytick.minor.size' : [2, validate_float], # minor ytick size in points |
| 329 | + 'ytick.major.pad' : [4, validate_float], # distance to label in points |
| 330 | + 'ytick.minor.pad' : [4, validate_float], # distance to label in points |
| 331 | + 'ytick.color' : ['k', validate_color], # color of the ytick labels |
| 332 | + 'ytick.labelsize' : [12, validate_fontsize], # fontsize of the ytick labels |
| 333 | + 'ytick.direction' : ['in', str], # direction of yticks |
| 334 | + |
| 335 | + 'grid.color' : ['k', validate_color], # grid color |
| 336 | + 'grid.linestyle' : [':', str], # dotted |
| 337 | + 'grid.linewidth' : [0.5, validate_float], # in points |
| 338 | + |
| 339 | + |
| 340 | + # figure props |
| 341 | + # figure size in inches: width by height |
| 342 | + 'figure.figsize' : [ (8,6), validate_nseq_float(2)], |
| 343 | + 'figure.dpi' : [ 80, validate_float], # DPI |
| 344 | + 'figure.facecolor' : [ '0.75', validate_color], # facecolor; scalar gray |
| 345 | + 'figure.edgecolor' : [ 'w', validate_color], # edgecolor; white |
| 346 | + |
| 347 | + 'figure.subplot.left' : [0.125, ValidateInterval(0, 1, closedmin=False, closedmax=False)], |
| 348 | + 'figure.subplot.right' : [0.9, ValidateInterval(0, 1, closedmin=False, closedmax=False)], |
| 349 | + 'figure.subplot.bottom' : [0.1, ValidateInterval(0, 1, closedmin=False, closedmax=False)], |
| 350 | + 'figure.subplot.top' : [0.9, ValidateInterval(0, 1, closedmin=False, closedmax=False)], |
| 351 | + 'figure.subplot.wspace' : [0.2, ValidateInterval(0, 1, closedmin=False, closedmax=True)], |
| 352 | + 'figure.subplot.hspace' : [0.2, ValidateInterval(0, 1, closedmin=False, closedmax=True)], |
| 353 | + |
| 354 | + |
| 355 | + 'savefig.dpi' : [ 100, validate_float], # DPI |
| 356 | + 'savefig.facecolor' : [ 'w', validate_color], # facecolor; white |
| 357 | + 'savefig.edgecolor' : [ 'w', validate_color], # edgecolor; white |
| 358 | + 'savefig.orientation' : [ 'portait', validate_orientation], # edgecolor; white |
| 359 | + |
| 360 | + 'tk.window_focus' : [ False, validate_bool], # Maintain shell focus for TkAgg |
| 361 | + 'tk.pythoninspect' : [ False, validate_bool], # Set PYTHONINSPECT |
| 362 | + 'ps.papersize' : [ 'letter', validate_ps_papersize], # Set the papersize/type |
| 363 | + 'ps.useafm' : [ False, validate_bool], # Set PYTHONINSPECT |
| 364 | + 'ps.usedistiller' : [ False, validate_ps_distiller], # use ghostscript or xpdf to distill ps output |
| 365 | + 'ps.distiller.res' : [6000, validate_int], # dpi |
| 366 | + 'pdf.compression' : [6, validate_int], # compression level from 0 to 9; 0 to disable |
| 367 | + 'pdf.inheritcolor' : [False, validate_bool], # ignore any color-setting commands from the frontend |
| 368 | + 'pdf.use14corefonts' : [False, validate_bool], # use only the 14 PDF core fonts, embedded in every PDF viewing application |
| 369 | + 'svg.image_inline' : [True, validate_bool], # write raster image data directly into the svg file |
| 370 | + 'svg.image_noscale' : [False, validate_bool], # suppress scaling of raster data embedded in SVG |
| 371 | + 'plugins.directory' : ['.matplotlib_plugins', str], # where plugin directory is locate |
| 372 | + |
| 373 | + # mathtext settings |
| 374 | + 'mathtext.mathtext2' : [False, validate_bool], # Needed to enable Unicode |
| 375 | + # fonts used by mathtext. These ship with matplotlib |
| 376 | + 'mathtext.rm' : ['cmr10.ttf', str], # Roman (normal) |
| 377 | + 'mathtext.it' : ['cmmi10.ttf', str], # Italic |
| 378 | + 'mathtext.tt' : ['cmtt10.ttf', str], # Typewriter (monospaced) |
| 379 | + 'mathtext.mit' : ['cmmi10.ttf', str], # Math italic |
| 380 | + 'mathtext.cal' : ['cmsy10.ttf', str], # Caligraphic |
| 381 | + 'mathtext.nonascii' : ['cmex10.ttf', str], # All other nonascii fonts |
| 382 | + |
| 383 | + } |
0 commit comments