Source code for pytplot.tplot

# Copyright 2018 Regents of the University of Colorado. All Rights Reserved.
# Released under the MIT license.
# This software was developed at the University of Colorado's Laboratory for Atmospheric and Space Physics.
# Verify current version before use at: https://github.com/MAVENSDC/PyTplot

from __future__ import division
import sys
import os
import logging
import pytplot
from pytplot import tplot_utilities
import tempfile
from .MPLPlotter.tplot import tplot as mpl_tplot

def webengine_hack():
    """ This function is a hack to resolve an import error. 
    Without this, we sometimes get:
    ImportError: QtWebEngineWidgets must be imported before a QCoreApplication instance is created
    """
    from PyQt5 import QtWidgets
    app = QtWidgets.QApplication.instance()
    if app is not None:
        import sip
        app.quit()
        sip.delete(app)
    import sys
    from PyQt5 import QtCore, QtWebEngineWidgets
    QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_ShareOpenGLContexts)
    app = QtWidgets.qApp = QtWidgets.QApplication(sys.argv)
    return app


if pytplot.using_graphics:
    from .QtPlotter import PyTPlot_Exporter
    from pyqtgraph.Qt import QtCore, QtGui, QtCore
    import pyqtgraph as pg
    from . import QtPlotter
    from pytplot.AncillaryPlots import spec_slicer
    from pytplot.AncillaryPlots import position_mars_2d
    from pytplot.AncillaryPlots import position_mars_3d

