def __init__(self, parent): QMainWindow.__init__(self, parent) loadUi(self, 'browse.ui') self.logger = logger.getChild('browse') self.dataloader = parent self.rootdir = '' self.loader = Loader() self._data = {} self.yaxis = None self.canvas = MPLCanvas(self) self.canvas.plotter.lines = True self.toolbar = MPLToolbar(self.canvas, self) self.toolbar.setObjectName('browsetoolbar') self.addToolBar(self.toolbar) layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(self.canvas) self.plotframe.setLayout(layout) self.sgroup = SettingGroup('browse') with self.sgroup as settings: geometry = settings.value('geometry', QByteArray()) self.restoreGeometry(geometry) windowstate = settings.value('windowstate', QByteArray()) self.restoreState(windowstate) splitstate = settings.value('splitstate', QByteArray()) self.splitter.restoreState(splitstate) self.monScaleEdit.setText(settings.value('fixedmonval'))
def __init__(self, parent): """ Constructing a basic QApplication """ QMainWindow.__init__(self, parent) self.sgroup = SettingGroup('main') self.ui = uic.loadUi(path.join(path.dirname(__file__), 'ui', 'qexplorer.ui'), self) self.addWidgets() self.ui.show() self.dir = path.dirname(__file__) self.pts = [] self.canvas = MPLCanvas(self) self.canvas.plotter.lines = True self.toolbar = MPLToolbar(self.canvas, self) self.toolbar.setObjectName('browsetoolbar') self.addToolBar(self.toolbar) self.v1 = [1, 0, 0] self.v2 = [0, 0, 1] layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(self.canvas) self.frmPlot.setLayout(layout) self.Reader = None # restore settings with self.sgroup as settings: data_template_path = settings.value('last_data_template', '') print(settings.value('test', '')) if data_template_path: dtempl, numor = extract_template(data_template_path) self.dir = dtempl self.ui.txtNumors.setText(str(numor)) print("directory set to", self.dir)
class FitterMain(QMainWindow): def __init__(self, model, data, fit=True, fit_kws={}): QMainWindow.__init__(self) layout = QSplitter(Qt.Vertical, self) self.canvas = MPLCanvas(self) self.toolbar = MPLToolbar(self.canvas, self) layout.addWidget(self.toolbar) layout.addWidget(self.canvas) self.fitter = Fitter(self, standalone=True, fit_kws=fit_kws) self.canvas.mpl_connect('button_press_event', self.fitter.on_canvas_pick) self.fitter.closeRequest.connect(self.close) self.fitter.replotRequest.connect(self.replot) self.fitter.initialize(model, data, fit) layout.addWidget(self.fitter) self.setCentralWidget(layout) self.setWindowTitle('Fitting: data %s' % data.name) def replot(self, limits=True): plotter = self.canvas.plotter plotter.reset(limits=limits) try: plotter.plot_data(self.fitter.data) plotter.plot_model_full(self.fitter.model, self.fitter.data) except Exception: logger.exception('Error while plotting') else: plotter.draw()
def __init__(self, model, data, fit=True, fit_kws={}): QMainWindow.__init__(self) layout = QSplitter(Qt.Vertical, self) self.canvas = MPLCanvas(self) self.toolbar = MPLToolbar(self.canvas, self) layout.addWidget(self.toolbar) layout.addWidget(self.canvas) self.fitter = Fitter(self, standalone=True, fit_kws=fit_kws) self.canvas.mpl_connect('button_press_event', self.fitter.on_canvas_pick) self.fitter.closeRequest.connect(self.close) self.fitter.replotRequest.connect(self.replot) self.fitter.initialize(model, data, fit) layout.addWidget(self.fitter) self.setCentralWidget(layout) self.setWindowTitle('Fitting: data %s' % data.name)
def on_actionPopOut_triggered(self): new_win = QMainWindow() canvas = MPLCanvas(new_win) toolbar = MPLToolbar(canvas, new_win) new_win.addToolBar(toolbar) splitter = QSplitter(Qt.Vertical, new_win) splitter.addWidget(canvas) try: from ufit.gui.console import QIPythonWidget except ImportError: lbl = QLabel( 'Please install IPython with qtconsole to ' 'activate the console part of this window.', new_win) splitter.addWidget(lbl) else: iw = QIPythonWidget('interactive pylab plotting prompt', new_win) iw.pushVariables({'ax': canvas.axes}) iw.executeCommand('from ufit.lab import *') iw.executeCommand('sca(ax)') iw.setFocus() iw.redrawme.connect(canvas.draw_idle) splitter.addWidget(iw) new_win.setCentralWidget(splitter) self.current_panel.plot(limits=None, canvas=canvas) new_win.show()
def __init__(self, data): QMainWindow.__init__(self) layout = QSplitter(Qt.Vertical, self) self.canvas = MPLCanvas(self) self.toolbar = MPLToolbar(self.canvas, self) layout.addWidget(self.toolbar) layout.addWidget(self.canvas) self.dloader = DataLoader(self, self.canvas.plotter, standalone=True) self.dloader.groupBox.hide() self.dloader.groupBoxLbl.hide() self.dloader.groupBoxDesc.hide() self.dloader.initialize() self.dloader.closeRequest.connect(self.close) layout.addWidget(self.dloader) self.setCentralWidget(layout) self.setWindowTitle('Data loading')
class BrowseWindow(QMainWindow): def __init__(self, parent): QMainWindow.__init__(self, parent) loadUi(self, 'browse.ui') self.logger = logger.getChild('browse') self.dataloader = parent self.rootdir = '' self.loader = Loader() self._data = {} self.yaxis = None self.canvas = MPLCanvas(self) self.canvas.plotter.lines = True self.toolbar = MPLToolbar(self.canvas, self) self.toolbar.setObjectName('browsetoolbar') self.addToolBar(self.toolbar) layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(self.canvas) self.plotframe.setLayout(layout) self.sgroup = SettingGroup('browse') with self.sgroup as settings: geometry = settings.value('geometry', QByteArray()) self.restoreGeometry(geometry) windowstate = settings.value('windowstate', QByteArray()) self.restoreState(windowstate) splitstate = settings.value('splitstate', QByteArray()) self.splitter.restoreState(splitstate) self.monScaleEdit.setText(settings.value('fixedmonval')) @pyqtSlot() def on_loadBtn_clicked(self): datas = [ self._data[item.type()] for item in self.dataList.selectedItems() ] if not datas: return items = [ScanDataItem(data) for data in datas] session.add_items(items) @pyqtSlot() def on_addNumBtn_clicked(self): numors = [ self._data[item.type()].meta['filenumber'] for item in self.dataList.selectedItems() ] if not numors: return self.dataloader.add_numors(sorted(numors)) @pyqtSlot() def on_dirBtn_clicked(self): newdir = QFileDialog.getExistingDirectory(self, 'New directory', self.rootdir) self.set_directory(path_to_str(newdir)) @pyqtSlot() def on_refreshBtn_clicked(self): self.set_directory(self.rootdir) @pyqtSlot() def on_monScaleBtn_clicked(self): self.set_directory(self.rootdir) @pyqtSlot() def on_yAxisBtn_clicked(self): self.set_directory(self.rootdir) def set_directory(self, root): self.setWindowTitle('ufit browser - %s' % root) self.canvas.axes.text(0.5, 0.5, 'Please wait, loading all data...', horizontalalignment='center') self.canvas.draw() QApplication.processEvents() self.rootdir = root files = os.listdir(root) self.dataList.clear() for fn in sorted(files): fn = path.join(root, fn) if not path.isfile(fn): continue try: t, n = extract_template(fn) self.loader.template = t fixed_yaxis = self.yAxisEdit.text() yaxis = fixed_yaxis if ( fixed_yaxis and self.useYAxis.isChecked()) else 'auto' res = self.loader.load(n, 'auto', yaxis, 'auto', 'auto', -1) except Exception as e: self.logger.warning('While loading %r: %s' % (fn, e)) else: if self.useMonScale.isChecked(): const = int(self.monScaleEdit.text()) # XXX check res.rescale(const) if self.useFmtString.isChecked(): try: scanLabel = self.fmtStringEdit.text().format( n, FormatWrapper(res)) except Exception: scanLabel = '%s (%s) - %s | %s' % ( n, res.xcol, res.title, ', '.join(res.environment)) else: scanLabel = '%s (%s) - %s | %s' % ( n, res.xcol, res.title, ', '.join(res.environment)) self._data[n] = res QListWidgetItem(scanLabel, self.dataList, n) self.canvas.axes.clear() self.canvas.draw() def on_dataList_itemSelectionChanged(self): numors = [item.type() for item in self.dataList.selectedItems()] if not numors: return plotter = self.canvas.plotter plotter.reset(False) if len(numors) > 1: for numor in numors: plotter.plot_data(self._data[numor], multi=True) plotter.plot_finish() else: plotter.plot_data(self._data[numors[0]]) plotter.draw() def closeEvent(self, event): event.accept() with self.sgroup as settings: settings.setValue('geometry', self.saveGeometry()) settings.setValue('windowstate', self.saveState()) settings.setValue('splitstate', self.splitter.saveState()) settings.setValue('fixedmonval', self.monScaleEdit.text())
class ReciprocalViewer(QMainWindow): def __init__(self, parent): """ Constructing a basic QApplication """ QMainWindow.__init__(self, parent) self.sgroup = SettingGroup('main') self.ui = uic.loadUi(path.join(path.dirname(__file__), 'ui', 'qexplorer.ui'), self) self.addWidgets() self.ui.show() self.dir = path.dirname(__file__) self.pts = [] self.canvas = MPLCanvas(self) self.canvas.plotter.lines = True self.toolbar = MPLToolbar(self.canvas, self) self.toolbar.setObjectName('browsetoolbar') self.addToolBar(self.toolbar) self.v1 = [1, 0, 0] self.v2 = [0, 0, 1] layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(self.canvas) self.frmPlot.setLayout(layout) self.Reader = None # restore settings with self.sgroup as settings: data_template_path = settings.value('last_data_template', '') print(settings.value('test', '')) if data_template_path: dtempl, numor = extract_template(data_template_path) self.dir = dtempl self.ui.txtNumors.setText(str(numor)) print("directory set to", self.dir) def closeEvent(self, event): with self.sgroup as settings: settings.setValue('test', 'abc') def addWidgets(self): """ Connecting signals """ self.ui.btnLoad.clicked.connect(self.readData) self.ui.btnSelectDir.clicked.connect(self.changeDir) self.ui.btnShow.clicked.connect(self.readPoints) self.ui.btnAddBZ.clicked.connect(self.addBZ) self.ui.fltEmax.valueChanged.connect(self.showPoints) self.ui.fltEmin.valueChanged.connect(self.showPoints) self.ui.chkBigFont.stateChanged.connect(self.bigFont) def readData(self): """ This function will read data from files indicated by folder and Numors """ numors = self.ui.txtNumors.text() self.canvas.axes.text(0.5, 0.5, 'Please wait, loading all data...', horizontalalignment='center') self.canvas.draw() QApplication.processEvents() self.reader = qr.QReader(self.dir, numors) self.canvas.axes.clear() self.canvas.draw() def readVectors(self): """ Reading orientation vectors from text fields """ self.v1 = [float(xx) for xx in str(self.ui.txtV1.text()).split()] self.v2 = [float(xx) for xx in str(self.ui.txtV2.text()).split()] def readPoints(self): """ It will find points in read scan files which has hkle values These is then converted to orientation vector basis and calculated distance from it. Only inplane points are processed. """ self.readVectors() self.canvas.axes.text(0.5, 0.5, 'Please wait, parsing read data...', horizontalalignment='center') self.canvas.draw() QApplication.processEvents() self.pts = self.reader.get_points(self.v1, self.v2) print("Datafiles read:", len(self.pts)) self.canvas.axes.clear() self.canvas.draw() self.showPoints() def showPoints(self): """ Will show read points in selected E range to canvas """ plotter = self.canvas.plotter plotter.reset(False) x = [] y = [] emin = self.ui.fltEmin.value() emax = self.ui.fltEmax.value() for pt in self.pts: if pt[2] >= emin and pt[2] <= emax: # ok, show point x.append(pt[0]) y.append(pt[1]) plotter.axes.plot(x, y, 'ro') plotter.axes.set_title('Measured points in reciprocal space', size='medium') plotter.axes.set_xlabel("x . (%.1f, %.1f, %.1f)" % tuple(self.v1)) plotter.axes.set_ylabel("y . (%.1f, %.1f, %.1f)" % tuple(self.v2)) plotter.draw() def changeDir(self): """ Change directory from which are the data read """ if self.dir: startdir = self.dir else: startdir = '.' fn = path_to_str(QFileDialog.getOpenFileName( self, 'Choose a file', startdir, 'All files (*)')[0]) if not fn: return dtempl, numor = extract_template(fn) self.dir = dtempl self.ui.txtNumors.setText(str(numor)) print("directory changed to", self.dir) def bigFont(self, state): """ Increase font size """ # TODO: should be done more sofisticated with more configuration ax = self.canvas.plotter.axes sizes = { "normal": [12, 10, 10], "big": [24, 22, 18] } if state == 0: # normal size toset = sizes["normal"] else: toset = sizes["big"] ax.title.set_fontsize(toset[0]) ax.xaxis.label.set_fontsize(toset[1]) ax.yaxis.label.set_fontsize(toset[1]) for t in ax.xaxis.get_major_ticks(): t.label.set_fontsize(toset[2]) for t in ax.yaxis.get_major_ticks(): t.label.set_fontsize(toset[2]) if (ax.legend_): for t in ax.legend_.texts: t.set_fontsize(toset[1]) self.canvas.plotter.draw() def addBZ(self): """ Experimental: add brilluin zone. Only Body centered tetragonal now supported. """ # check by vectors self.readVectors() myplane = np.cross(self.v1, self.v2) # TODO: generate gamma point dynamically gpts = np.array([[0, 0], [0, 2], [1, 1], [2, 0], [2, 2]]) # TODO: read lattice parameters from file bzc = bp.BZCreator(gpts, a = 4.33148, c = 10.83387, plane = myplane) bzc.doPlot(self.canvas.plotter.axes) self.canvas.plotter.draw()
def __init__(self): QMainWindow.__init__(self) self.itempanels = {} self.multipanels = {} self.current_panel = None self.inspector_window = None self.annotation_window = None self.sgroup = SettingGroup('main') loadUi(self, 'main.ui') self.menuRecent.aboutToShow.connect(self.on_menuRecent_aboutToShow) self.menuMoveToGroup = QMenu('Move selected to group', self) self.menuMoveToGroup.setIcon(QIcon(':/drawer-open.png')) self.menuMoveToGroup.aboutToShow.connect( self.on_menuMoveToGroup_aboutToShow) self.menuCopyToGroup = QMenu('Copy selected to group', self) self.menuCopyToGroup.setIcon(QIcon(':/drawer-double-open.png')) self.menuCopyToGroup.aboutToShow.connect( self.on_menuCopyToGroup_aboutToShow) self.menuRemoveGroup = QMenu('Remove group', self) self.menuRemoveGroup.setIcon(QIcon(':/drawer--minus.png')) self.menuRemoveGroup.aboutToShow.connect( self.on_menuRemoveGroup_aboutToShow) self.menuRenameGroup = QMenu('Rename group', self) self.menuRenameGroup.aboutToShow.connect( self.on_menuRenameGroup_aboutToShow) # populate plot view layout2 = QVBoxLayout() layout2.setContentsMargins(0, 0, 0, 0) self.canvas = MPLCanvas(self, maincanvas=True) self.canvas.replotRequest.connect( lambda: self.current_panel.plot(True)) self.canvas.mpl_connect('button_press_event', self.on_canvas_pick) self.canvas.mpl_connect('pick_event', self.on_canvas_pick) self.canvas.mpl_connect('button_release_event', self.on_canvas_click) self.toolbar = MPLToolbar(self.canvas, self) self.toolbar.setObjectName('mainplottoolbar') self.toolbar.popoutRequested.connect(self.on_actionPopOut_triggered) self.addToolBar(self.toolbar) layout2.addWidget(self.canvas) self.plotframe.setLayout(layout2) # session events session.itemsUpdated.connect(self.on_session_itemsUpdated) session.itemAdded.connect(self.on_session_itemAdded) session.filenameChanged.connect(self.on_session_filenameChanged) session.dirtyChanged.connect(self.on_session_dirtyChanged) # create data loader self.dloader = DataLoader(self, self.canvas.plotter) self.dloader.newDatas.connect(self.on_dloader_newDatas) self.stacker.addWidget(self.dloader) self.current_panel = self.dloader # create item model self.itemlistmodel = ItemListModel() self.itemTree.setModel(self.itemlistmodel) self.itemlistmodel.reset() self.itemTree.addAction(self.actionMergeData) self.itemTree.addAction(self.actionRemoveData) self.itemTree.addAction(self.menuMoveToGroup.menuAction()) self.itemTree.addAction(self.menuCopyToGroup.menuAction()) self.itemTree.newSelection.connect(self.on_itemTree_newSelection) # backend selector self.backend_group = QActionGroup(self) for backend in backends.available: action = QAction(backend.backend_name, self) action.setCheckable(True) if backends.backend.backend_name == backend.backend_name: action.setChecked(True) self.backend_group.addAction(action) self.menuBackend.addAction(action) action.triggered.connect(self.on_backend_action_triggered) # manage button menu = QMenu(self) menu.addAction(self.actionMergeData) menu.addAction(self.actionRemoveData) menu.addMenu(self.menuMoveToGroup) menu.addMenu(self.menuCopyToGroup) menu.addAction(self.actionReorder) menu.addSeparator() menu.addAction(self.actionNewGroup) menu.addMenu(self.menuRenameGroup) menu.addMenu(self.menuRemoveGroup) self.manageBtn.setMenu(menu) # right-mouse-button menu for canvas menu = self.canvasMenu = QMenu(self) menu.addAction(self.actionUnzoom) menu.addAction(self.actionHideFit) menu.addSeparator() menu.addAction(self.actionDrawSymbols) menu.addAction(self.actionConnectData) menu.addAction(self.actionSmoothImages) menu.addSeparator() menu.addAction(self.actionDrawGrid) menu.addAction(self.actionShowLegend) # restore window state with self.sgroup as settings: geometry = settings.value('geometry', QByteArray()) self.restoreGeometry(geometry) windowstate = settings.value('windowstate', QByteArray()) self.restoreState(windowstate) splitstate = settings.value('splitstate', QByteArray()) self.splitter.restoreState(splitstate) vsplitstate = settings.value('vsplitstate', QByteArray()) self.vsplitter.restoreState(vsplitstate) self.recent_files = settings.value('recentfiles', []) or []
class UFitMain(QMainWindow): def __init__(self): QMainWindow.__init__(self) self.itempanels = {} self.multipanels = {} self.current_panel = None self.inspector_window = None self.annotation_window = None self.sgroup = SettingGroup('main') loadUi(self, 'main.ui') self.menuRecent.aboutToShow.connect(self.on_menuRecent_aboutToShow) self.menuMoveToGroup = QMenu('Move selected to group', self) self.menuMoveToGroup.setIcon(QIcon(':/drawer-open.png')) self.menuMoveToGroup.aboutToShow.connect( self.on_menuMoveToGroup_aboutToShow) self.menuCopyToGroup = QMenu('Copy selected to group', self) self.menuCopyToGroup.setIcon(QIcon(':/drawer-double-open.png')) self.menuCopyToGroup.aboutToShow.connect( self.on_menuCopyToGroup_aboutToShow) self.menuRemoveGroup = QMenu('Remove group', self) self.menuRemoveGroup.setIcon(QIcon(':/drawer--minus.png')) self.menuRemoveGroup.aboutToShow.connect( self.on_menuRemoveGroup_aboutToShow) self.menuRenameGroup = QMenu('Rename group', self) self.menuRenameGroup.aboutToShow.connect( self.on_menuRenameGroup_aboutToShow) # populate plot view layout2 = QVBoxLayout() layout2.setContentsMargins(0, 0, 0, 0) self.canvas = MPLCanvas(self, maincanvas=True) self.canvas.replotRequest.connect( lambda: self.current_panel.plot(True)) self.canvas.mpl_connect('button_press_event', self.on_canvas_pick) self.canvas.mpl_connect('pick_event', self.on_canvas_pick) self.canvas.mpl_connect('button_release_event', self.on_canvas_click) self.toolbar = MPLToolbar(self.canvas, self) self.toolbar.setObjectName('mainplottoolbar') self.toolbar.popoutRequested.connect(self.on_actionPopOut_triggered) self.addToolBar(self.toolbar) layout2.addWidget(self.canvas) self.plotframe.setLayout(layout2) # session events session.itemsUpdated.connect(self.on_session_itemsUpdated) session.itemAdded.connect(self.on_session_itemAdded) session.filenameChanged.connect(self.on_session_filenameChanged) session.dirtyChanged.connect(self.on_session_dirtyChanged) # create data loader self.dloader = DataLoader(self, self.canvas.plotter) self.dloader.newDatas.connect(self.on_dloader_newDatas) self.stacker.addWidget(self.dloader) self.current_panel = self.dloader # create item model self.itemlistmodel = ItemListModel() self.itemTree.setModel(self.itemlistmodel) self.itemlistmodel.reset() self.itemTree.addAction(self.actionMergeData) self.itemTree.addAction(self.actionRemoveData) self.itemTree.addAction(self.menuMoveToGroup.menuAction()) self.itemTree.addAction(self.menuCopyToGroup.menuAction()) self.itemTree.newSelection.connect(self.on_itemTree_newSelection) # backend selector self.backend_group = QActionGroup(self) for backend in backends.available: action = QAction(backend.backend_name, self) action.setCheckable(True) if backends.backend.backend_name == backend.backend_name: action.setChecked(True) self.backend_group.addAction(action) self.menuBackend.addAction(action) action.triggered.connect(self.on_backend_action_triggered) # manage button menu = QMenu(self) menu.addAction(self.actionMergeData) menu.addAction(self.actionRemoveData) menu.addMenu(self.menuMoveToGroup) menu.addMenu(self.menuCopyToGroup) menu.addAction(self.actionReorder) menu.addSeparator() menu.addAction(self.actionNewGroup) menu.addMenu(self.menuRenameGroup) menu.addMenu(self.menuRemoveGroup) self.manageBtn.setMenu(menu) # right-mouse-button menu for canvas menu = self.canvasMenu = QMenu(self) menu.addAction(self.actionUnzoom) menu.addAction(self.actionHideFit) menu.addSeparator() menu.addAction(self.actionDrawSymbols) menu.addAction(self.actionConnectData) menu.addAction(self.actionSmoothImages) menu.addSeparator() menu.addAction(self.actionDrawGrid) menu.addAction(self.actionShowLegend) # restore window state with self.sgroup as settings: geometry = settings.value('geometry', QByteArray()) self.restoreGeometry(geometry) windowstate = settings.value('windowstate', QByteArray()) self.restoreState(windowstate) splitstate = settings.value('splitstate', QByteArray()) self.splitter.restoreState(splitstate) vsplitstate = settings.value('vsplitstate', QByteArray()) self.vsplitter.restoreState(vsplitstate) self.recent_files = settings.value('recentfiles', []) or [] def on_dloader_newDatas(self, datas, ingroup): for group in session.groups: if group.name == ingroup: break else: group = session.add_group(ingroup) items = [] for data in datas: if isinstance(data, ScanData): items.append(ScanDataItem(data)) elif isinstance(data, ImageData): items.append(ImageDataItem(data)) else: logger.warning('unknown data type: %s' % data) session.add_items(items, group) def on_session_itemsUpdated(self): # remove all panels whose item has vanished for item, panel in listitems(self.itempanels): if item not in session.all_items: self.stacker.removeWidget(panel) del self.itempanels[item] def on_session_itemAdded(self, item): # a single item has been added, show it self.itemTree.setCurrentIndex(self.itemlistmodel.index_for_item(item)) def on_session_filenameChanged(self): if session.filename: self.setWindowTitle('ufit - %s[*]' % session.filename) self._add_recent_file(session.filename) else: self.setWindowTitle('ufit[*]') def on_session_dirtyChanged(self, dirty): self.setWindowModified(dirty) def _add_recent_file(self, fname): """Add to recent file list.""" if not fname: return if fname in self.recent_files: self.recent_files.remove(fname) self.recent_files.insert(0, fname) if len(self.recent_files) > max_recent_files: self.recent_files.pop(-1) def on_menuRecent_aboutToShow(self): """Update recent file menu""" recent_files = [] for fname in self.recent_files: if fname != session.filename and path.isfile(fname): recent_files.append(fname) self.menuRecent.clear() if recent_files: for i, fname in enumerate(recent_files): action = QAction('%d - %s' % (i + 1, fname), self) action.triggered.connect(self.load_session) action.setData(fname) self.menuRecent.addAction(action) self.actionClearRecent.setEnabled(len(recent_files) > 0) self.menuRecent.addSeparator() self.menuRecent.addAction(self.actionClearRecent) @pyqtSlot() def on_actionClearRecent_triggered(self): """Clear recent files list""" self.recent_files = [] def select_new_panel(self, panel): if panel is not self.current_panel: if hasattr(self.current_panel, 'save_limits'): self.current_panel.save_limits() self.current_panel = panel self.stacker.setCurrentWidget(self.current_panel) # doesn't hurt def on_canvas_pick(self, event): if isinstance(self.current_panel, ScanDataPanel): self.current_panel.on_canvas_pick(event) def on_canvas_click(self, event): if event.button == 3 and not self.toolbar.mode: # right button self.canvasMenu.popup(QCursor.pos()) @pyqtSlot() def on_loadBtn_clicked(self): self.select_new_panel(self.dloader) self.itemTree.setCurrentIndex(QModelIndex()) @pyqtSlot() def on_actionNewGroup_triggered(self): name = QInputDialog.getText( self, 'ufit', 'Please enter a name ' 'for the new group:')[0] if not name: return session.add_group(name) def on_menuMoveToGroup_aboutToShow(self): self.menuMoveToGroup.clear() for group in session.groups: action = QAction(group.name, self) def move_to(_arg=None, group=group): items = self.selected_items() if not items: return session.move_items(items, group) self.re_expand_tree() action.triggered.connect(move_to) self.menuMoveToGroup.addAction(action) def on_menuCopyToGroup_aboutToShow(self): self.menuCopyToGroup.clear() for group in session.groups: action = QAction(group.name, self) def copy_to(_arg=None, group=group): items = self.selected_items() if not items: return session.copy_items(items, group) self.re_expand_tree() action.triggered.connect(copy_to) self.menuCopyToGroup.addAction(action) def on_menuRemoveGroup_aboutToShow(self): self.menuRemoveGroup.clear() for group in session.groups: action = QAction(group.name, self) def remove(_arg=None, group=group): session.remove_group(group) self.re_expand_tree() action.triggered.connect(remove) self.menuRemoveGroup.addAction(action) def on_menuRenameGroup_aboutToShow(self): self.menuRenameGroup.clear() for group in session.groups: action = QAction(group.name, self) def rename(_arg=None, group=group): name = QInputDialog.getText(self, 'ufit', 'Please enter a new name ' 'for the group:', text=group.name)[0] if not name: return session.rename_group(group, name) action.triggered.connect(rename) self.menuRenameGroup.addAction(action) @pyqtSlot() def on_actionRemoveData_triggered(self): items = self.selected_items() if not items: return if QMessageBox.question( self, 'ufit', 'OK to remove %d item(s)?' % len(items), QMessageBox.Yes | QMessageBox.No) == QMessageBox.No: return session.remove_items(items) self.re_expand_tree() @pyqtSlot() def on_actionReorder_triggered(self): dlg = QDialog(self) loadUi(dlg, 'reorder.ui') data2obj = dlg.itemList.populate() if not dlg.exec_(): return new_structure = [] for i in range(dlg.itemList.count()): new_index = dlg.itemList.item(i).type() obj = data2obj[new_index] if isinstance(obj, ItemGroup): new_structure.append((obj, [])) else: if not new_structure: QMessageBox.warning( self, 'ufit', 'Reordering invalid: every data item ' 'must be below a group') return new_structure[-1][1].append(obj) session.reorder_groups(new_structure) self.re_expand_tree() def selected_items(self, itemcls=SessionItem): """Return a list of selected items that belong to the given class.""" items = (index.internalPointer() for index in self.itemTree.selectedIndexes()) if not itemcls: # This will also return ItemGroup objects! return list(items) return [item for item in items if isinstance(item, itemcls)] def on_itemTree_newSelection(self): items = self.selected_items(None) if len(items) == 1 and isinstance(items[0], ItemGroup): # a group is selected -- act as if we selected all items items = items[0].items if len(items) == 0: self.on_loadBtn_clicked() elif len(items) == 1: item = items[0] if item not in self.itempanels: panel = self.itempanels[item] = \ item.create_panel(self, self.canvas) self.stacker.addWidget(panel) else: panel = self.itempanels[item] self.select_new_panel(panel) panel.plot(panel.get_saved_limits()) self.toolbar.update() if self.inspector_window and isinstance(item, ScanDataItem): self.inspector_window.setDataset(item.data) else: paneltype = type(items[0]) if not hasattr(paneltype, 'create_multi_panel'): return if paneltype not in self.multipanels: panel = self.multipanels[paneltype] = \ items[0].create_multi_panel(self, self.canvas) self.stacker.addWidget(panel) else: panel = self.multipanels[paneltype] panel.initialize(items) self.select_new_panel(panel) panel.plot() def on_itemTree_expanded(self, index): index.internalPointer().expanded = True session.set_dirty() def on_itemTree_collapsed(self, index): index.internalPointer().expanded = False session.set_dirty() def re_expand_tree(self): # expand / collapse all groups according to last saved state for group in session.groups: if group.expanded: self.itemTree.expand(self.itemlistmodel.index_for_group(group)) else: self.itemTree.collapse( self.itemlistmodel.index_for_group(group)) @pyqtSlot() def on_actionInspector_triggered(self): if self.inspector_window: self.inspector_window.activateWindow() return self.inspector_window = InspectorWindow(self) def deref(): self.inspector_window = None self.inspector_window.replotRequest.connect( lambda: self.current_panel.plot(True)) self.inspector_window.closed.connect(deref) if isinstance(self.current_panel, ScanDataPanel): self.inspector_window.setDataset(self.current_panel.item.data) self.inspector_window.show() @pyqtSlot() def on_actionAnnotations_triggered(self): if self.annotation_window: self.annotation_window.activateWindow() return self.annotation_window = AnnotationWindow(self) def deref(): self.annotation_window = None self.annotation_window.closed.connect(deref) self.annotation_window.show() @pyqtSlot() def on_actionLoadData_triggered(self): self.on_loadBtn_clicked() def on_actionHideFit_toggled(self, on): self.canvas.plotter.no_fits = on self.current_panel.plot() def on_actionConnectData_toggled(self, on): self.canvas.plotter.lines = on self.current_panel.plot() def on_actionDrawSymbols_toggled(self, on): self.canvas.plotter.symbols = on self.current_panel.plot() def on_actionShowLegend_toggled(self, on): self.canvas.plotter.legend = on self.current_panel.plot() def on_actionDrawGrid_toggled(self, on): self.canvas.plotter.grid = on self.current_panel.plot() def on_actionSmoothImages_toggled(self, on): self.canvas.plotter.imgsmoothing = on self.current_panel.plot() def _get_export_filename(self, filter='ASCII text (*.txt)'): initialdir = session.props.get('lastexportdir', session.dirname) filename, _ = QFileDialog.getSaveFileName(self, 'Select export file name', initialdir, filter) if filename == '': return '' expfilename = path_to_str(filename) session.props.lastexportdir = path.dirname(expfilename) return expfilename @pyqtSlot() def on_actionExportASCII_triggered(self): expfilename = self._get_export_filename() if expfilename: self.current_panel.export_ascii(expfilename) @pyqtSlot() def on_actionExportFIT_triggered(self): expfilename = self._get_export_filename() if expfilename: self.current_panel.export_fits(expfilename) @pyqtSlot() def on_actionExportPython_triggered(self): expfilename = self._get_export_filename('Python files (*.py)') if expfilename: self.current_panel.export_python(expfilename) @pyqtSlot() def on_actionExportParams_triggered(self): items = self.selected_items(ScanDataItem) dlg = ParamExportDialog(self, items) if dlg.exec_() != QDialog.Accepted: return expfilename = self._get_export_filename() if expfilename: try: dlg.do_export(expfilename) except Exception as e: logger.exception('While exporting parameters') QMessageBox.warning(self, 'Error', 'Could not export ' 'parameters: %s' % e) @pyqtSlot() def on_actionPrint_triggered(self): self.canvas.print_() @pyqtSlot() def on_actionPopOut_triggered(self): new_win = QMainWindow() canvas = MPLCanvas(new_win) toolbar = MPLToolbar(canvas, new_win) new_win.addToolBar(toolbar) splitter = QSplitter(Qt.Vertical, new_win) splitter.addWidget(canvas) try: from ufit.gui.console import QIPythonWidget except ImportError: lbl = QLabel( 'Please install IPython with qtconsole to ' 'activate the console part of this window.', new_win) splitter.addWidget(lbl) else: iw = QIPythonWidget('interactive pylab plotting prompt', new_win) iw.pushVariables({'ax': canvas.axes}) iw.executeCommand('from ufit.lab import *') iw.executeCommand('sca(ax)') iw.setFocus() iw.redrawme.connect(canvas.draw_idle) splitter.addWidget(iw) new_win.setCentralWidget(splitter) self.current_panel.plot(limits=None, canvas=canvas) new_win.show() @pyqtSlot() def on_actionSavePlot_triggered(self): self.toolbar.save_figure() @pyqtSlot() def on_actionUnzoom_triggered(self): self.toolbar.home() def check_save(self): if not self.isWindowModified(): # nothing there to be saved return True resp = QMessageBox.question( self, 'ufit', 'Save current session?\n%s' % session.filename, QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel) if resp == QMessageBox.Yes: return self.save_session() elif resp == QMessageBox.No: return True return False @pyqtSlot() def on_actionNewSession_triggered(self): if not self.check_save(): return session.clear() self.on_loadBtn_clicked() @pyqtSlot() def on_actionLoad_triggered(self): if not self.check_save(): return initialdir = session.dirname if not initialdir: with self.sgroup as settings: initialdir = settings.value('loadfiledirectory', '') filename, _ = QFileDialog.getOpenFileName(self, 'Select file name', initialdir, 'ufit files (*.ufit)') if filename == '': return self.load_session(path_to_str(filename)) @pyqtSlot() def on_actionInsert_triggered(self): initialdir = session.dirname if not initialdir: with self.sgroup as settings: initialdir = settings.value('loadfiledirectory', '') filename, _ = QFileDialog.getOpenFileName(self, 'Select file name', initialdir, 'ufit files (*.ufit)') if filename == '': return self.insert_session(path_to_str(filename)) def load_session(self, filename=None): if not filename: # Recent files action action = self.sender() if isinstance(action, QAction): if not self.check_save(): return filename = action.data() try: session.load(filename) with self.sgroup as settings: settings.setValue('loadfiledirectory', path.dirname(filename)) except Exception as err: logger.exception('Loading session %r failed' % filename) QMessageBox.warning(self, 'Error', 'Loading failed: %s' % err) else: self.re_expand_tree() self.setWindowModified(False) # if there are annotations, show the window automatically if session.props.get('annotations'): self.on_actionAnnotations_triggered() def insert_session(self, filename): temp_session.load(filename) basename = path.basename(filename) if basename.endswith('.ufit'): basename = basename[:-5] # XXX slight HACK for group in temp_session.groups: session.add_group(group.name + ' (from %s)' % basename) for item in group.items: session.add_item(item) @pyqtSlot() def on_actionSave_triggered(self): self.save_session() @pyqtSlot() def on_actionSaveAs_triggered(self): self.save_session_as() @pyqtSlot() def on_actionQExplorer_triggered(self): ReciprocalViewer(self) def save_session(self): if session.filename is None: return self.save_session_as() try: session.save() except Exception as err: logger.exception('Saving session failed') QMessageBox.warning(self, 'Error', 'Saving failed: %s' % err) return False return True def save_session_as(self): initialdir = session.dirname filename, _ = QFileDialog.getSaveFileName(self, 'Select file name', initialdir, 'ufit files (*.ufit)') if filename == '': return False session.set_filename(path_to_str(filename)) try: session.save() except Exception as err: logger.exception('Saving session failed') QMessageBox.warning(self, 'Error', 'Saving failed: %s' % err) return False return True @pyqtSlot() def on_actionMergeData_triggered(self): items = self.selected_items(ScanDataItem) if len(items) < 2: return dlg = QDialog(self) loadUi(dlg, 'rebin.ui') if dlg.exec_(): try: precision = float(dlg.precisionEdit.text()) except ValueError: return datalist = [i.data for i in items] new_data = datalist[0].merge(precision, *datalist[1:]) session.add_item(ScanDataItem(new_data), self.items[-1].group) @pyqtSlot() def on_actionQuit_triggered(self): self.close() def closeEvent(self, event): if not self.check_save(): event.ignore() return event.accept() with self.sgroup as settings: settings.setValue('geometry', self.saveGeometry()) settings.setValue('windowstate', self.saveState()) settings.setValue('splitstate', self.splitter.saveState()) settings.setValue('vsplitstate', self.vsplitter.saveState()) settings.setValue('recentfiles', self.recent_files) @pyqtSlot() def on_actionAbout_triggered(self): dlg = QDialog(self) dlg.setWindowFlags(Qt.Dialog | Qt.FramelessWindowHint) loadUi(dlg, 'about.ui') dlg.lbl.setText(dlg.lbl.text().replace('VERSION', __version__)) dlg.exec_() @pyqtSlot() def on_backend_action_triggered(self): backends.set_backend(str(self.sender().text()))