예제 #1
0
    def run(cls, fnames=[], project=None, engine=None, plot_method=None,
            name=None, dims=None, encoding=None, enable_post=False,
            seaborn_style=None,
            concat_dim=get_default_value(xr.open_mfdataset, 'concat_dim'),
            chname={}, show=True):
        """
        Create a mainwindow and open the given files or project

        This class method creates a new mainwindow instance and sets the
        global :attr:`mainwindow` variable.

        Parameters
        ----------
        %(MainWindow.open_external_files.parameters)s
        %(MainWindow.parameters)s

        Notes
        -----
        - There can be only one mainwindow at the time
        - This method does not create a QApplication instance! See
          :meth:`run_app`

        See Also
        --------
        run_app
        """
        mainwindow = cls(show=show)
        _set_mainwindow(mainwindow)
        if fnames or project:
            mainwindow.open_external_files(
                fnames, project, engine, plot_method, name, dims, encoding,
                enable_post, seaborn_style, concat_dim, chname)
        psyplot.with_gui = True
        return mainwindow
예제 #2
0
    def open_external_files(self, fnames=[], project=None, engine=None,
                            plot_method=None, name=None, dims=None,
                            encoding=None, enable_post=False,
                            seaborn_style=None, concat_dim=get_default_value(
                                xr.open_mfdataset, 'concat_dim'), chname={}):
        """
        Open external files

        Parameters
        ----------
        %(make_plot.parameters.fnames|project|engine|plot_method|name|dims|encoding|enable_post|seaborn_style|concat_dim|chname)s
        """
        if seaborn_style is not None:
            import seaborn as sns
            sns.set_style(seaborn_style)
        if project is not None:
            fnames = [s.split(',') for s in fnames]
            if not isinstance(project, dict):
                project = psyd.safe_list(project)[0]
            single_files = (l[0] for l in fnames if len(l) == 1)
            alternative_paths = defaultdict(lambda: next(single_files, None))
            alternative_paths.update(list(l for l in fnames if len(l) == 2))
            p = psy.Project.load_project(
                project, alternative_paths=alternative_paths,
                engine=engine, main=not psy.gcp(), encoding=encoding,
                enable_post=enable_post, chname=chname)
            if isinstance(project, six.string_types):
                p.attrs.setdefault('project_file', project)
            return True
        else:
            self.new_plots(False)
            self.plot_creator.open_dataset(fnames, engine=engine,
                                           concat_dim=concat_dim)
            if name == 'all':
                ds = self.plot_creator.get_ds()
                name = sorted(set(ds.variables) - set(ds.coords))
            self.plot_creator.insert_array(
                list(filter(None, psy.safe_list(name))))
            if dims is not None:
                ds = self.plot_creator.get_ds()
                dims = {key: ', '.join(
                    map(str, val)) for key, val in six.iteritems(
                        dims)}
                for i, vname in enumerate(
                        self.plot_creator.array_table.vnames):
                    self.plot_creator.array_table.selectRow(i)
                    self.plot_creator.array_table.update_selected(
                        )
                self.plot_creator.array_table.selectAll()
                var = ds[vname[0]]
                self.plot_creator.array_table.update_selected(
                    dims=var.psy.decoder.correct_dims(var, dims.copy()))
            if plot_method:
                self.plot_creator.pm_combo.setCurrentIndex(
                    self.plot_creator.pm_combo.findText(plot_method))
            self.plot_creator.exec_()
            return True
예제 #3
0
    def open_external_files(self,
                            fnames=[],
                            project=None,
                            engine=None,
                            plot_method=None,
                            name=None,
                            dims=None,
                            encoding=None,
                            enable_post=False,
                            seaborn_style=None,
                            concat_dim=get_default_value(
                                xr.open_mfdataset, 'concat_dim')):
        """
        Open external files

        Parameters
        ----------
        %(make_plot.parameters.fnames|project|engine|plot_method|name|dims|encoding|enable_post|seaborn_style|concat_dim)s
        """
        if seaborn_style is not None:
            import seaborn as sns
            sns.set_style(seaborn_style)
        if project is not None:
            fnames = [s.split(',') for s in fnames]
            single_files = (l[0] for l in fnames if len(l) == 1)
            alternative_paths = defaultdict(lambda: next(single_files, None))
            alternative_paths.update(list(l for l in fnames if len(l) == 2))
            p = psy.Project.load_project(project,
                                         alternative_paths=alternative_paths,
                                         engine=engine,
                                         main=not psy.gcp(),
                                         encoding=encoding,
                                         enable_post=enable_post)
            if isinstance(project, six.string_types):
                p.attrs.setdefault('project_file', project)
        else:
            self.new_plots(False)
            self.plot_creator.open_dataset(fnames,
                                           engine=engine,
                                           concat_dim=concat_dim)
            self.plot_creator.insert_array(name)
            if dims is not None:
                self.plot_creator.array_table.selectAll()
                self.plot_creator.array_table.update_selected(
                    dims={
                        key: ', '.join(map(str, val))
                        for key, val in six.iteritems(dims)
                    })
            if plot_method:
                self.plot_creator.pm_combo.setCurrentText(plot_method)
            self.plot_creator.exec_()
