예제 #1
0
def validate_marker(val):
    """Does not really make a validation because markers can be quite of
    different types"""
    if val is None:
        return None
    else:
        return safe_list(val)
예제 #2
0
 def make_plot(self, ds, name, exec_=None):
     from psyplot_gui.main import mainwindow
     mainwindow.new_plots()
     mainwindow.plot_creator.switch2ds(ds)
     mainwindow.plot_creator.insert_array(safe_list(name))
     if exec_:
         mainwindow.plot_creator.exec_()
예제 #3
0
def validate_sym_lims(val):
    validator = try_and_error(
        validate_none, ValidateInStrings('sym_links', ['min', 'max'], True))
    val = safe_list(val)
    if len(val) != 2:
        val = val + val
    if not len(val) == 2:
        raise ValueError("Need two values for the symmetric limits, not %i" %
                         (len(val)))
    return list(map(validator, val))
예제 #4
0
    def add_datasets_from_cp(self, project=None):
        """Clear the tree and add the datasets based upon the given `project`

        Parameters
        ----------
        project: psyplot.project.Project
            The project containing the data array. If the project is not a main
            project, it's main project is used.
        """
        if project is None:
            project = gcp(True)
            sp_arrs = ArrayList().arrays
        elif project.is_main:
            sp_arrs = gcp().arrays
        else:
            sp_arrs = project.arrays
            project = project.main

        expanded_items = self.expanded_items()
        # remove items from the tree
        self.clear()
        for i, ds_desc in six.iteritems(
                project._get_ds_descriptions(
                    project.array_info(ds_description='all'))):
            top_item = DatasetTreeItem(ds_desc['ds'], self.attr_columns, 0)
            if ds_desc['fname'] is not None and not all(
                    s is None for s in ds_desc['fname']):
                ds_desc['fname'] = ', '.join(
                    map(osp.basename, safe_list(ds_desc['fname'])))
            else:
                ds_desc['fname'] = None
            top_item.setText(
                0, '%s%i: %s' % ('*' if any(
                    any(arr is arr2 for arr2 in sp_arrs)
                    for arr in ds_desc['arr']) else '', i, ds_desc['fname']))
            for arr in ds_desc['arr']:
                arr.psy.onbasechange.connect(self.add_datasets_from_cp)
            self.addTopLevelItem(top_item)
        self.expand_items(expanded_items)
