Source code for omfit_classes.omfit_dmp

try:
    # framework is running
    from .startup_choice import *
except ImportError as _excp:
    # class is imported by itself
    if (
        'attempted relative import with no known parent package' in str(_excp)
        or 'No module named \'omfit_classes\'' in str(_excp)
        or "No module named '__main__.startup_choice'" in str(_excp)
    ):
        from startup_choice import *
    else:
        raise


from omfit_classes.omfit_hdf5 import dict2hdf5, OMFIThdf5

import weakref
from matplotlib.pyplot import *
from matplotlib import pyplot
import numpy as np

__all__ = ['figures_dmp', 'OMFITdmp']

# ----------------
# Data Managment Plan
# ----------------

patch_plot_functions = [
    'acorr',
    #'add_artist',
    #'add_callback',
    #'add_collection',
    #'add_container',
    #'add_image',
    #'add_line',
    #'add_patch',
    #'add_table',
    #'aname',
    'angle_spectrum',
    'annotate',
    #'apply_aspect',
    'arrow',
    #'autoscale',
    #'autoscale_view',
    #'axes',
    #'axes_downsample',
    'axhline',
    'axhspan',
    'axis',
    'axvline',
    'axvspan',
    'bar',
    'barbs',
    'barh',
    'boxplot',
    'broken_barh',
    'bxp',
    #'can_pan',
    #'can_zoom',
    #'cla', #<-------
    'clabel',
    #'clear', #<------
    'cohere',
    #'contains',
    #'contains_point',
    'contour',
    'contourf',
    #'convert_xunits',
    #'convert_yunits',
    'csd',
    #'drag_pan',
    #'draw',
    #'draw_artist',
    #'end_pan',
    'errorbar',
    'eventplot',
    'fill',
    'fill_between',
    'fill_betweenx',
    #'findobj',
    #'format_coord',
    #'format_cursor_data',
    #'format_xdata',
    #'format_ydata',
    #'grid', #<-------
    #'has_data',
    #'have_units',
    'hexbin',
    'hist',
    'hist2d',
    #'hitlist',
    'hlines',
    #'hold',
    'imshow',
    #'in_axes',
    #'invert_xaxis',
    #'invert_yaxis',
    #'is_figure_set',
    #'is_transform_set',
    #'ishold',
    'legend',
    #'locator_params',
    'loglog',
    'magnitude_spectrum',
    #'margins',
    'matshow',
    #'minorticks_off',
    #'minorticks_on',
    #'mouseover',
    #'name',
    #'pchanged',
    'pcolor',
    'pcolorfast',
    'pcolormesh',
    'phase_spectrum',
    #'pick',
    #'pickable',
    'pie',
    'plot',
    'plot_date',
    #'properties',
    'psd',
    'quiver',
    'quiverkey',
    #'redraw_in_frame',
    #'relim',
    #'remove', #<-------
    #'remove_callback',
    'reset_position',
    'scatter',
    'semilogx',
    'semilogy',
    #'set',
    'specgram',
    'spy',
    'stackplot',
    #'stale',
    #'start_pan',
    'stem',
    'step',
    'sticky_edges',
    'streamplot',
    'table',
    'text',
    #'tick_params',
    #'ticklabel_format',
    'tricontour',
    'tricontourf',
    'tripcolor',
    'triplot',
    #'twinx',
    #'twiny',
    #'update',
    #'update_datalim',
    #'update_datalim_bounds',
    #'update_datalim_numerix',
    #'update_from',
    #'use_sticky_edges',
    'violin',
    'violinplot',
    'vlines',
    'xaxis_date',
    #'xaxis_inverted',
    'xcorr',
    'yaxis_date',
    #'yaxis_inverted',
    #'zorder'
] + [
    #'set_adjustable',
    #'set_agg_filter',
    'set_alpha',
    #'set_anchor',
    #'set_animated',
    #'set_aspect',
    #'set_autoscale_on',
    #'set_autoscalex_on',
    #'set_autoscaley_on',
    #'set_axes',
    #'set_axes_locator',
    #'set_axis_bgcolor',
    #'set_axis_off',
    #'set_axis_on',
    #'set_axisbelow',
    #'set_clip_box',
    #'set_clip_on',
    #'set_clip_path',
    #'set_color_cycle',
    #'set_contains',
    #'set_cursor_props',
    #'set_downsampling',
    #'set_facecolor',
    #'set_fc',
    #'set_figure',
    #'set_frame_on',
    #'set_gid',
    #'set_label',
    #'set_navigate',
    #'set_navigate_mode',
    #'set_path_effects',
    #'set_picker',
    #'set_position',
    #'set_prop_cycle',
    #'set_rasterization_zorder',
    #'set_rasterized',
    #'set_sketch_params',
    #'set_snap',
    'set_title',
    #'set_transform',
    #'set_url',
    #'set_visible',
    #'set_xbound',
    'set_xlabel',
    #'set_xlim',
    #'set_xmargin',
    'set_xscale',
    'set_xticklabels',
    'set_xticks',
    #'set_ybound',
    'set_ylabel',
    #'set_ylim',
    #'set_ymargin',
    'set_yscale',
    'set_yticklabels',
    'set_yticks',
    #'set_zorder'
]


