Changeset 805
- Timestamp:
- 07/16/15 19:32:53 (10 months ago)
- Location:
- mystic
- Files:
-
- 2 edited
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
mystic/mystic/__init__.py
r776 r805 45 45 import tools 46 46 47 # scripts 48 from scripts import * 49 47 50 # backward compatibility 48 51 from tools import * -
mystic/mystic/scripts.py
r804 r805 1 1 #!/usr/bin/env python 2 2 # 3 # Author: Patrick Hung (patrickh @caltech)3 # Author: Mike McKerns (mmckerns @caltech and @uqfoundation) 4 4 # Author: Jean-Christophe Fillion-Robin (jchris.fillionr @kitware.com) 5 5 # Copyright (c) 1997-2015 California Institute of Technology. 6 6 # License: 3-clause BSD. The full license text is available at: 7 7 # - http://mmckerns.github.io/project/mystic/browser/mystic/LICENSE 8 9 __doc__ = """ 10 mystic_model_plotter.py [options] model (filename) 11 12 generate surface contour plots for model, specified by full import path 13 generate model trajectory from logfile (or solver restart file), if provided 14 15 The option "bounds" takes an indicator string, where the bounds should 16 be given as comma-separated slices. For example, using bounds = "-1:10, 0:20" 17 will set the lower and upper bounds for x to be (-1,10) and y to be (0,20). 18 The "step" can also be given, to control the number of lines plotted in the 19 grid. Thus "-1:10:.1, 0:20" would set the bounds as above, but use increments 20 of .1 along x and the default step along y. For models with > 2D, the bounds 21 can be used to specify 2 dimensions plus fixed values for remaining dimensions. 22 Thus, "-1:10, 0:20, 1.0" would plot the 2D surface where the z-axis was fixed 23 at z=1.0. 24 25 The option "label" takes comma-separated strings. For example, label = "x,y," 26 will place 'x' on the x-axis, 'y' on the y-axis, and nothing on the z-axis. 27 LaTeX is also accepted. For example, label = "$ h $, $ {\\alpha}$, $ v$" will 28 label the axes with standard LaTeX math formatting. Note that the leading 29 space is required, while a trailing space aligns the text with the axis 30 instead of the plot frame. 31 32 The option "reduce" can be given to reduce the output of a model to a scalar, 33 thus converting 'model(params)' to 'reduce(model(params))'. A reducer is given 34 by the import path (e.g. 'numpy.add'). The option "scale" will convert the plot 35 to log-scale, and scale the cost by 'z=log(4*z*scale+1)+2'. This is useful for 36 visualizing small contour changes around the minimium. If using log-scale 37 produces negative numbers, the option "shift" can be used to shift the cost 38 by 'z=z+shift'. Both shift and scale are intended to help visualize contours. 39 40 Required Inputs: 41 model full import path for the model (e.g. mystic.models.rosen) 42 43 Additional Inputs: 44 filename name of the convergence logfile (e.g. log.txt) 8 __doc__ = \ 45 9 """ 10 functional interfaces for mystic's visual analytics scripts 11 """ 12 13 __all__ = ['model_plotter',] 14 46 15 47 16 from mpl_toolkits.mplot3d import axes3d … … 53 22 54 23 #XXX: better if reads single id only? (e.g. same interface as read_history) 55 def get_history(source, ids=None):24 def _get_history(source, ids=None): 56 25 """get params and cost from the given source 57 26 … … 86 55 87 56 88 def get_instance(location, *args, **kwds):57 def _get_instance(location, *args, **kwds): 89 58 """given the import location of a model or model class, return the model 90 59 … … 99 68 100 69 101 def parse_input(option):70 def _parse_input(option): 102 71 """parse 'option' string into 'select', 'axes', and 'mask' 103 72 … … 107 76 108 77 For example, 109 >>> select, axes, mask = parse_input("-1:10:.1, 0.0, 5.0, -50:50:.5")78 >>> select, axes, mask = _parse_input("-1:10:.1, 0.0, 5.0, -50:50:.5") 110 79 >>> select 111 80 [0, 3] … … 129 98 130 99 131 def parse_axes(option, grid=True):100 def _parse_axes(option, grid=True): 132 101 """parse option string into grid axes; using modified numpy.ogrid notation 133 102 … … 176 145 177 146 178 def draw_projection(x, cost, scale=True, shift=False, style=None, figure=None):147 def _draw_projection(x, cost, scale=True, shift=False, style=None, figure=None): 179 148 """draw a solution trajectory (for overlay on a 1D plot) 180 149 … … 206 175 207 176 208 def draw_trajectory(x, y, cost=None, scale=True, shift=False, style=None, figure=None):177 def _draw_trajectory(x, y, cost=None, scale=True, shift=False, style=None, figure=None): 209 178 """draw a solution trajectory (for overlay on a contour plot) 210 179 … … 241 210 242 211 243 def draw_slice(f, x, y=None, scale=True, shift=False):212 def _draw_slice(f, x, y=None, scale=True, shift=False): 244 213 """plot a slice of a 2D function 'f' in 1D 245 214 … … 281 250 282 251 283 def draw_contour(f, x, y=None, surface=False, fill=True, scale=True, shift=False, density=5):252 def _draw_contour(f, x, y=None, surface=False, fill=True, scale=True, shift=False, density=5): 284 253 """draw a contour plot for a given 2D function 'f' 285 254 … … 328 297 329 298 330 def model_plotter(cmdargs=[]): 331 """convenience function providing a function interface to the model 332 plotter. The ``cmdargs`` can either be a :class:`basestring` or 333 a :class:`list`. 334 335 See ``mystic.model_plotter`` module documentation for a complete 336 description of the model plotter and its associated arguments. 337 338 Examples: 339 340 >>> from mystic.model_plotter import model_plotter 341 >>> model_plotter(cmdargs='mystic.models.zimmermann log.txt -b "-5:10:.1, -5:10:.1" -d -x 1') 342 343 or 344 345 >>> from mystic.model_plotter import model_plotter 346 >>> model_plotter(cmdargs=['mystic.models.zimmermann', 'log.txt', '-b', '-5:10:.1, -5:10:.1', '-d', '-x', '1']) 347 348 """ 349 350 if isinstance(cmdargs, basestring): 351 import shlex 352 cmdargs = shlex.split(cmdargs) 353 354 if not isinstance(cmdargs, list): 355 raise Exception("'cmdargs' is expected to either be a list or a string") 356 299 def model_plotter(model, logfile=None, **kwds): 300 """ 301 generate surface contour plots for model, specified by full import path 302 generate model trajectory from logfile (or solver restart file), if provided 303 304 Available from the command shell as: 305 mystic_model_plotter.py model (filename) [options] 306 307 or as a function call as: 308 mystic.model_plotter(model, filename=None, **options) 309 310 The option "bounds" takes an indicator string, where the bounds should 311 be given as comma-separated slices. For example, using bounds = "-1:10, 0:20" 312 will set the lower and upper bounds for x to be (-1,10) and y to be (0,20). 313 The "step" can also be given, to control the number of lines plotted in the 314 grid. Thus "-1:10:.1, 0:20" would set the bounds as above, but use increments 315 of .1 along x and the default step along y. For models with > 2D, the bounds 316 can be used to specify 2 dimensions plus fixed values for remaining dimensions. 317 Thus, "-1:10, 0:20, 1.0" would plot the 2D surface where the z-axis was fixed 318 at z=1.0. When called from a script, slice objects can be used instead of a 319 string, thus "-1:10:.1, 0:20, 1.0" becomes (slice(-1,10,.1), slice(20), 1.0). 320 321 The option "label" takes comma-separated strings. For example, label = "x,y," 322 will place 'x' on the x-axis, 'y' on the y-axis, and nothing on the z-axis. 323 LaTeX is also accepted. For example, label = "$ h $, $ {\\alpha}$, $ v$" will 324 label the axes with standard LaTeX math formatting. Note that the leading 325 space is required, while a trailing space aligns the text with the axis 326 instead of the plot frame. 327 328 The option "reduce" can be given to reduce the output of a model to a scalar, 329 thus converting 'model(params)' to 'reduce(model(params))'. A reducer is given 330 by the import path (e.g. 'numpy.add'). The option "scale" will convert the plot 331 to log-scale, and scale the cost by 'z=log(4*z*scale+1)+2'. This is useful for 332 visualizing small contour changes around the minimium. If using log-scale 333 produces negative numbers, the option "shift" can be used to shift the cost 334 by 'z=z+shift'. Both shift and scale are intended to help visualize contours. 335 336 Required Inputs: 337 model full import path for the model (e.g. mystic.models.rosen) 338 339 Additional Inputs: 340 filename name of the convergence logfile (e.g. log.txt) 341 """ 357 342 #FIXME: should be able to: 358 343 # - apply a constraint as a region of NaN -- apply when 'xx,yy=x[ij],y[ij]' … … 368 353 # - if trajectory outside contour grid, will increase bounds 369 354 # (see support_hypercube.py for how to fix bounds) 355 import shlex 356 _model = None 357 _reducer = None 358 _solver = None 359 360 # handle the special case where list is provided by sys.argv 361 if isinstance(model, (list,tuple)) and not logfile and not kwds: 362 cmdargs = model # (above is used by script to parse command line) 363 elif isinstance(model, basestring) and not logfile and not kwds: 364 cmdargs = shlex.split(model) 365 # 'everything else' is essentially the functional interface 366 else: 367 out = kwds.get('out', None) 368 bounds = kwds.get('bounds', None) 369 label = kwds.get('label', None) 370 nid = kwds.get('nid', None) 371 iter = kwds.get('iter', None) 372 reduce = kwds.get('reduce', None) 373 scale = kwds.get('scale', None) 374 shift = kwds.get('shift', None) 375 fill = kwds.get('fill', False) 376 depth = kwds.get('depth', False) 377 dots = kwds.get('dots', False) 378 join = kwds.get('join', False) 379 380 # special case: bounds passed as list of slices 381 if not isinstance(bounds, (basestring, type(None))): 382 cmdargs = '' 383 for b in bounds: 384 if isinstance(b, slice): 385 cmdargs += "{}:{}:{}, ".format(b.start, b.stop, b.step) 386 else: 387 cmdargs += "{}, ".format(b) 388 bounds = cmdargs[:-2] 389 390 # special case: model passed as model instance 391 #model.__doc__.split('using::')[1].split()[0].strip() 392 if callable(model): _model, model = model, "None" 393 if callable(reduce): _reducer, reduce = reduce, None 394 395 # handle logfile if given 396 if logfile: model += ' ' + logfile 397 398 # process "commandline" arguments 399 cmdargs = '' 400 cmdargs += '' if out is None else '--out={} '.format(out) 401 cmdargs += '' if bounds is None else '--bounds="{}" '.format(bounds) 402 cmdargs += '' if label is None else '--label={} '.format(label) 403 cmdargs += '' if nid is None else '--nid={} '.format(nid) 404 cmdargs += '' if iter is None else '--iter={} '.format(iter) 405 cmdargs += '' if reduce is None else '--reduce={} '.format(reduce) 406 cmdargs += '' if scale is None else '--scale={} '.format(scale) 407 cmdargs += '' if shift is None else '--shift={} '.format(shift) 408 cmdargs += '' if fill == False else '--fill ' 409 cmdargs += '' if depth == False else '--depth ' 410 cmdargs += '' if dots == False else '--dots ' 411 cmdargs += '' if join == False else '--join ' 412 cmdargs = model.split() + shlex.split(cmdargs) 370 413 371 414 #XXX: note that 'argparse' is new as of python2.7 372 415 from optparse import OptionParser 373 parser = OptionParser(usage= __doc__)374 parser.add_option("- p","--plot-filepath",action="store",dest="plot_filepath",\416 parser = OptionParser(usage=model_plotter.__doc__) 417 parser.add_option("-u","--out",action="store",dest="out",\ 375 418 metavar="STR",default=None, 376 help=" save generated plot")419 help="filepath to save generated plot") 377 420 parser.add_option("-b","--bounds",action="store",dest="bounds",\ 378 421 metavar="STR",default="-5:5:.1, -5:5:.1", … … 408 451 # get the import path for the model 409 452 model = parsed_args[0] # e.g. 'mystic.models.rosen' 410 if "None" == model: model = None #XXX: 'required'... allow this?453 if "None" == model: model = None 411 454 412 455 try: # get the name of the parameter log file … … 489 532 490 533 # process inputs 491 select, spec, mask = parse_input(options) 492 x,y = parse_axes(spec, grid=True) # grid=False for 1D plots 534 if _model: model = _model 535 if _reducer: reducer = _reducer 536 if _solver: solver = _solver 537 select, spec, mask = _parse_input(options) 538 x,y = _parse_axes(spec, grid=True) # grid=False for 1D plots 493 539 #FIXME: does grid=False still make sense here...? 494 if reducer: reducer = get_instance(reducer)540 if reducer: reducer = _reducer or _get_instance(reducer) 495 541 if solver and (not source or not model): 496 542 raise RuntimeError('a model and results filename are required') … … 498 544 raise RuntimeError('a model or a results file is required') 499 545 if model: 500 model = get_instance(model)546 model = _model or _get_instance(model) 501 547 # need a reducer if model returns an array 502 548 if reducer: model = reduced(reducer, arraylike=False)(model) … … 505 551 # if 'live'... pick a solver 506 552 solver = 'mystic.solvers.fmin' 507 solver = get_instance(solver)553 solver = _solver or _get_instance(solver) 508 554 xlen = len(select)+len(mask) 509 555 if solver.__name__.startswith('diffev'): … … 533 579 #elif source: v=cost[-1] 534 580 #else: v=None 535 #fig0 = draw_slice(model, x=x, y=v, scale=scale, shift=shift)581 #fig0 = _draw_slice(model, x=x, y=v, scale=scale, shift=shift) 536 582 # plot the surface in 2D or 3D 537 fig = draw_contour(model, x, y, surface=surface, fill=fill, scale=scale, shift=shift)583 fig = _draw_contour(model, x, y, surface=surface, fill=fill, scale=scale, shift=shift) 538 584 else: 539 585 #fig0 = None … … 543 589 # params are the parameter trajectories 544 590 # cost is the solution trajectory 545 params, cost = get_history(source, ids)591 params, cost = _get_history(source, ids) 546 592 if len(cost) > 1: style = style[1:] # 'auto-color' #XXX: or grayscale? 547 593 … … 549 595 ## project trajectory on a 1D slice of model surface #XXX: useful? 550 596 #s = select[0] if len(select) else 0 551 #px = p[int(s)] # draw_projection requires one parameter597 #px = p[int(s)] # _draw_projection requires one parameter 552 598 ## ignore everything after 'stop' 553 599 #_c = eval('c[%s]' % stop) 554 600 #_x = eval('px[%s]' % stop) 555 #fig0 = draw_projection(_x,_c, style=style, scale=scale, shift=shift, figure=fig0)601 #fig0 = _draw_projection(_x,_c, style=style, scale=scale, shift=shift, figure=fig0) 556 602 557 603 # plot the trajectory on the model surface (2D or 3D) 558 604 # get two selected params #XXX: what if len(select)<2? or len(p)<2? 559 605 p = [p[int(i)] for i in select[:2]] 560 px,py = p # draw_trajectory requires two parameters606 px,py = p # _draw_trajectory requires two parameters 561 607 # ignore everything after 'stop' 562 608 _x = eval('px[%s]' % stop) 563 609 _y = eval('py[%s]' % stop) 564 610 _c = eval('c[%s]' % stop) if surface else None 565 fig = draw_trajectory(_x,_y,_c, style=style, scale=scale, shift=shift, figure=fig)611 fig = _draw_trajectory(_x,_y,_c, style=style, scale=scale, shift=shift, figure=fig) 566 612 567 613 # add labels to the axes … … 573 619 if surface: ax.set_zlabel(label[2]) 574 620 575 if not parsed_opts. plot_filepath:621 if not parsed_opts.out: 576 622 plt.show() 577 623 else: 578 fig.savefig(parsed_opts. plot_filepath)624 fig.savefig(parsed_opts.out) 579 625 580 626 -
mystic/scripts/mystic_model_plotter.py
r804 r805 7 7 # - http://mmckerns.github.io/project/mystic/browser/mystic/LICENSE 8 8 9 from mystic .model_plotterimport model_plotter9 from mystic import model_plotter 10 10 11 11 __doc__ = model_plotter.__doc__ … … 14 14 15 15 import sys 16 model_plotter(cmdargs=sys.argv[1:]) 16 17 model_plotter(sys.argv[1:]) 17 18 18 19
Note: See TracChangeset
for help on using the changeset viewer.