예제 #5
0
def start_app(fnames=[], name=[], dims=None, plot_method=None,
              output=None, project=None, engine=None, formatoptions=None,
              tight=False, encoding=None, enable_post=False,
              seaborn_style=None, output_project=None,
              concat_dim=get_default_value(xr.open_mfdataset, 'concat_dim'),
              chname={},
              backend=False, new_instance=False, rc_file=None,
              rc_gui_file=None, include_plugins=rcParams['plugins.include'],
              exclude_plugins=rcParams['plugins.exclude'], offline=False,
              pwd=None, script=None, command=None, exec_=True, use_all=False,
              callback=None, preset=None,
              opengl_implementation=None, webengineview=True):
    """
    Eventually start the QApplication or only make a plot

    Parameters
    ----------
    %(make_plot.parameters)s
    backend: None or str
        The backend to use. By default, the ``'gui.backend'`` key in the
        :attr:`~psyplot_gui.config.rcsetup.rcParams` dictionary is used.
        Otherwise it can be None to use the standard matplotlib backend or a
        string identifying the backend
    new_instance: bool
        If True/set and the `output` parameter is not set, a new application is
        created
    rc_gui_file: str
        The path to a yaml configuration file that can be used to update  the
        :attr:`~psyplot_gui.config.rcsetup.rcParams`
    include_plugins: list of str
        The plugin widget to include. Can be either None to load all that are
        not explicitly excluded by `exclude_plugins` or a list of
        plugins to include. List items can be either module names, plugin
        names or the module name and widget via ``'<module_name>:<widget>'``
    exclude_plugins: list of str
        The plugin widgets to exclude. Can be either ``'all'`` to exclude
        all plugins or a list like in `include_plugins`.
    offline: bool
        If True/set, psyplot will be started in offline mode without
        intersphinx and remote access for the help explorer
    pwd: str
        The path to the working directory to use. Note if you do not provide
        any `fnames` or `project`, but set the `pwd`, it will switch the
        `pwd` of the current GUI.
    script: str
        The path to a python script that shall be run in the GUI. If the GUI
        is already running, the commands will be executed in this GUI.
    command: str
        Python commands that shall be run in the GUI. If the GUI is already
        running, the commands will be executed in this GUI
    use_all: bool
        If True, use all variables. Note that this is the default if the
        `output` is specified and not `name`
    exec_: bool
        If True, the main loop is entered.
    callback: str
        A unique identifier for the method that should be used if psyplot is
        already running. Set this parameter to None to avoid sending
    opengl_implementation: {'software', 'desktop', 'gles', 'automatic'}
        OpenGL implementation to pass to Qt. Possible options are
        'software', 'desktop', 'gles' and 'automatic' (which let's PyQt
        decide).
    webengineview: bool
        If True (default), use an HTML help widget. This might not be available
        for all builds of PyQt5 under all circumstances. If not set, the
        rcParams key ``'help_explorer.use_webengineview'`` is used.

    Returns
    -------
    None or :class:`psyplot_gui.main.MainWindow`
        ``None`` if `exec_` is True, otherwise the created
        :class:`~psyplot_gui.main.MainWindow` instance
    """
    if pwd is not None:
        os.chdir(pwd)
    if script is not None:
        script = osp.abspath(script)

    if project is not None and (name != [] or dims is not None):
        warn('The `name` and `dims` parameter are ignored if the `project`'
             ' parameter is set!')

    # load rcParams from file
    if rc_gui_file is not None:
        rcParams.load_from_file(rc_gui_file)

    # set plugins
    rcParams['plugins.include'] = include_plugins
    rcParams['plugins.exclude'] = exclude_plugins
    if webengineview is not None:
        rcParams['help_explorer.use_webengineview'] = webengineview

    if offline:
        rcParams['help_explorer.online'] = False
        rcParams['help_explorer.use_intersphinx'] = False

    if dims is not None and not isinstance(dims, dict):
        dims = dict(chain(*map(six.iteritems, dims)))

    if output is not None:
        return make_plot(
            fnames=fnames, name=name, dims=dims, plot_method=plot_method,
            output=output, project=project, engine=engine,
            formatoptions=formatoptions, tight=tight, rc_file=rc_file,
            encoding=encoding, enable_post=enable_post,
            seaborn_style=seaborn_style, output_project=output_project,
            concat_dim=concat_dim, chname=chname, preset=preset)
    if use_all:
        name = 'all'
    else:
        name = safe_list(name)

    if formatoptions is not None:
        if not isinstance(formatoptions, dict):
            # list of dicts
            for fmt in formatoptions[1:]:
                formatoptions[0].update(fmt)
            formatoptions = formatoptions[0]
        if preset is not None:
            import psyplot.project as psy
            preset_data = psy.Project._load_preset(preset)
        else:
            preset_data = {}
        preset_data.update(formatoptions)
        preset = tempfile.NamedTemporaryFile(prefix='psy_', suffix='.yml').name
        with open(preset, 'w') as f:
            yaml.dump(preset_data, f)

    # make preset path absolute
    if preset is not None and not isinstance(preset, dict) and \
            osp.exists(preset):
        preset = osp.abspath(preset)

    # Lock file creation
    if not new_instance:
        lock_file = osp.join(get_configdir(), 'psyplot.lock')
        lock = fasteners.InterProcessLock(lock_file)

        # Try to lock psyplot.lock. If it's *possible* to do it, then
        # there is no previous instance running and we can start a
        # new one. If *not*, then there is an instance already
        # running, which is locking that file
        lock_created = lock.acquire(False)
    else:
        lock_created = False

    chname = dict(chname)

    if lock_created:
        # Start a new instance
        atexit.register(lock.release)
    elif not new_instance:
        if callback is None:
            if fnames or project:
                callback = 'new_plot'
            elif pwd is not None:
                callback = 'change_cwd'
                fnames = [pwd]
            elif script is not None:
                callback = 'run_script'
                fnames = [script]
            elif command is not None:
                callback = 'command'
                engine = command
        if callback:
            send_files_to_psyplot(
                callback, fnames, project, engine, plot_method, name, dims,
                encoding, enable_post, seaborn_style, concat_dim, chname,
                preset)
        return
    elif new_instance:
        rcParams['main.listen_to_port'] = False
    if backend is not False:
        rcParams['backend'] = backend
    from psyplot_gui.main import MainWindow
    fnames = _get_abs_names(fnames)
    if project is not None:
        project = _get_abs_names([project])[0]
    if exec_:
        from psyplot_gui.compat.qtcompat import QApplication
        app = QApplication(sys.argv)

    _set_opengl_implementation(opengl_implementation)

    if isinstance(new_instance, MainWindow):
        mainwindow = new_instance
    else:
        mainwindow = MainWindow.run(fnames, project, engine, plot_method, name,
                                    dims, encoding, enable_post, seaborn_style,
                                    concat_dim, chname, preset)
    if script is not None:
        mainwindow.console.run_script_in_shell(script)
    if command is not None:
        mainwindow.console.run_command_in_shell(command)
    if exec_:
        sys.excepthook = mainwindow.excepthook
        sys.exit(app.exec_())
    else:
        return mainwindow
