def run_code(self): """Run the update of the project inside the :attr:`shell`""" if self.line_edit.isVisible(): text = str(self.line_edit.text()) else: text = str(self.text_edit.toPlainText()) if not text or not self.fmtos: return group_ind = self.group_combo.currentIndex() if self.groups[group_ind] == COORDSGROUP: key = self.fmtos[group_ind][self.fmt_combo.currentIndex()] param = 'dims' else: key = self.fmtos[group_ind][self.fmt_combo.currentIndex()].key param = 'fmt' if self.yaml_cb.isChecked(): import psyplot.project as psy psy.gcp().update(**{key: yaml.load(text)}) else: code = "psy.gcp().update(%s={'%s': %s})" % (param, key, text) if ExecutionInfo is not None: info = ExecutionInfo(raw_cell=code, store_history=False, silent=True, shell_futures=False) e = ExecutionResult(info) else: e = ExecutionResult() self.console.run_command_in_shell(code, e) try: e.raise_error() except Exception: # reset the console and clear the error message raise finally: self.console.reset()
def refresh_plots_item(self, item, vname, mp=None, sp=None): expand = item.isExpanded() item.takeChildren() try: num = self.ds().psy.num except AttributeError: return if mp is None: mp = gcp(True) if sp is None: sp = gcp() for i in range(len(mp)): sub = mp[i:i + 1] array_info = sub.array_info(ds_description={'arr', 'num'}) arrs = sub._get_ds_descriptions(array_info).get(num, {}) if arrs and any(vname in arr.psy.base_variables for arr in arrs['arr']): child = QTreeWidgetItem(0) prefix = '*' if sub[0] in sp else '' text = sub[0].psy._short_info() child.setText(0, prefix + text) child.setToolTip(0, text) item.addChild(child) if expand and item.childCount(): item.setExpanded(True)
def add_datasets_from_cp(self, project): """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 # 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: ds_desc['fname'] = osp.basename(ds_desc['fname']) top_item.setText(0, '%s%i: %s' % ( '*' if any(arr in sp_arrs for arr in ds_desc['arr']) else '', i, ds_desc['fname'])) top_item.setToolTip(0, str(ds_desc['ds'])) for arr in ds_desc['arr']: arr.onbasechange.connect(self.add_datasets_from_cp) self.addTopLevelItem(top_item)
def run_code(self): """Run the update of the project inside the :attr:`shell`""" if self.line_edit.isVisible(): text = str(self.line_edit.text()) else: text = str(self.text_edit.toPlainText()) if not text or not self.fmtos: return group_ind = self.group_combo.currentIndex() if self.groups[group_ind] == COORDSGROUP: key = self.fmtos[group_ind][self.fmt_combo.currentIndex()] param = 'dims' else: key = self.fmtos[group_ind][self.fmt_combo.currentIndex()].key param = 'fmt' if self.yaml_cb.isChecked(): import psyplot.project as psy psy.gcp().update(**{key: yaml.load(text, Loader=yaml.Loader)}) else: code = "psy.gcp().update(%s={'%s': %s})" % (param, key, text) if ExecutionInfo is not None: info = ExecutionInfo(raw_cell=code, store_history=False, silent=True, shell_futures=False) e = ExecutionResult(info) else: e = ExecutionResult() self.console.run_command_in_shell(code, e) try: e.raise_error() except Exception: # reset the console and clear the error message raise finally: self.console.reset()
def load_fmt_widget(self, i): """Load the formatoption specific widget This method loads the formatoption specific widget from the :meth:`psyplot.plotter.Formatoption.get_fmt_widget` method and displays it above the :attr:`line_edit` Parameters ---------- i: int The index of the current formatoption""" self.remove_fmt_widget() group_ind = self.group_combo.currentIndex() if not self.no_fmtos_update: from psyplot.project import gcp if self.groups[group_ind] == COORDSGROUP: dim = self.fmtos[group_ind][i] self.fmt_widget = self.dim_widget self.dim_widget.set_dim(dim) self.dim_widget.set_single_selection( dim not in gcp()[0].dims) self.dim_widget.setVisible(True) else: fmto = self.fmtos[group_ind][i] self.fmt_widget = fmto.get_fmt_widget(self, gcp()) if self.fmt_widget is not None: self.vbox.insertWidget(2, self.fmt_widget)
def load_fmt_widget(self, i): """Load the formatoption specific widget This method loads the formatoption specific widget from the :meth:`psyplot.plotter.Formatoption.get_fmt_widget` method and displays it above the :attr:`line_edit` Parameters ---------- i: int The index of the current formatoption""" self.remove_fmt_widget() group_ind = self.group_combo.currentIndex() if not self.no_fmtos_update: from psyplot.project import gcp if self.groups[group_ind] == COORDSGROUP: dim = self.fmtos[group_ind][i] self.fmt_widget = self.dim_widget self.dim_widget.set_dim(dim) self.dim_widget.set_single_selection(dim not in gcp()[0].dims) self.dim_widget.setVisible(True) else: fmto = self.fmtos[group_ind][i] self.fmt_widget = fmto.get_fmt_widget(self, gcp()) if self.fmt_widget is not None: self.vbox.insertWidget(2, self.fmt_widget)
def update_cp(self, *args, **kwargs): """Update the current project from what is selected in this list""" if not self._no_project_update: mp = gcp(True) sp = gcp() selected = [item.arr.arr_name for item in self.selectedItems()] other_selected = [ arr.arr_name for arr in sp if arr not in self.arrays] with self._no_project_update: scp(mp(arr_name=selected + other_selected))
def update_from_project(self, project): """Update the content from the given Project Parameters ---------- project: psyplot.project.Project If the project is a main project, new items will be added. Otherwise only the current selection changes""" if self._no_project_update: return if not self.can_import_plotter: # remove the current items self.disconnect_items() return attr = self.project_attribute # stop if the module of the plotter has not yet been imported if attr and Project._registered_plotters[attr][0] not in sys.modules: return try: arrays = project if not attr else getattr(project, attr) mp = gcp(True) if project is None else project.main main_arrays = mp if not attr else getattr(mp, attr) except ImportError: # plotter could not be loaded self.is_empty = True self.can_import_plotter = False return self.is_empty = not bool(main_arrays) with self._no_project_update: if project is None: for item in self.array_items: item.setSelected(False) elif project.is_main: old_arrays = self.arrays # remove outdated items i = 0 for arr in old_arrays: if arr not in arrays: item = self.takeItem(i) item.disconnect_from_array() else: i += 1 # add new items for arr in arrays: if arr not in old_arrays: item = ArrayItem(weakref.ref(arr.psy), parent=self) self.addItem(item) # resort to match the project for arr in reversed(main_arrays): for i, item in enumerate(self.array_items): if item.arr() is arr.psy: self.insertItem(0, self.takeItem(i)) cp = gcp() for item in self.array_items: item.setSelected(getattr(item.arr(), 'arr', item.arr()) in cp) self.updated_from_project.emit(self)
def test_unselect_all_button(self): """Test whether the subproject is changed cleared when unselecting all """ self.window.showMaximized() psy.plot.plot2d(self.get_file('test-t2m-u-v.nc'), name='t2m', time=[0, 1]) # test whether the current subproject is not empty self.assertTrue(bool(psy.gcp())) # unselect all QTest.mouseClick(self.project_content.unselect_button, Qt.LeftButton) self.assertFalse(bool(psy.gcp()))
def update_cp(self, *args, **kwargs): """Update the current project from what is selected in this list""" if not self._no_project_update: mp = gcp(True) sp = gcp() selected = [item.arr().arr_name for item in self.selectedItems()] arrays = self.arrays other_selected = [ arr.psy.arr_name for arr in sp if arr not in arrays ] with self._no_project_update: scp(mp(arr_name=selected + other_selected))
def test_item_selection(self): """Test whether the subproject is changed correctly if the selection in the list changes""" sp = psy.plot.plot2d(self.get_file('test-t2m-u-v.nc'), name='t2m', time=[0, 1]) self.assertIs(psy.gcp()[0], sp[0]) self.assertIs(psy.gcp()[1], sp[1]) self.content_widget.lists['All'].item(0).setSelected(False) self.assertIs(psy.gcp()[0], sp[1]) self.content_widget.lists['All'].item(0).setSelected(True) self.assertIs(psy.gcp()[0], sp[0], msg='Reselection failed!') self.assertIs(psy.gcp()[1], sp[1], msg='Reselection failed!')
def test_select_all_button(self): """Test whether the subproject is changed correctly when selecting all """ self.window.showMaximized() sp = psy.plot.plot2d(self.get_file('test-t2m-u-v.nc'), name='t2m', time=[0, 1]) psy.scp(None) QTest.mouseClick(self.project_content.select_all_button, Qt.LeftButton) self.assertIs(psy.gcp()[0], sp[0], msg='actual: %s, expected: %s' % (psy.gcp(), sp)) self.assertIs(psy.gcp()[1], sp[1]) self.assertEqual(self._selected_rows('All'), [0, 1], msg='Not all arrays selected!')
def test_main_03_dims(self): import yaml psy.register_plotter('test_plotter', module='test_plotter', plotter_name='TestPlotter') fname2 = tempfile.NamedTemporaryFile( suffix='.pdf', prefix='test_psyplot_').name self._created_files.add(fname2) # create a formatoptions file fmt_file = tempfile.NamedTemporaryFile( suffix='.yml', prefix='test_psyplot_').name self._created_files.add(fmt_file) with open(fmt_file, 'w') as f: yaml.dump({'fmt1': 'fmt1', 'fmt2': 'fmt2'}, f) if not six.PY2: with self.assertRaisesRegex(ValueError, 'plotting method'): main.main([bt.get_file('test-t2m-u-v.nc'), '-o', fname2, '-d', 'time,1,2', 'y,3,4', '-n', 'u', 'v']) main.main([bt.get_file('test-t2m-u-v.nc'), '-o', fname2, '-d', 'time,1,2', 'y,3,4', '-n', 'u', 'v', '-pm', 'test_plotter', '-fmt', fmt_file]) mp = psy.gcp(True) self.assertEqual(len(mp), 2*2*2, msg=mp) all_dims = set(product((1, 2), (3, 4), ('u', 'v'))) for arr in mp: idims = arr.psy.idims all_dims -= {(idims['time'], idims['lat'], arr.name)} self.assertFalse(all_dims) for i, plotter in enumerate(mp.plotters): self.assertEqual(plotter['fmt1'], 'fmt1', msg='Wrong value for fmt1 of plotter %i!' % i) self.assertEqual(plotter['fmt2'], 'fmt2', msg='Wrong value for fmt2 of plotter %i!' % i)
def create_project(self, ds): import psyplot.project as psy def get_key(nml_key): return nml_key if nml_key not in errs else nml_key + '_flag' vmeta = self.variables_meta variables = ds.vname.values indicators = self.task_config.indicators nml = self.namelist errs = self.err_nml_keys vmeta = OrderedDict([(key, vmeta[key]) for key in ds.vname.values]) for nml_key in nml: for i, variable in enumerate(variables): for ind in indicators: other_keys = { key: range(ds[key].size) for key in map(get_key, set(nml) - {nml_key}) } label = ', '.join(map('{0}=%({0})s'.format, other_keys)) other_keys['vname'] = i fmt = self.fmt.copy() psy.plot.lineplot( ds, name=ind, dims=other_keys, fmt=fmt, coord=nml_key, legendlabels=label, attrs={'vname_long': vmeta.get(variable)}) return psy.gcp(True)[:]
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
def add_mp_to_menu(self): mp = psy.gcp(True) action = QAction(os.path.basename(mp.attrs.get( 'project_file', 'Untitled %s*' % mp.num)), self) action.setStatusTip( 'Make project %s the current project' % mp.num) action.triggered.connect(lambda: psy.scp(psy.project(mp.num))) self.project_actions[mp.num] = action self.windows_menu.addAction(action)
def add_mp_to_menu(self): mp = psy.gcp(True) action = QAction( os.path.basename( mp.attrs.get('project_file', 'Untitled %s*' % mp.num)), self) action.setStatusTip('Make project %s the current project' % mp.num) action.triggered.connect(lambda: psy.scp(psy.project(mp.num))) self.project_actions[mp.num] = action self.windows_menu.addAction(action)
def get_ds(self): import psyplot.project as psy project = psy.gcp() datasets = project.datasets dim = self.dim dims = {ds.coords[dim].shape[0]: ds for ds in datasets.values()} if len(dims) > 1: warn("Datasets have differing dimensions lengths for the " "%s dimension!" % dim) return min(dims.items())[1]
def set_current_fmt_value(self, i): """Add the value of the current formatoption to the line text""" group_ind = self.group_combo.currentIndex() if not self.no_fmtos_update: if self.groups[group_ind] == COORDSGROUP: from psyplot.project import gcp dim = self.fmtos[group_ind][i] self.set_obj(gcp().arrays[0].psy.idims[dim]) else: fmto = self.fmtos[group_ind][i] self.set_obj(fmto.value)
def test_save_and_load(self): """Test project reproducability through the save and load method""" plt.close('all') maps = psy.plot.mapplot(get_file('test-t2m-u-v.nc'), name='t2m', time=[1, 2], ax=(2, 2)) maps[0].update(cmap='winter', bounds='minmax') maps.share(keys='bounds') grid_ax = plt.subplot2grid((2, 2), (1, 0), 1, 2) lines = psy.plot.lineplot(get_file('icon_test.nc'), name='u', x=0, time=range(5), ax=grid_ax) plt.savefig(os.path.join(bt.ref_dir, self.get_ref_file('save_load1'))) plt.figure() ax = plt.axes(maps[0].plotter.ax.get_position()) psy.plot.lineplot(get_file('icon_test.nc'), name='t2m', z=0, x=0, ax=[ax]) fname = os.path.join(bt.ref_dir, self.get_ref_file('save_load2')) plt.savefig(fname) p = psy.gcp(True) p.save_project(fname + '.pkl', use_rel_paths=False) p.close(True, True) plt.close('all') p = psy.Project.load_project(fname + '.pkl') plt.figure(1) self.compare_figures(self.get_ref_file('save_load1')) plt.figure(2) self.compare_figures(self.get_ref_file('save_load2')) p.close(True, True) plt.close('all') maps = psy.plot.mapplot(get_file('icon_test.nc'), name='t2m', time=[1, 2], ax=(2, 2)) maps[0].update(cmap='winter', bounds='minmax') maps.share(keys='bounds') grid_ax = plt.subplot2grid((2, 2), (1, 0), 1, 2) lines = psy.plot.lineplot(get_file('icon_test.nc'), name='u', x=0, time=range(5), ax=grid_ax) plt.savefig(os.path.join(bt.ref_dir, self.get_ref_file('save_load3'))) p.close(True, True) plt.close('all') p = psy.Project.load_project(fname + '.pkl', alternative_paths={ get_file('test-t2m-u-v.nc'): get_file('icon_test.nc')}) plt.figure(1) self.compare_figures(self.get_ref_file('save_load3')) plt.figure(2) self.compare_figures(self.get_ref_file('save_load2')) p.close(True, True) plt.close('all') os.remove(fname + '.pkl') for i in range(1, 4): os.remove(os.path.join( bt.ref_dir, self.get_ref_file('save_load%i' % i)))
def __init__(self, plotter_type=None, *args, **kwargs): """ Parameters ---------- plotter_type: str or None If str, it mus be an attribute name of the :class:`psyplot.project.Project` class. Otherwise the full project is used ``*args,**kwargs`` Are determined by the parent class Notes ----- When initialized, the content of the list is determined by ``gcp(True)`` and ``gcp()``""" super(PlotterList, self).__init__(*args, **kwargs) self.project_attribute = plotter_type self.setSelectionMode(QAbstractItemView.MultiSelection) self.itemSelectionChanged.connect(self.update_cp) self.update_from_project(gcp(True)) self.update_from_project(gcp())
def __init__(self, plotter_type=None, *args, **kwargs): """ Parameters ---------- plotter_type: str or None If str, it mus be an attribute name of the :class:`psyplot.project.Project` class. Otherwise the full project is used ``*args,**kwargs`` Are determined by the parent class Notes ----- When initialized, the content of the list is determined by ``gcp(True)`` and ``gcp()``""" super(PlotterList, self).__init__(*args, **kwargs) self.project_attribute = plotter_type self.setSelectionMode(QAbstractItemView.MultiSelection) self.itemSelectionChanged.connect(self.update_cp) Project.oncpchange.connect(self.update_from_project) self.update_from_project(gcp(True)) self.update_from_project(gcp())
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)
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_()
def test_mp_sp(self): """Test whether the mp and sp variables are set correctly""" from xarray import DataArray psy.Project.oncpchange.emit(psy.gcp(True)) psy.Project.oncpchange.emit(psy.gcp()) self.assertIs(self.window.console.get_obj('mp')[1], psy.gcp(True)) self.assertIs(self.window.console.get_obj('sp')[1], psy.gcp()) sp = psy.plot.lineplot(DataArray([1, 2, 3], name='test').to_dataset()) self.assertIs(self.window.console.get_obj('mp')[1], psy.gcp(True)) self.assertIs(self.window.console.get_obj('sp')[1], sp) sp.close(True, True) self.assertIs(self.window.console.get_obj('mp')[1], psy.gcp(True)) self.assertIs(self.window.console.get_obj('sp')[1], psy.gcp())
def __init__(self, *args, **kwargs): super(ProjectContentWidget, self).__init__(*args, **kwargs) vbox = QVBoxLayout() # create buttons for unselecting and selecting all arrays self.unselect_button = SelectNoneButton('Unselect all', parent=self) self.select_all_button = SelectAllButton('Select all', parent=self) button_hbox = QHBoxLayout() button_hbox.addWidget(self.unselect_button) button_hbox.addWidget(self.select_all_button) mp = gcp(True) self.unselect_button.setEnabled(bool(mp)) self.select_all_button.setEnabled(bool(mp)) # create widget showing the content of the current project self.content_widget = ProjectContent(parent=self) vbox.addLayout(button_hbox) vbox.addWidget(self.content_widget) self.setLayout(vbox)
def __init__(self, *args, **kwargs): super(ProjectContentWidget, self).__init__(*args, **kwargs) vbox = QVBoxLayout() # create buttons for unselecting and selecting all arrays self.unselect_button = SelectNoneButton('Unselect all', parent=self) self.select_all_button = SelectAllButton('Select all', parent=self) button_hbox = QHBoxLayout() button_hbox.addWidget(self.unselect_button) button_hbox.addWidget(self.select_all_button) sp = gcp(True) self.unselect_button.setEnabled(bool(sp)) self.select_all_button.setEnabled(bool(sp)) # create widget showing the content of the current project self.content_widget = ProjectContent(parent=self) vbox.addLayout(button_hbox) vbox.addWidget(self.content_widget) self.setLayout(vbox)
def test_main_02_alternative_ds(self): sp, fname1 = self._create_and_save_test_project() fname2 = tempfile.NamedTemporaryFile( suffix='.pdf', prefix='test_psyplot_').name self._created_files.add(fname2) sp.save_project(fname1, use_rel_paths=False) psy.close('all') main.main([bt.get_file('circumpolar_test.nc'), '-p', fname1, '-o', fname2]) self.assertTrue(osp.exists(fname2), msg='Missing ' + fname2) mp = psy.gcp(True) self.assertEqual(len(mp), 4) self.assertEqual( set(t[0] for t in mp._get_dsnames(mp.array_info( dump=False, use_rel_paths=False))), {bt.get_file('circumpolar_test.nc')})
def test_make_plot(self): """Test the making of plots""" fname = self.get_file('test-t2m-u-v.nc') sp1 = psy.plot.plot2d(fname, name='t2m') # to make sure, have in the mean time another dataset in the current # subproject, we create a second plot psy.plot.plot2d(fname, name='t2m') ds = sp1[0].psy.base name = 't2m' self.tree.make_plot(ds, name) try: self.window.plot_creator.pm_combo.setCurrentText('plot2d') except AttributeError: self.window.plot_creator.pm_combo.setEditText('plot2d') QTest.mouseClick( self.window.plot_creator.bbox.button(QDialogButtonBox.Ok), Qt.LeftButton) self.assertIs(ds, psy.gcp()[0].psy.base)
def test_main_01_from_project(self): """Test the :func:`psyplot.__main__.main` function""" if not six.PY2: with self.assertRaisesRegex(ValueError, 'filename'): main.main(['-o', 'test.pdf']) sp, fname1 = self._create_and_save_test_project() fname2 = tempfile.NamedTemporaryFile( suffix='.pdf', prefix='test_psyplot_').name self._created_files.add(fname2) sp.save_project(fname1, use_rel_paths=False) psy.close('all') if six.PY2: main.main(['-p', fname1, '-o', fname2]) else: with self.assertWarnsRegex(UserWarning, 'ignored'): main.main(['-p', fname1, '-o', fname2, '-n', 't2m']) self.assertTrue(osp.exists(fname2), msg='Missing ' + fname2) self.assertEqual(len(psy.gcp(True)), 4)
def test_reload(qtbot, test_dir, tmp_path) -> None: """Test the reload button.""" import psyplot.project as psy from psy_view.ds_widget import DatasetWidget f1, f2 = "regular-test.nc", "regional-icon-test.nc" shutil.copy(osp.join(test_dir, f1), str(tmp_path / f1)) ds_widget = DatasetWidget(psy.open_dataset(str(tmp_path / f1))) qtbot.addWidget(ds_widget) qtbot.mouseClick(ds_widget.variable_buttons['t2m'], Qt.LeftButton) assert ds_widget.ds_tree.topLevelItemCount() == 1 assert ds_widget.ds["t2m"].ndim == 4 # now copy the icon file to the same destination and reload everything shutil.copy(osp.join(test_dir, f2), str(tmp_path / f1)) ds_widget.reload() assert ds_widget.ds_tree.topLevelItemCount() == 1 assert ds_widget.ds["t2m"].ndim == 3 assert len(psy.gcp(True)) == 1
def create_project(self, ds): import psyplot.project as psy import seaborn as sns sns.set_style('white') for name, (vref, vsim) in zip(self.names, self.all_variables): self.logger.debug('Creating plots of %s', vsim) kwargs = dict(precision=0.1) if vref.startswith('prcp') else {} psy.plot.densityreg(ds, name='all_' + vsim, coord='all_' + vref, fmt=self.fmt, title='All percentiles', arr_names=['%s_all' % name], **kwargs) arr_names = ['%s_%1.2f' % (name, p) for p in ds.pctl.values] psy.plot.densityreg(ds, name=vsim, coord=vref, fmt=self.fmt, arr_names=arr_names, pctl=range(ds.pctl.size), **kwargs) return psy.gcp(True)[:]
def __init__(self): super(MainWindow, self).__init__() #: list of figures from the psyplot backend self.figures = [] self.error_msg = PyErrorMessage(self) self.setDockOptions( QMainWindow.AnimatedDocks | QMainWindow.AllowNestedDocks | QMainWindow.AllowTabbedDocks) #: Inprocess console self.console = ConsoleWidget(parent=self) self.project_actions = {} # --------------------------------------------------------------------- # ----------------------------- Menus --------------------------------- # --------------------------------------------------------------------- # ######################## File menu ################################## # --------------------------- New plot -------------------------------- self.file_menu = QMenu('File', parent=self) self.new_plot_action = QAction('New plot', self) self.new_plot_action.setStatusTip( 'Use an existing dataset (or open a new one) to create one or ' 'more plots') self.new_plot_action.setShortcut(QKeySequence.New) self.new_plot_action.triggered.connect(self.new_plots) self.file_menu.addAction(self.new_plot_action) # --------------------------- Open project ---------------------------- self.open_project_menu = QMenu('Open project', self) self.file_menu.addMenu(self.open_project_menu) self.open_mp_action = QAction('New main project', self) self.open_mp_action.setShortcut(QKeySequence.Open) self.open_mp_action.setStatusTip('Open a new main project') self.open_mp_action.triggered.connect(self.open_mp) self.open_project_menu.addAction(self.open_mp_action) self.open_sp_action = QAction('Add to current', self) self.open_sp_action.setShortcut(QKeySequence( 'Ctrl+Shift+O', QKeySequence.NativeText)) self.open_sp_action.setStatusTip( 'Load a project as a sub project and add it to the current main ' 'project') self.open_sp_action.triggered.connect(self.open_sp) self.open_project_menu.addAction(self.open_sp_action) # ----------------------- Save project -------------------------------- self.save_project_menu = QMenu('Save project', parent=self) self.file_menu.addMenu(self.save_project_menu) self.save_mp_action = QAction('All', self) self.save_mp_action.setStatusTip( 'Save the entire project into a pickle file') self.save_mp_action.setShortcut(QKeySequence.Save) self.save_mp_action.triggered.connect(self.save_mp) self.save_project_menu.addAction(self.save_mp_action) self.save_sp_action = QAction('Selected', self) self.save_sp_action.setStatusTip( 'Save the selected sub project into a pickle file') self.save_sp_action.triggered.connect(self.save_sp) self.save_project_menu.addAction(self.save_sp_action) # ------------------------ Save project as ---------------------------- self.save_project_menu = QMenu('Save project', parent=self) self.file_menu.addMenu(self.save_project_menu) self.save_project_as_menu = QMenu('Save project as', parent=self) self.file_menu.addMenu(self.save_project_as_menu) self.save_mp_as_action = QAction('All', self) self.save_mp_as_action.setStatusTip( 'Save the entire project into a pickle file') self.save_mp_as_action.setShortcut(QKeySequence.SaveAs) self.save_mp_as_action.triggered.connect( partial(self.save_mp, new_name=True)) self.save_project_as_menu.addAction(self.save_mp_as_action) self.save_sp_as_action = QAction('Selected', self) self.save_sp_as_action.setStatusTip( 'Save the selected sub project into a pickle file') self.save_sp_as_action.triggered.connect( partial(self.save_sp, new_name=True)) self.save_project_as_menu.addAction(self.save_sp_as_action) # -------------------------- Pack project ----------------------------- self.pack_project_menu = QMenu('Zip project files', parent=self) self.file_menu.addMenu(self.pack_project_menu) self.pack_mp_action = QAction('All', self) self.pack_mp_action.setStatusTip( 'Pack all the data of the main project into one folder') self.pack_mp_action.triggered.connect(partial(self.save_mp, pack=True)) self.pack_project_menu.addAction(self.pack_mp_action) self.pack_sp_action = QAction('Selected', self) self.pack_sp_action.setStatusTip( 'Pack all the data of the current sub project into one folder') self.pack_sp_action.triggered.connect(partial(self.save_sp, pack=True)) self.pack_project_menu.addAction(self.pack_sp_action) # ------------------------ Export figures ----------------------------- self.export_project_menu = QMenu('Export figures', parent=self) self.file_menu.addMenu(self.export_project_menu) self.export_mp_action = QAction('All', self) self.export_mp_action.setStatusTip( 'Pack all the data of the main project into one folder') self.export_mp_action.triggered.connect(self.export_mp) self.export_mp_action.setShortcut(QKeySequence( 'Ctrl+E', QKeySequence.NativeText)) self.export_project_menu.addAction(self.export_mp_action) self.export_sp_action = QAction('Selected', self) self.export_sp_action.setStatusTip( 'Pack all the data of the current sub project into one folder') self.export_sp_action.setShortcut(QKeySequence( 'Ctrl+Shift+E', QKeySequence.NativeText)) self.export_sp_action.triggered.connect(self.export_sp) self.export_project_menu.addAction(self.export_sp_action) # ------------------------ Close project ------------------------------ self.file_menu.addSeparator() self.close_project_menu = QMenu('Close project', parent=self) self.file_menu.addMenu(self.close_project_menu) self.close_mp_action = QAction('Main project', self) self.close_mp_action.setStatusTip( 'Close the main project and delete all data and plots out of ' 'memory') self.close_mp_action.setShortcut(QKeySequence.Close) self.close_mp_action.triggered.connect( lambda: psy.close(psy.gcp(True).num)) self.close_project_menu.addAction(self.close_mp_action) self.close_sp_action = QAction('Only selected', self) self.close_sp_action.setStatusTip( 'Close the selected arrays project and delete all data and plots ' 'out of memory') self.close_sp_action.setShortcut(QKeySequence( 'Ctrl+Shift+W', QKeySequence.NativeText)) self.close_sp_action.triggered.connect( lambda: psy.gcp().close(True, True)) self.close_project_menu.addAction(self.close_sp_action) # ------------------------ Quit ------------------------------ if sys.platform != 'darwin': # mac os makes this anyway self.quit_action = QAction('Quit', self) self.quit_action.triggered.connect( QtCore.QCoreApplication.instance().quit) self.quit_action.setShortcut(QKeySequence.Quit) self.file_menu.addAction(self.quit_action) self.menuBar().addMenu(self.file_menu) # ######################## Console menu ############################### self.console_menu = QMenu('Console', self) self.console_menu.addActions(self.console.actions()) self.menuBar().addMenu(self.console_menu) # ######################## Windows menu ############################### self.windows_menu = QMenu('Windows', self) self.menuBar().addMenu(self.windows_menu) # --------------------------------------------------------------------- # -------------------------- Dock windows ----------------------------- # --------------------------------------------------------------------- #: tab widget displaying the arrays in current main and sub project self.project_content = ProjectContentWidget(parent=self) self.addDockWidget(Qt.LeftDockWidgetArea, self.project_content.to_dock('Plot objects', self), 'pane') #: tree widget displaying the open datasets self.ds_tree = DatasetTree(parent=self) self.addDockWidget(Qt.LeftDockWidgetArea, self.ds_tree.to_dock( 'Datasets', self), 'pane') #: tree widget displaying the open figures self.figures_tree = FiguresTree(parent=self) self.addDockWidget(Qt.LeftDockWidgetArea, self.figures_tree.to_dock( 'Figures', self), 'pane') #: help explorer self.help_explorer = help_explorer = HelpExplorer(parent=self) self.addDockWidget(Qt.RightDockWidgetArea, help_explorer.to_dock( 'Help explorer', self), 'pane') #: general formatoptions widget self.fmt_widget = FormatoptionWidget( parent=self, help_explorer=help_explorer, shell=self.console.kernel_client.kernel.shell) self.addDockWidget(Qt.BottomDockWidgetArea, self.fmt_widget.to_dock( 'Formatoptions', self), 'pane') self.windows_menu.addSeparator() self.add_mp_to_menu() psy.Project.oncpchange.connect(self.eventually_add_mp_to_menu) # --------------------------------------------------------------------- # -------------------------- connections ------------------------------ # --------------------------------------------------------------------- self.console.help_explorer = help_explorer psyp.default_print_func = partial(help_explorer.show_rst, oname='formatoption_docs') psy._PlotterInterface._print_func = psyp.default_print_func self.setCentralWidget(self.console) # make sure that the plots are shown between the project content and # the help explorer widget self.setCorner(Qt.TopLeftCorner, Qt.LeftDockWidgetArea) self.setCorner(Qt.TopRightCorner, Qt.RightDockWidgetArea) # make sure that the formatoption widgets are shown between the # project content and the help explorer widget self.setCorner(Qt.BottomLeftCorner, Qt.LeftDockWidgetArea) self.setCorner(Qt.BottomRightCorner, Qt.RightDockWidgetArea) # Server to open external files on a single instance self.open_files_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP) self.showMaximized() self._file_thread = Thread(target=self.start_open_files_server) self._file_thread.setDaemon(True) self._file_thread.start() self.open_external.connect(self.open_external_files) # --------------------------------------------------------------------- # ------------------------------ closure ------------------------------ # --------------------------------------------------------------------- self.help_explorer.show_intro(self.console.intro_msg)
def save_mp(self, *args, **kwargs): """Save the current main project""" self._save_project(psy.gcp(True), **kwargs)
# In[ ]: maps.update(lonlatbox='Europe', datagrid='k-') maps.show() # The same works for vector data # In[ ]: vectors = psy.plot.mapvector( 'icon_grid_demo.nc', name=[['u', 'v']] * 2, projection='robin', ax=(1, 2), lonlatbox='Europe') vectors[0].update(arrowsize=100) vectors[1].update(plot='stream') # And combined scalar and vector fields # In[ ]: combined = psy.plot.mapcombined( 'icon_grid_demo.nc', name=[['t2m', ['u', 'v']]], projection='robin', lonlatbox='Europe', arrowsize=100, cmap='RdBu_r') # In[ ]: psy.gcp(True).close(True, True)
def save_sp(self, *args, **kwargs): """Save the current sub project""" self._save_project(psy.gcp(), **kwargs)
def export_mp(self, *args, **kwargs): self._export_project(psy.gcp(True), **kwargs)
def create_dataset_tree(self): """Set up the columns and insert the :class:`DatasetTreeItem` instances from the current project""" self.set_columns() self.add_datasets_from_cp(gcp())
def select_none(self): """Clear current subproject""" scp(gcp(True)[:0])
def select_all(self): """Select all arrays""" scp(gcp(True)[:])
# This example shows you how to make a line plot using the `psyplot.project.ProjectPlotter.lineplot` method. # In[ ]: import psyplot.project as psy # get_ipython().magic(u'matplotlib inline') # get_ipython().magic(u'config InlineBackend.close_figures = False') # In[ ]: axes = iter(psy.multiple_subplots(2, 2, n=3)) for var in ['t2m', 'u', 'v']: psy.plot.lineplot( 'demo.nc', # netCDF file storing the data name=var, # one plot for each variable t=range(5), # one violin plot for each time step z=0, x=0, # choose latitude and longitude as dimensions ylabel="{desc}", # use the longname and units on the y-axis ax=next(axes), color='coolwarm', legend=False ) lines = psy.gcp(True) lines.show() # In[ ]: lines.close(True, True)
def update_current_list(self): """Update the current list from the current main and sub project""" self.currentWidget().update_from_project(gcp(True)) self.currentWidget().update_from_project(gcp())
def __init__(self, *args, **kwargs): super(FiguresTree, self).__init__(*args, **kwargs) self.setHeaderLabel('Figure') Project.oncpchange.connect(self.add_figures_from_cp) self.add_figures_from_cp(gcp(True))
# This example shows you how to make a bar plot using the `psyplot.project.ProjectPlotter.barplot` method. # In[ ]: import psyplot.project as psy # get_ipython().magic(u'matplotlib inline') # get_ipython().magic(u'config InlineBackend.close_figures = False') # In[ ]: axes = iter(psy.multiple_subplots(2, 2, n=3)) for var in ['t2m', 'u', 'v']: psy.plot.barplot( 'demo.nc', # netCDF file storing the data name=var, # one plot for each variable y=[0, 1], # two bars in total z=0, x=0, # choose latitude and longitude as dimensions ylabel="{desc}", # use the longname and units on the y-axis ax=next(axes), color='coolwarm', legend=False, xticklabels='%B %Y' ) bars = psy.gcp(True) bars.show() # In[ ]: bars.close(True, True)
def enable_from_project(self, project): """Enable the button if the given project is not empty""" self.setEnabled(bool(project.main if project is not None else gcp(1)))
def export_sp(self, *args, **kwargs): self._export_project(psy.gcp(), **kwargs)
def refill_from_rc(self, sort_by_key): from psyplot.project import gcp self.fill_combos_from_project(gcp())