Changeset 805


Ignore:
Timestamp:
07/16/15 19:32:53 (10 months ago)
Author:
mmckerns
Message:

made model_plotter function more function-like

Location:
mystic
Files:
2 edited
1 moved

Legend:

Unmodified
Added
Removed
  • mystic/mystic/__init__.py

    r776 r805  
    4545import tools 
    4646 
     47# scripts 
     48from scripts import * 
     49 
    4750# backward compatibility 
    4851from tools import * 
  • mystic/mystic/scripts.py

    r804 r805  
    11#!/usr/bin/env python 
    22# 
    3 # Author: Patrick Hung (patrickh @caltech) 
     3# Author: Mike McKerns (mmckerns @caltech and @uqfoundation) 
    44# Author: Jean-Christophe Fillion-Robin (jchris.fillionr @kitware.com) 
    55# Copyright (c) 1997-2015 California Institute of Technology. 
    66# License: 3-clause BSD.  The full license text is available at: 
    77#  - 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__ = \ 
    459""" 
     10functional interfaces for mystic's visual analytics scripts 
     11""" 
     12 
     13__all__ = ['model_plotter',] 
     14 
    4615 
    4716from mpl_toolkits.mplot3d import axes3d 
     
    5322 
    5423#XXX: better if reads single id only? (e.g. same interface as read_history) 
    55 def get_history(source, ids=None): 
     24def _get_history(source, ids=None): 
    5625    """get params and cost from the given source 
    5726 
     
    8655 
    8756 
    88 def get_instance(location, *args, **kwds): 
     57def _get_instance(location, *args, **kwds): 
    8958    """given the import location of a model or model class, return the model 
    9059 
     
    9968 
    10069 
    101 def parse_input(option): 
     70def _parse_input(option): 
    10271    """parse 'option' string into 'select', 'axes', and 'mask' 
    10372 
     
    10776 
    10877For 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") 
    11079    >>> select 
    11180    [0, 3] 
     
    12998 
    13099 
    131 def parse_axes(option, grid=True): 
     100def _parse_axes(option, grid=True): 
    132101    """parse option string into grid axes; using modified numpy.ogrid notation 
    133102 
     
    176145 
    177146 
    178 def draw_projection(x, cost, scale=True, shift=False, style=None, figure=None): 
     147def _draw_projection(x, cost, scale=True, shift=False, style=None, figure=None): 
    179148    """draw a solution trajectory (for overlay on a 1D plot) 
    180149 
     
    206175 
    207176 
    208 def draw_trajectory(x, y, cost=None, scale=True, shift=False, style=None, figure=None): 
     177def _draw_trajectory(x, y, cost=None, scale=True, shift=False, style=None, figure=None): 
    209178    """draw a solution trajectory (for overlay on a contour plot) 
    210179 
     
    241210 
    242211 
    243 def draw_slice(f, x, y=None, scale=True, shift=False): 
     212def _draw_slice(f, x, y=None, scale=True, shift=False): 
    244213    """plot a slice of a 2D function 'f' in 1D 
    245214 
     
    281250 
    282251 
    283 def draw_contour(f, x, y=None, surface=False, fill=True, scale=True, shift=False, density=5): 
     252def _draw_contour(f, x, y=None, surface=False, fill=True, scale=True, shift=False, density=5): 
    284253    """draw a contour plot for a given 2D function 'f' 
    285254 
     
    328297 
    329298 
    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  
     299def model_plotter(model, logfile=None, **kwds): 
     300    """ 
     301generate surface contour plots for model, specified by full import path 
     302generate model trajectory from logfile (or solver restart file), if provided 
     303 
     304Available from the command shell as: 
     305  mystic_model_plotter.py model (filename) [options] 
     306 
     307or as a function call as: 
     308  mystic.model_plotter(model, filename=None, **options) 
     309 
     310The option "bounds" takes an indicator string, where the bounds should 
     311be given as comma-separated slices. For example, using bounds = "-1:10, 0:20" 
     312will set the lower and upper bounds for x to be (-1,10) and y to be (0,20). 
     313The "step" can also be given, to control the number of lines plotted in the 
     314grid. Thus "-1:10:.1, 0:20" would set the bounds as above, but use increments 
     315of .1 along x and the default step along y.  For models with > 2D, the bounds 
     316can be used to specify 2 dimensions plus fixed values for remaining dimensions. 
     317Thus, "-1:10, 0:20, 1.0" would plot the 2D surface where the z-axis was fixed 
     318at z=1.0.  When called from a script, slice objects can be used instead of a 
     319string, thus "-1:10:.1, 0:20, 1.0" becomes (slice(-1,10,.1), slice(20), 1.0). 
     320 
     321The option "label" takes comma-separated strings. For example, label = "x,y," 
     322will place 'x' on the x-axis, 'y' on the y-axis, and nothing on the z-axis. 
     323LaTeX is also accepted. For example, label = "$ h $, $ {\\alpha}$, $ v$" will 
     324label the axes with standard LaTeX math formatting. Note that the leading 
     325space is required, while a trailing space aligns the text with the axis 
     326instead of the plot frame. 
     327 
     328The option "reduce" can be given to reduce the output of a model to a scalar, 
     329thus converting 'model(params)' to 'reduce(model(params))'. A reducer is given 
     330by the import path (e.g. 'numpy.add'). The option "scale" will convert the plot 
     331to log-scale, and scale the cost by 'z=log(4*z*scale+1)+2'. This is useful for 
     332visualizing small contour changes around the minimium. If using log-scale 
     333produces negative numbers, the option "shift" can be used to shift the cost 
     334by 'z=z+shift'. Both shift and scale are intended to help visualize contours. 
     335 
     336Required Inputs: 
     337  model               full import path for the model (e.g. mystic.models.rosen) 
     338 
     339Additional Inputs: 
     340  filename            name of the convergence logfile (e.g. log.txt) 
     341    """ 
    357342    #FIXME: should be able to: 
    358343    # - apply a constraint as a region of NaN -- apply when 'xx,yy=x[ij],y[ij]' 
     
    368353    # - if trajectory outside contour grid, will increase bounds 
    369354    #   (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) 
    370413 
    371414    #XXX: note that 'argparse' is new as of python2.7 
    372415    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",\ 
    375418                      metavar="STR",default=None, 
    376                       help="save generated plot") 
     419                      help="filepath to save generated plot") 
    377420    parser.add_option("-b","--bounds",action="store",dest="bounds",\ 
    378421                      metavar="STR",default="-5:5:.1, -5:5:.1", 
     
    408451    # get the import path for the model 
    409452    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 
    411454 
    412455    try: # get the name of the parameter log file 
     
    489532 
    490533    # 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 
    493539    #FIXME: does grid=False still make sense here...? 
    494     if reducer: reducer = get_instance(reducer) 
     540    if reducer: reducer = _reducer or _get_instance(reducer) 
    495541    if solver and (not source or not model): 
    496542        raise RuntimeError('a model and results filename are required') 
     
    498544        raise RuntimeError('a model or a results file is required') 
    499545    if model: 
    500         model = get_instance(model) 
     546        model = _model or _get_instance(model) 
    501547        # need a reducer if model returns an array 
    502548        if reducer: model = reduced(reducer, arraylike=False)(model) 
     
    505551        # if 'live'... pick a solver 
    506552        solver = 'mystic.solvers.fmin' 
    507         solver = get_instance(solver) 
     553        solver = _solver or _get_instance(solver) 
    508554        xlen = len(select)+len(mask) 
    509555        if solver.__name__.startswith('diffev'): 
     
    533579       #elif source: v=cost[-1] 
    534580       #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) 
    536582        # 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) 
    538584    else: 
    539585       #fig0 = None 
     
    543589        # params are the parameter trajectories 
    544590        # cost is the solution trajectory 
    545         params, cost = get_history(source, ids) 
     591        params, cost = _get_history(source, ids) 
    546592        if len(cost) > 1: style = style[1:] # 'auto-color' #XXX: or grayscale? 
    547593 
     
    549595           ## project trajectory on a 1D slice of model surface #XXX: useful? 
    550596           #s = select[0] if len(select) else 0 
    551            #px = p[int(s)] # draw_projection requires one parameter 
     597           #px = p[int(s)] # _draw_projection requires one parameter 
    552598           ## ignore everything after 'stop' 
    553599           #_c = eval('c[%s]' % stop) 
    554600           #_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) 
    556602 
    557603            # plot the trajectory on the model surface (2D or 3D) 
    558604            # get two selected params #XXX: what if len(select)<2? or len(p)<2? 
    559605            p = [p[int(i)] for i in select[:2]] 
    560             px,py = p # draw_trajectory requires two parameters 
     606            px,py = p # _draw_trajectory requires two parameters 
    561607            # ignore everything after 'stop' 
    562608            _x = eval('px[%s]' % stop) 
    563609            _y = eval('py[%s]' % stop) 
    564610            _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) 
    566612 
    567613    # add labels to the axes 
     
    573619    if surface: ax.set_zlabel(label[2]) 
    574620 
    575     if not parsed_opts.plot_filepath: 
     621    if not parsed_opts.out: 
    576622        plt.show() 
    577623    else: 
    578         fig.savefig(parsed_opts.plot_filepath) 
     624        fig.savefig(parsed_opts.out) 
    579625 
    580626 
  • mystic/scripts/mystic_model_plotter.py

    r804 r805  
    77#  - http://mmckerns.github.io/project/mystic/browser/mystic/LICENSE 
    88 
    9 from mystic.model_plotter import model_plotter 
     9from mystic import model_plotter 
    1010 
    1111__doc__ = model_plotter.__doc__ 
     
    1414 
    1515    import sys 
    16     model_plotter(cmdargs=sys.argv[1:]) 
     16 
     17    model_plotter(sys.argv[1:]) 
    1718 
    1819 
Note: See TracChangeset for help on using the changeset viewer.