예제 #6
0
    def test_param(self,
                   check_index_duplicates=True,
                   check_data_duplicates=False,
                   to_csv=True,
                   **kwargs):
        def get_data(task):
            if not isinstance(task.data, pd.DataFrame):
                return task.data
            return [task.data]

        def no_duplicates(df):
            return df.ix[~df.index.duplicated(keep=False)]

        if self.param_cls is None:
            return
        to_db = self.use_db
        name = self.name
        self._test_init()
        kwargs.setdefault(name, {})
        kwargs.setdefault('to_return', [name])
        manager = self.organizer.param(stations=self.stations_file,
                                       to_csv=to_csv,
                                       to_db=to_db,
                                       **kwargs)
        task = manager.get_task(name)
        ref_data = get_data(task)

        # check if run worked
        if task.has_run:
            self.assertEqual(
                set(task.namelist_keys),
                set(self.organizer.exp_config['namelist']['weathergen_ctl']))

        setup_from_file = False
        for fname in filter(None, safe_list(task.datafile)):
            setup_from_file = True
            self.assertTrue(osp.exists(fname),
                            msg='Datafile %s of %s task does not exist!' %
                            (fname, name))
        if check_index_duplicates:
            for df in get_data(task):
                idx = df.index
                self.assertFalse(
                    idx.has_duplicates,
                    msg='%s task index data has duplicates!\n%s' %
                    (name, idx.values[idx.duplicated(keep=False)]))
        if check_data_duplicates:
            self.assertFalse(
                task.data.duplicated().any(),
                msg='%s task data has duplicates!\n%s' %
                (name, task.data[task.data.duplicated(keep=False)]))
        engine = task.engine
        setup_from_db = False
        if engine is not None:
            sql_dtypes = task._split_kwargs(task.sql_dtypes)
            for i, table in enumerate(safe_list(task.dbname)):
                if table is not None:
                    setup_from_db = True
                    self.assertTrue(engine.has_table(table),
                                    msg='Database has no table %s of %s task' %
                                    (table, name))
                    data = task._get_data(i)
                    data_cols = set(data.columns) | set(data.index.names)
                    self.assertEqual(set(sql_dtypes[i]) & data_cols,
                                     data_cols,
                                     msg='Missing sql dtype for %s' % name)

        # check setup from file
        if setup_from_file:
            manager = self.organizer.param(stations=self.stations_file,
                                           **kwargs)
            new_task = manager.get_task(name)
            self.assertEqual(new_task.setup_from,
                             'file',
                             msg='setup_from of %s task should be "file"!' %
                             (name))
            new_data = get_data(new_task)
            self.assertEqual(len(new_data),
                             len(ref_data),
                             msg=('Number of dataframes for %s task are not '
                                  'equal after setup from file!') % name)
            for df, df_ref in zip(new_data, ref_data):
                df.sort_index(inplace=True)
                df_ref.sort_index(inplace=True)
                df = no_duplicates(df)
                df_ref = no_duplicates(df_ref)
                mask = (df != df_ref).values.any(axis=1)
                self.assertIsNone(df_equals(df, df_ref, check_dtype=False),
                                  msg=df_diff_msg %
                                  (df.ix[mask], df_ref.ix[mask]))
        # check setup from db
        if setup_from_db:
            for fname in filter(None, safe_list(task.datafile)):
                os.remove(fname)
            manager = self.organizer.param(stations=self.stations_file,
                                           **kwargs)
            new_task = manager.get_task(name)
            self.assertEqual(new_task.setup_from,
                             'db',
                             msg='setup_from of %s task should be "db"!' %
                             (name))
            new_data = get_data(new_task)
            self.assertEqual(len(new_data),
                             len(ref_data),
                             msg=('Number of dataframes for %s task are not '
                                  'equal after setup from db!') % name)
            for df, df_ref in zip(new_data, ref_data):
                df.sort_index(inplace=True)
                df_ref.sort_index(inplace=True)
                df = no_duplicates(df)
                df_ref = no_duplicates(df_ref)
                mask = (df != df_ref).values.any(axis=1)
                self.assertIsNone(df_equals(df, df_ref, check_dtype=False),
                                  msg=df_diff_msg %
                                  (df.ix[mask], df_ref.ix[mask]))
        return manager