[docs] def tplot(name, trange=None, var_label=None, slice=False, combine_axes=True, nb=False, save_file=None, gui=False, qt=False, bokeh=False, save_png=None, display=True, testing=False, extra_functions=[], extra_function_args=[], vert_spacing=None, pos_2d=False, pos_3d=False, exec_qt=True, window_name='Plot', interactive=False, # the following are for the matplotlib version xsize=None, ysize=None, save_eps='', save_svg='', save_pdf='', save_jpeg='', dpi=None, fig=None, axis=None, pseudo_plot_num=None, second_axis_size=0.0, return_plot_objects=False): """ This is the function used to display the tplot variables stored in memory. It is a wrapper that calls a matplotlib-specific version of tplot. Parameters ---------- name : str or list of str, required List of tplot variables that will be plotted. If this is empty, nothing will be plotted. trange: list of string or float, optional If set, this time range will be used, temporarily overriding any previous xlim or timespan calls var_label : str, optional The name of the tplot variable you would like as a second x axis. xsize: float, optional Plot size in the horizontal direction (in inches) ysize: float, optional Plot size in the vertical direction (in inches) dpi: float, optional The resolution of the plot in dots per inch save_png : str, optional A full file name and path. If this option is set, the plot will be automatically saved to the file name provided in a PNG format. save_eps : str, optional A full file name and path. If this option is set, the plot will be automatically saved to the file name provided in a EPS format. save_jpeg : str, optional A full file name and path. If this option is set, the plot will be automatically saved to the file name provided in a JPEG format. save_pdf : str, optional A full file name and path. If this option is set, the plot will be automatically saved to the file name provided in a PDF format. save_svg : str, optional A full file name and path. If this option is set, the plot will be automatically saved to the file name provided in a SVG format. display: bool, optional If True, then this function will display the plotted tplot variables. Necessary to make this optional so we can avoid it in a headless server environment. return_plot_objects: bool, optional If true, returns the matplotlib fig and axes objects for further manipulation. Returns ------- Any Returns matplotlib fig and axes objects, if return_plot_objects==True Examples -------- >>> #Plot a single line in bokeh >>> import pyspedas >>> x_data = [2,3,4,5,6] >>> y_data = [1,2,3,4,5] >>> pyspedas.store_data("Variable1", data={'x':x_data, 'y':y_data}) >>> pyspedas.tplot("Variable1",bokeh=True) >>> #Display two plots >>> x_data = [1,2,3,4,5] >>> y_data = [[1,5],[2,4],[3,3],[4,2],[5,1]] >>> pyspedas.store_data("Variable2", data={'x':x_data, 'y':y_data}) >>> pyspedas.tplot(["Variable1", "Variable2"]) >>> #Display 2 plots, using Variable1 as another x axis >>> x_data = [1,2,3] >>> y_data = [ [1,2,3] , [4,5,6], [7,8,9] ] >>> v_data = [1,2,3] >>> pyspedas.store_data("Variable3", data={'x':x_data, 'y':y_data, 'v':v_data}) >>> pyspedas.options("Variable3", 'spec', 1) >>> pyspedas.tplot(["Variable2", "Variable3"], var_label='Variable1') """ # If no tplot names were provided, exit if name is None or len(name) < 1: logging.error("no valid tplot variables were provided.") return elif not isinstance(name, list): name = [name] # If only one name was provided, put it in a list num_plots = len(name) if qt == False and bokeh == False: return mpl_tplot(name, trange=trange, var_label=var_label, xsize=xsize, ysize=ysize, save_png=save_png, save_eps=save_eps, save_svg=save_svg, save_pdf=save_pdf, save_jpeg=save_jpeg, dpi=dpi, display=display, fig=fig, axis=axis, slice=slice, running_trace_count=pseudo_plot_num, second_axis_size=second_axis_size, return_plot_objects=return_plot_objects) # Code below this point should be unreachable, left in for reference purposes if interactive: slice=True if not pytplot.using_graphics and save_file is None: print("Qt was not successfully imported. Specify save_file to save the file as a .html file.") return # Check a bunch of things for i in range(num_plots): if isinstance(name[i], int): name[i] = list(pytplot.data_quants.keys())[name[i]] if name[i] not in pytplot.data_quants.keys(): logging.info(str(name[i]) + " is currently not in pytplot") return if isinstance(var_label, int): var_label = list(pytplot.data_quants.keys())[var_label] if vert_spacing is None: if 'vertical_spacing' in pytplot.tplot_opt_glob: vert_spacing = pytplot.tplot_opt_glob['vertical_spacing'] else: vert_spacing = 25 # Just a default that looks ok if bokeh: logging.error("This version of pytplot no longer supports Bokeh plotting.") else: if save_png is not None: layout = QtPlotter.generate_stack(name, var_label=var_label, combine_axes=combine_axes, vert_spacing=vert_spacing) layout.resize(pytplot.tplot_opt_glob['window_size'][0], pytplot.tplot_opt_glob['window_size'][1]) for i, item in enumerate(layout.items()): if type(item) == pg.graphicsItems.GraphicsLayout.GraphicsLayout: layout.items()[i].resize(pytplot.tplot_opt_glob['window_size'][0], pytplot.tplot_opt_glob['window_size'][1]) exporter = PyTPlot_Exporter.PytplotExporter(layout) exporter.parameters()['width'] = pytplot.tplot_opt_glob['window_size'][0] exporter.parameters()['height'] = pytplot.tplot_opt_glob['window_size'][1] exporter.export(save_png) if display: # This layout is used when the user wants a png image saved. layout_orig = QtPlotter.generate_stack(name, var_label=var_label, combine_axes=combine_axes, vert_spacing=vert_spacing) layout_orig.resize(pytplot.tplot_opt_glob['window_size'][0], pytplot.tplot_opt_glob['window_size'][1]) for i, item in enumerate(layout_orig.items()): if type(item) == pg.graphicsItems.GraphicsLayout.GraphicsLayout: layout_orig.items()[i].resize(pytplot.tplot_opt_glob['window_size'][0], pytplot.tplot_opt_glob['window_size'][1]) try: #TODO: This exporter requires h5py to be installed because that is what pyqtgraph requires. exporter = QtPlotter.PytplotExporter(layout_orig) except: exporter = None # Set up displayed plot window and grab plots to plot on it available_qt_window = tplot_utilities.get_available_qt_window(name=window_name) layout = QtPlotter.generate_stack(name, var_label=var_label, combine_axes=combine_axes, vert_spacing=vert_spacing) available_qt_window.newlayout(layout) available_qt_window.resize(pytplot.tplot_opt_glob['window_size'][0], pytplot.tplot_opt_glob['window_size'][1]) # Implement button that lets you save the PNG available_qt_window.init_savepng(exporter) # Show the plot window and plot available_qt_window.show() available_qt_window.activateWindow() # This function is responsible for calling all of the extra plotting routines that a user might like with # their data plots extra_function_handler(extra_functions, extra_function_args, name, slice, pos_2d, pos_3d) if testing: return # (hasattr(sys, 'ps1')) checks to see if we're in ipython if (not (hasattr(sys, 'ps1')) or not hasattr(QtCore, 'PYQT_VERSION')) and exec_qt: QtGui.QApplication.instance().exec_() pass else: try: magic = get_ipython().magic magic(u'%gui qt5') except: pass return
def extra_function_handler(extra_functions, extra_functions_args, names, slice, pos_2d, pos_3d): functions_to_call = extra_functions function_args_to_call = extra_functions_args # Handles the old way of calling the spec slicing plots, (if anyone still uses that way) if slice: # Call 2D spice slicing window; This will only plot something when spectrograms are involved. functions_to_call.append(spec_slicer.spec_slicer) function_args_to_call.append([None, None, True]) if pos_2d: functions_to_call.append(position_mars_2d.position_mars_2d) function_args_to_call.append([None]) if pos_3d: functions_to_call.append(position_mars_3d.position_mars_3d) function_args_to_call.append([None]) static_list = [i for i in names if 'static' in pytplot.data_quants[i].attrs['plot_options']['extras']] for tplot_var in static_list: # Call 2D static window; This will only plot something when spectrograms are involved. functions_to_call.append(spec_slicer.spec_slicer) function_args_to_call.append( [tplot_var, pytplot.data_quants[tplot_var].attrs['plot_options']['extras']['static'], False]) static_tavg_list = [i for i in names if 'static_tavg' in pytplot.data_quants[i].attrs['plot_options']['extras']] for tplot_var in static_tavg_list: # Call 2D static window for time-averaged values; This will only plot something when spectrograms # are involved functions_to_call.append(spec_slicer.spec_slicer) function_args_to_call.append([tplot_var,pytplot.data_quants[tplot_var].attrs['plot_options']['extras']['static_tavg'], False]) for f, args in zip(functions_to_call, function_args_to_call): f(*args)