def _tr(self):
    for item in self:
        if 'data' in self[item]:
            data = b2s(self[item]['data'])
            if isinstance(data, str) and data == '_None':
                data = None
            elif isinstance(data, np.ndarray) and 'float' in str(data.dtype):
                data = np.array(data, dtype=float)
            self[item] = data
        else:
            _tr(self[item])

    return self


[docs]class OMFITdmp(SortedDict, OMFITobject): """ Class to satisfy DoE Data Managment Plan that requires the data used in a publication figure to be made available """ def __init__(self, filename, *args, **kw): # this is when loading from HDF5 object if isinstance(filename, str): OMFITobject.__init__(self, filename, *args, **kw) SortedDict.__init__(self) self.dynaLoad = True else: # this is when creating object from matplotlib figure num = getattr(filename, 'number', filename.get_label()) OMFITobject.__init__(self, 'Figure_%s.h5' % num, *args, **kw) SortedDict.__init__(self) self.from_fig(filename)
[docs] def from_fig(self, fig): """ Populate object and file from matplotlib figure :param fig: matplotlib figure :return: self """ self.clear() self.dynaLoad = False for ai, ax in enumerate(fig.get_axes()): if id(ax) in figures_dmp: self['axes_%d' % id(ax)] = axp = copy.copy(figures_dmp[id(ax)]['DATA']) self['axes_%d' % id(ax)].append({'func': 'ax.set_xlim', 'args': [ax.get_xlim()]}) self['axes_%d' % id(ax)].append({'func': 'ax.set_ylim', 'args': [ax.get_ylim()]}) tmp = ax.get_position().get_points().flatten().tolist() tmp = tmp[:2] + [tmp[2] - tmp[0]] + [tmp[3] - tmp[1]] self['axes_%d' % id(ax)].insert(0, {'func': 'fig.add_axes', 'args': [tmp]}) self.save() return self
[docs] def load(self): self.clear() tmp = OMFIThdf5(self.filename, noCopyToCWD=True)['DATA'] for ax in tmp: self[ax] = [] for step in sorted(tmp[ax], key=lambda x: int(x.split('_')[1])): self[ax].append(_tr(tmp[ax][step])) self[ax][-1]['args'] = list(self[ax][-1]['args'].values())
[docs] def plot(self): """ generate plot based on dictionary content :return: matplotlib Figure handle """ from omfit_classes.utils_plot import image fig = pyplot.gcf() for ax in self: for step in self[ax]: func = b2s(step['func']) if func == 'fig.add_axes': ax = fig.add_axes(*step.get('args', []), **step.get('kwargs', {})) else: args = step.get('args', []) kwargs = step.get('kwargs', {}) eval(func)(*args, **kwargs) return fig
[docs] def save(self): """ writes ditionary to HDF5 """ dictin = {} for ax in self: dictin['axes_%d' % id(ax)] = tmp = {'step_%d' % k: copy.copy(v) for k, v in enumerate(self[ax])} for step in list(tmp.values()): step['args'] = {'%d' % k: copy.copy(v) for k, v in enumerate(step['args'])} return dict2hdf5(self.filename, {'DATA': dictin}, compression=9)
[docs] def script(self): """ :return: string with Python script to reproduce the figure (with DATA!) """ txt = ['# auto-generated OMFIT data management plan plotting script', ''] txt.append('fig = pyplot.gcf()') txt.append('') for k, ax in enumerate(self): if len(self) > 1: comment = 'AXES %d' % k txt.append('# ' + comment) for step in self[ax]: args_txt = ','.join(map(repr, step.get('args', []))) kw_txt = keyword_arguments(step.get('kwargs', {})) if step['func'] == 'fig.add_axes': txt.append("ax = fig.add_axes(%s)" % ','.join([_f for _f in [args_txt, kw_txt] if _f])) else: txt.append("%s(%s)" % (step['func'], ','.join([_f for _f in [args_txt, kw_txt] if _f]))) txt.append('') return '\n'.join(txt)
[docs] def OMFITpythonPlot(self, filename): """ generate OMFITpythonPlot script from figure (with DATA!) :param filename: filename for OMFITpythonPlot script :return: OMFITpythonPlot object """ from omfit_classes.omfit_python import OMFITpythonPlot return OMFITpythonPlot(filename, fromString=self.script())
figures_dmp = {} originals = {} subs = {} mpl_dump_enable = [True] # storage function that is used by the @dump_function_usage decorator def mpl_dump(dumpDict): if not mpl_dump_enable[0]: return # store data information on a per axis basis ax = dumpDict['args'][0] if id(ax) not in figures_dmp: figures_dmp[id(ax)] = {} figures_dmp[id(ax)]['weakref'] = weakref.ref(ax) figures_dmp[id(ax)].setdefault('DATA', []) figures_dmp[id(ax)]['DATA'].append(dumpDict) if figures_dmp[id(ax)]['DATA'][-1]['func'].startswith('_omfit_dmp_'): figures_dmp[id(ax)]['DATA'][-1]['func'] = 'ax.' + re.sub('^_omfit_dmp_', '', figures_dmp[id(ax)]['DATA'][-1]['func']) figures_dmp[id(ax)]['DATA'][-1]['args'] = list(figures_dmp[id(ax)]['DATA'][-1]['args'][1:]) # cleanup data from old figures for item in list(figures_dmp.keys()): if figures_dmp[item]['weakref']() is None: del figures_dmp[item] from matplotlib.axes import Axes # monkey patching of matplotlib.Axes function to track arguments passed for function_name in patch_plot_functions: for package in ['Axes']: if hasattr(eval(package), function_name) and (package, function_name) not in originals: originals[package, function_name] = getattr(eval(package), function_name) subs.setdefault(id(originals[package, function_name]), []).append((package, function_name)) for sub in subs: for k, (package, function_name) in enumerate(subs[sub]): if k == 0: exec( ''' @dump_function_usage(mpl_dump) def _omfit_dmp_{function_name}(*args,**kw): #print('{function_name}') return originals['{package}','{function_name}'](*args,**kw) _omfit_dmp_{function_name}.__doc__=originals['{package}','{function_name}'].__doc__ '''.format( function_name=function_name, package=package ) ) setattr(eval(package), function_name, eval('_omfit_dmp_' + function_name)) ############################################ if '__main__' == __name__: test_classes_main_header() tmp = OMFITdmp(OMFITsrc + '/../samples/DIII-D_1_journal_XXXX_FigXX.h5') print(tmp)