예제 #7
0
def start_app(fnames=[], name=[], dims=None, plot_method=None,
              output=None, project=None, engine=None, formatoptions=None,
              tight=False, encoding=None, enable_post=False,
              seaborn_style=None, output_project=None,
              concat_dim=get_default_value(xr.open_mfdataset, 'concat_dim'),
              chname={},
              backend=False, new_instance=False, rc_file=None,
              rc_gui_file=None, include_plugins=rcParams['plugins.include'],
              exclude_plugins=rcParams['plugins.exclude'], offline=False,
              pwd=None, script=None, command=None, exec_=True, use_all=False,
              callback=None):
    """
    Eventually start the QApplication or only make a plot

    Parameters
    ----------
    %(make_plot.parameters)s
    backend: None or str
        The backend to use. By default, the ``'gui.backend'`` key in the
        :attr:`~psyplot_gui.config.rcsetup.rcParams` dictionary is used.
        Otherwise it can be None to use the standard matplotlib backend or a
        string identifying the backend
    new_instance: bool
        If True/set and the `output` parameter is not set, a new application is
        created
    rc_gui_file: str
        The path to a yaml configuration file that can be used to update  the
        :attr:`~psyplot_gui.config.rcsetup.rcParams`
    include_plugins: list of str
        The plugin widget to include. Can be either None to load all that are
        not explicitly excluded by `exclude_plugins` or a list of
        plugins to include. List items can be either module names, plugin
        names or the module name and widget via ``'<module_name>:<widget>'``
    exclude_plugins: list of str
        The plugin widgets to exclude. Can be either ``'all'`` to exclude
        all plugins or a list like in `include_plugins`.
    offline: bool
        If True/set, psyplot will be started in offline mode without
        intersphinx and remote access for the help explorer
    pwd: str
        The path to the working directory to use. Note if you do not provide
        any `fnames` or `project`, but set the `pwd`, it will switch the
        `pwd` of the current GUI.
    script: str
        The path to a python script that shall be run in the GUI. If the GUI
        is already running, the commands will be executed in this GUI.
    command: str
        Python commands that shall be run in the GUI. If the GUI is already
        running, the commands will be executed in this GUI
    use_all: bool
        If True, use all variables. Note that this is the default if the
        `output` is specified and not `name`
    exec_: bool
        If True, the main loop is entered.
    callback: str
        A unique identifier for the method that should be used if psyplot is
        already running. Set this parameter to None to avoid sending

    Returns
    -------
    None or :class:`psyplot_gui.main.MainWindow`
        ``None`` if `exec_` is True, otherwise the created
        :class:`~psyplot_gui.main.MainWindow` instance
    """
    if pwd is not None:
        os.chdir(pwd)
    if script is not None:
        script = osp.abspath(script)

    if project is not None and (name != [] or dims is not None):
        warn('The `name` and `dims` parameter are ignored if the `project`'
             ' parameter is set!')

    # load rcParams from file
    if rc_gui_file is not None:
        rcParams.load_from_file(rc_gui_file)

    # set plugins
    rcParams['plugins.include'] = include_plugins
    rcParams['plugins.exclude'] = exclude_plugins

    if offline:
        rcParams['help_explorer.online'] = False
        rcParams['help_explorer.use_intersphinx'] = False

    if dims is not None and not isinstance(dims, dict):
        dims = dict(chain(*map(six.iteritems, dims)))

    if output is not None:
        return make_plot(
            fnames=fnames, name=name, dims=dims, plot_method=plot_method,
            output=output, project=project, engine=engine,
            formatoptions=formatoptions, tight=tight, rc_file=rc_file,
            encoding=encoding, enable_post=enable_post,
            seaborn_style=seaborn_style, output_project=output_project,
            concat_dim=concat_dim, chname=chname)
    if use_all:
        name = 'all'
    else:
        name = safe_list(name)

    # Lock file creation
    if not new_instance:
        lock_file = osp.join(get_configdir(), 'psyplot.lock')
        lock = fasteners.InterProcessLock(lock_file)

        # Try to lock psyplot.lock. If it's *possible* to do it, then
        # there is no previous instance running and we can start a
        # new one. If *not*, then there is an instance already
        # running, which is locking that file
        lock_created = lock.acquire(False)
    else:
        lock_created = False

    chname = dict(chname)

    if lock_created:
        # Start a new instance
        atexit.register(lock.release)
    elif not new_instance:
        if callback is None:
            if fnames or project:
                callback = 'new_plot'
            elif pwd is not None:
                callback = 'change_cwd'
                fnames = [pwd]
            elif script is not None:
                callback = 'run_script'
                fnames = [script]
            elif command is not None:
                callback = 'command'
                engine = command
        if callback:
            send_files_to_psyplot(
                callback, fnames, project, engine, plot_method, name, dims,
                encoding, enable_post, seaborn_style, concat_dim, chname)
        return
    elif new_instance:
        rcParams['main.listen_to_port'] = False
    if backend is not False:
        rcParams['backend'] = backend
    from psyplot_gui.main import MainWindow
    fnames = _get_abs_names(fnames)
    if project is not None:
        project = _get_abs_names([project])[0]
    if exec_:
        from psyplot_gui.compat.qtcompat import QApplication
        app = QApplication(sys.argv)
    if isinstance(new_instance, MainWindow):
        mainwindow = new_instance
    else:
        mainwindow = MainWindow.run(fnames, project, engine, plot_method, name,
                                    dims, encoding, enable_post, seaborn_style,
                                    concat_dim, chname)
    if script is not None:
        mainwindow.console.run_script_in_shell(script)
    if command is not None:
        mainwindow.console.run_command_in_shell(command)
    if exec_:
        sys.excepthook = mainwindow.excepthook
        sys.exit(app.exec_())
    else:
        return mainwindow