예제 #4
0
def make_plot(fnames=[],
              name=[],
              dims=None,
              plot_method=None,
              output=None,
              project=None,
              engine=None,
              formatoptions=None,
              tight=False,
              rc_file=None,
              encoding=None,
              enable_post=False,
              seaborn_style=None,
              output_project=None,
              concat_dim=get_default_value(xr.open_mfdataset, 'concat_dim'),
              chname={}):
    """
    Eventually start the QApplication or only make a plot

    Parameters
    ----------
    fnames: list of str
        Either the filenames to show, or, if the `project` parameter is set,
        the a list of `,`-separated filenames to make a mapping from the
        original filename to a new one
    name: list of str
        The variable names to plot if the `output` parameter is set
    dims: dict
        A mapping from coordinate names to integers if the `project` is not
        given
    plot_method: str
        The name of the plot_method to use
    output: str or list of str
        If set, the data is loaded and the figures are saved to the specified
        filename and now graphical user interface is shown
    project: str
        If set, the project located at the given file name is loaded
    engine: str
        The engine to use for opening the dataset (see
        :func:`psyplot.data.open_dataset`)
    formatoptions: dict
        A dictionary of formatoption that is applied to the data visualized by
        the chosen `plot_method`
    tight: bool
        If True/set, it is tried to figure out the tight bbox of the figure and
        adjust the paper size of the `output` to it
    rc_file: str
        The path to a yaml configuration file that can be used to update  the
        :attr:`~psyplot.config.rcsetup.rcParams`
    encoding: str
        The encoding to use for loading the project. If None, it is
        automatically determined by pickle. Note: Set this to ``'latin1'``
        if using a project created with python2 on python3.
    enable_post: bool
        Enable the :attr:`~psyplot.plotter.Plotter.post` processing
        formatoption. If True/set, post processing scripts are enabled in the
        given `project`. Only set this if you are sure that you can trust the
        given project file because it may be a security vulnerability.
    seaborn_style: str
        The name of the style of the seaborn package that can be used for
        the :func:`seaborn.set_style` function
    output_project: str
        The name of a project file to save the project to
    concat_dim: str
        The concatenation dimension if multiple files in `fnames` are
        provided
    chname: dict
        A mapping from variable names in the project to variable names in the
        datasets that should be used instead
    """
    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!')
    if rc_file is not None:
        rcParams.load_from_file(rc_file)

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

    if len(output) == 1:
        output = output[0]
    if not fnames and not project:
        raise ValueError(
            "Either a filename or a project file must be provided if "
            "the output parameter is set!")
    elif project is None and plot_method is None:
        raise ValueError(
            "A plotting method must be provided if the output parameter "
            "is set and not the project!")
    if seaborn_style is not None:
        import seaborn as sns
        sns.set_style(seaborn_style)
    import psyplot.project as psy
    if project is not None:
        fnames = [s.split(',') for s in fnames]
        chname = dict(chname)
        single_files = (l[0] for l in fnames if len(l) == 1)
        alternative_paths = defaultdict(lambda: next(single_files, None))
        alternative_paths.update([l for l in fnames if len(l) == 2])
        p = psy.Project.load_project(project,
                                     alternative_paths=alternative_paths,
                                     engine=engine,
                                     encoding=encoding,
                                     enable_post=enable_post,
                                     chname=chname)
        if formatoptions is not None:
            p.update(fmt=formatoptions)
        p.export(output, tight=tight)
    else:
        pm = getattr(psy.plot, plot_method, None)
        if pm is None:
            raise ValueError("Unknown plot method %s!" % plot_method)
        kwargs = {'name': name} if name else {}
        p = pm(fnames,
               dims=dims or {},
               engine=engine,
               fmt=formatoptions or {},
               mf_mode=True,
               concat_dim=concat_dim,
               **kwargs)
        p.export(output, tight=tight)
    if output_project is not None:
        p.save_project(output_project)
    return
예제 #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,
              concat_dim=get_default_value(xr.open_mfdataset, 'concat_dim'),
              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, 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.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.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
    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, concat_dim=concat_dim)

    # Lock file creation
    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)

    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)
        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)
    mainwindow = MainWindow.run(fnames, project, engine, plot_method, name,
                                dims, encoding, enable_post, seaborn_style,
                                concat_dim)
    if script is not None:
        mainwindow.console.run_script_in_shell(script)
    if command is not None:
        mainwindow.console.kernel_manager.kernel.shell.run_code(command)
    if exec_:
        sys.exit(app.exec_())
    else:
        return mainwindow
예제 #6
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
예제 #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