def _init_measurement_table(self, parent): self.full_measurement_model = MeasurementTableModelBase( self, self.parent.session, [ "is_acceptable", "wavelength", "species", "equivalent_width", "equivalent_width_uncertainty", "abundances", "abundance_uncertainties", "is_upper_limit", "user_flag", "expot", "reduced_equivalent_width" ]) self.measurement_model = MeasurementTableModelProxy(self) self.measurement_model.setSourceModel(self.full_measurement_model) vbox, measurement_view, btn_filter, btn_refresh = base.create_measurement_table_with_buttons( self, self.measurement_model, self.parent.session, callbacks_after_menu=[self.new_session_loaded], display_fitting_options=False) self.measurement_view = measurement_view self.measurement_model.add_view_to_update(self.measurement_view) _ = self.measurement_view.selectionModel() _.selectionChanged.connect(self.selected_measurement_changed) self.measurement_view.setSizePolicy( QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.MinimumExpanding)) self.measurement_model.add_filter_function( "use_for_stellar_parameter_inference", lambda model: model.use_for_stellar_parameter_inference) self.btn_filter_acceptable = btn_filter self.btn_filter_acceptable.clicked.connect(self.refresh_plots) self.btn_refresh = btn_refresh self.btn_refresh.clicked.connect(self.new_session_loaded) return vbox
def _init_measurement_table(self): self.full_measurement_model = MeasurementTableModelBase( self, self.parent.session, [ "is_acceptable", "wavelength", "expot", "loggf", "equivalent_width", "reduced_equivalent_width", "abundances", "abundances_to_solar", "is_upper_limit", "user_flag" ]) self.measurement_model = MeasurementTableModelProxy(self) self.measurement_model.setSourceModel(self.full_measurement_model) #self.measurement_view = MeasurementTableView(self) #self.measurement_view.setModel(self.measurement_model) vbox, measurement_view, btn_filter, btn_refresh = base.create_measurement_table_with_buttons( self, self.measurement_model, self.parent.session, callbacks_after_menu=[self.new_session_loaded], display_fitting_options=False) self.measurement_view = measurement_view self.measurement_model.add_view_to_update(self.measurement_view) _ = self.measurement_view.selectionModel() _.selectionChanged.connect(self.selected_measurement_changed) ## Sorting crashes :( #self.measurement_view.setSortingEnabled(True) #self.measurement_view.setItemDelegate(MeasurementTableDelegate(self,self.measurement_view)) self.measurement_view.setSizePolicy( QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.MinimumExpanding)) self.btn_filter_acceptable = btn_filter self.btn_filter_acceptable.clicked.connect(self.refresh_plots) self.btn_refresh = btn_refresh self.btn_refresh.clicked.connect(self.new_session_loaded) return vbox
class StellarParametersTab(QtGui.QWidget): def __init__(self, parent): """ Create a tab for the determination of stellar parameters by excitation and ionization equalibrium. :param parent: The parent widget. """ super(StellarParametersTab, self).__init__(parent) self.parent = parent sp = QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.MinimumExpanding) sp.setHeightForWidth(self.sizePolicy().hasHeightForWidth()) self.setSizePolicy(sp) self.parent_layout = QtGui.QHBoxLayout(self) self.parent_layout.setContentsMargins(20, 20, 20, 0) ########################################### ############ Create LHS Layout ############ ########################################### lhs_layout = QtGui.QVBoxLayout() lhs_layout.setSpacing(0) lhs_layout.setContentsMargins(0, 0, 0, 0) ## Add RT options grid_layout = self._init_rt_options(parent) lhs_layout.addLayout(grid_layout) ## Add RT buttons hbox_layout = self._init_rt_buttons(parent) lhs_layout.addLayout(hbox_layout) ## Add state table (slopes) grid_layout = self._init_state_table(parent) lhs_layout.addLayout(grid_layout) ## Add measurement table vbox = self._init_measurement_table(parent) lhs_layout.addLayout(vbox) ## Add table buttons hbox_layout = self._init_other_buttons(parent) lhs_layout.addLayout(hbox_layout) self.parent_layout.addLayout(lhs_layout) ########################################### ############ Finish LHS Layout ############ ########################################### ########################################### ############ Create RHS Layout ############ ########################################### rhs_layout = QtGui.QVBoxLayout() rhs_layout.setSpacing(0) rhs_layout.setContentsMargins(0, 0, 0, 0) self._init_scatterplots(parent) self._init_specfig(parent) rhs_layout.addWidget(self.expotfig) rhs_layout.addWidget(self.rewfig) rhs_layout.addWidget(self.specfig) self.parent_layout.addLayout(rhs_layout) ########################################### ############ Finish RHS Layout ############ ########################################### # E. Holmbeck added this self.params_to_optimize = np.array([True] * 4) def measure_abundances(self): """ The measure abundances button has been clicked. - if no acceptable measurements, fit all - update session stellar parameters - calculate abundances - update table and plots - update plots """ if self.parent.session is None or not self._check_for_spectral_models( ): return None # If no acceptable measurements, fit all for model in self.parent.session.spectral_models: if model.use_for_stellar_parameter_inference and "fitted_result" in model.metadata: break # do not fit if any stellar parameter lines are already fit else: for model in self.parent.session.spectral_models: if isinstance(model, SpectralSynthesisModel): continue try: model.fit() except: logger.exception( "Exception in fitting spectral model {}".format(model)) continue self.update_stellar_parameter_session() ## Loop through the spectral models and measure relevant abundances ## Note, have to do ALL the spectral models because might have added new measurements spectral_models = [] for spectral_model in self.parent.session.spectral_models: if isinstance(spectral_model, ProfileFittingModel) and spectral_model.is_acceptable \ and spectral_model.use_for_stellar_parameter_inference and (not spectral_model.is_upper_limit): spectral_models.append(spectral_model) if len(spectral_models) == 0: logger.debug( "StellarParametersTab.measure_abundances: no spectral models to measure!" ) else: self.parent.session.measure_abundances( spectral_models=spectral_models) self.measurement_model.reset() self.update_stellar_parameter_state_table() self.update_stellar_parameter_labels() self.refresh_plots() return None def new_session_loaded(self): if not hasattr(self.parent, "session") or self.parent.session is None: return None self.update_stellar_parameter_labels() self.full_measurement_model.new_session(self.parent.session) self.measurement_model.reset() self.measurement_view.update_session(self.parent.session) self.specfig.new_session(self.parent.session) self.update_stellar_parameter_state_table() self.refresh_plots() return None def update_stellar_parameter_session(self): """ Update the stellar parameters with the values in the GUI. """ self.parent.session.metadata["stellar_parameters"].update({ "effective_temperature": float(self.edit_teff.text()), "surface_gravity": float(self.edit_logg.text()), "metallicity": float(self.edit_metallicity.text()), "microturbulence": float(self.edit_xi.text()), "alpha": float(self.edit_alpha.text()) }) return True def update_stellar_parameter_labels(self): if not hasattr(self.parent, "session") or self.parent.session is None: print("Labels not updated") return None widget_info = [(self.edit_teff, "{0:.0f}", "effective_temperature"), (self.edit_logg, "{0:.2f}", "surface_gravity"), (self.edit_metallicity, "{0:+.2f}", "metallicity"), (self.edit_xi, "{0:.2f}", "microturbulence"), (self.edit_alpha, "{0:.2f}", "alpha")] for widget, fmt, key in widget_info: widget.setText( fmt.format( self.parent.session.metadata["stellar_parameters"][key])) return None def selected_measurement_changed(self): ta = time() try: selected_model = self._get_selected_model() except IndexError: self.update_selected_points(redraw=True) logger.debug("Time taken B: {}".format(time() - ta)) return None if selected_model is None: logger.debug("No selected model: {}".format(time() - ta)) return None logger.debug("selected model is at {}".format( selected_model._repr_wavelength)) self.refresh_plots() logger.debug("Time taken: {}".format(time() - ta)) return None def update_stellar_parameter_state_table(self): """ Update the text labels """ ## Note: this uses self.measurement_model to get a good list of measurements. ## So, have to call measurement_model.reset() before doing this ## Note: I have scrapped the Ti I/II in favor of hardcoding. ## Get data # species, abundance, expot, rew acceptable = self.measurement_model.get_data_column("is_acceptable") not_upper_limit = np.logical_not( self.measurement_model.get_data_column("is_upper_limit")) species = self.measurement_model.get_data_column("species") abundance = self.measurement_model.get_data_column("abundances") expot = self.measurement_model.get_data_column("expot") rew = self.measurement_model.get_data_column( "reduced_equivalent_width") ii1 = acceptable & (not_upper_limit) & (np.round(species, 1) == 26.0) ii2 = acceptable & (not_upper_limit) & (np.round(species, 1) == 26.1) chi1, eps1, REW1 = expot[ii1], abundance[ii1], rew[ii1] chi2, eps2, REW2 = expot[ii2], abundance[ii2], rew[ii2] finite = np.isfinite(chi1 * eps1 * REW1) chi1, eps1, REW1 = chi1[finite], eps1[finite], REW1[finite] finite = np.isfinite(chi2 * eps2 * REW2) chi2, eps2, REW2 = chi2[finite], eps2[finite], REW2[finite] ## Fit lines try: mchi1, bchi1, med1, eXH1, emchi1, N1 = utils.fit_line(chi1, eps1) except Exception as e: logger.debug(e) mchi1, bchi1, med1, eXH1, emchi1, N1 = np.nan, np.nan, np.nan, np.nan, np.nan, len( eps1) try: mREW1, bREW1, med1, eXH1, emREW1, N1 = utils.fit_line(REW1, eps1) except Exception as e: logger.debug(e) mREW1, bREW1, med1, eXH1, emREW1, N1 = np.nan, np.nan, np.nan, np.nan, np.nan, len( eps1) try: mchi2, bchi2, med2, eXH2, emchi2, N2 = utils.fit_line(chi2, eps2) except Exception as e: logger.debug(e) mchi2, bchi2, med2, eXH2, emchi2, N2 = np.nan, np.nan, np.nan, np.nan, np.nan, len( eps2) try: mREW2, bREW2, med2, eXH2, emREW2, N2 = utils.fit_line(REW2, eps2) except Exception as e: logger.debug(e) mREW2, bREW2, med2, eXH2, emREW2, N2 = np.nan, np.nan, np.nan, np.nan, np.nan, len( eps2) ## Update table XH1 = med1 - solar_composition(26.0) XH2 = med2 - solar_composition(26.1) self.state_fe1_N.setText(u"Fe I ({})".format(N1)) self.state_fe1_XH.setText(u"{:.2f} ± {:.2f}".format(XH1, eXH1)) self.state_fe1_dAdchi.setText(u"{:.3f} ± {:.3f}".format(mchi1, emchi1)) self.state_fe1_dAdREW.setText(u"{:.3f} ± {:.3f}".format(mREW1, emREW1)) self.state_fe2_N.setText(u"Fe II ({})".format(N2)) self.state_fe2_XH.setText(u"{:.2f} ± {:.2f}".format(XH2, eXH2)) self.state_fe2_dAdchi.setText(u"{:.3f} ± {:.3f}".format(mchi2, emchi2)) self.state_fe2_dAdREW.setText(u"{:.3f} ± {:.3f}".format(mREW2, emREW2)) return None def refresh_plots(self): self.expotfig.update_scatterplot(False) self.rewfig.update_scatterplot(False) self.expotfig.update_selected_points(True) self.rewfig.update_selected_points(True) self.specfig.update_spectrum_figure(True) return None def refresh_selected_points(self): self.expotfig.update_selected_points(True) self.rewfig.update_selected_points(True) return None def _get_selected_model(self, full_output=False): # Map the first selected row back to the source model index. try: proxy_index = self.measurement_view.selectionModel( ).selectedIndexes()[-1] except IndexError: return (None, None, None) if full_output else None index = self.measurement_model.mapToSource(proxy_index).row() model = self.parent.session.metadata["spectral_models"][index] return (model, proxy_index, index) if full_output else model def options(self): """ Open a GUI for the radiative transfer and solver options. """ return SolveOptionsDialog(self.parent.session).exec_() def quality_control(self): """ Show a dialog to specify quality control constraints for spectral models used in the determination of stellar parameters. """ dialog = QualityControlDialog(self.parent.session, filter_spectral_models=lambda m: m. use_for_stellar_parameter_inference) dialog.exec_() if len(dialog.affected_indices) > 0: self.measurement_model.reset() self.refresh_plots() return None def sperrors_dialog(self): """ Open a GUI for the stellar parameter errors. """ return StellarParameterUncertaintiesDialog(self.parent.session).exec_() def solve_parameters(self): """ Solve the stellar parameters. """ if self.parent.session is None or not self._check_for_spectral_models( ): return None ## use current state as initial guess logger.info("Setting [alpha/Fe]=0.4 to solve") self.update_stellar_parameter_session() self.parent.session.optimize_stellar_parameters() ## refresh everything self.measure_abundances() self.new_session_loaded() # E. Holmbeck added this function def solve_feh(self): """ Solve the stellar parameters. """ if self.parent.session is None or not self._check_for_spectral_models( ): return None ## use current state as initial guess logger.info("Setting [alpha/Fe]=0.4 to solve") self.update_stellar_parameter_session() self.parent.session.optimize_feh(self.params_to_optimize) self.parent.session.metadata["stellar_parameters"] ## refresh everything # E. Holmbeck added 'new_session' again; trying to fix update problem self.new_session_loaded() self.measure_abundances() self.new_session_loaded() def _init_rt_options(self, parent): grid_layout = QtGui.QGridLayout() # Effective temperature. label = QtGui.QLabel(self) label.setText("Teff") label.setSizePolicy( QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Minimum)) grid_layout.addWidget(label, 0, 0, 1, 1) self.edit_teff = QtGui.QLineEdit(self) self.edit_teff.setMinimumSize(QtCore.QSize(40, 0)) self.edit_teff.setMaximumSize(QtCore.QSize(50, 16777215)) self.edit_teff.setAlignment(QtCore.Qt.AlignCenter) self.edit_teff.setSizePolicy( QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Minimum)) self.edit_teff.setValidator( QtGui.QDoubleValidator(3000, 8000, 0, self.edit_teff)) self.edit_teff.textChanged.connect(self._check_lineedit_state) grid_layout.addWidget(self.edit_teff, 0, 1) # E. Holmbeck added checkbox self.teff_const = QtGui.QCheckBox("Hold constant") self.teff_const.setChecked(False) self.teff_const.stateChanged.connect( lambda: self.const_param(self.teff_const, 0)) grid_layout.addWidget(self.teff_const, 0, 2, -1) # Surface gravity. label = QtGui.QLabel(self) label.setText("logg") label.setSizePolicy( QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Minimum)) grid_layout.addWidget(label, 1, 0, 1, 1) self.edit_logg = QtGui.QLineEdit(self) self.edit_logg.setMinimumSize(QtCore.QSize(40, 0)) self.edit_logg.setMaximumSize(QtCore.QSize(50, 16777215)) self.edit_logg.setAlignment(QtCore.Qt.AlignCenter) self.edit_logg.setValidator( QtGui.QDoubleValidator(-1, 6, 3, self.edit_logg)) self.edit_logg.setSizePolicy( QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Minimum)) self.edit_logg.textChanged.connect(self._check_lineedit_state) grid_layout.addWidget(self.edit_logg, 1, 1) # E. Holmbeck added checkbox self.logg_const = QtGui.QCheckBox("Hold constant") self.logg_const.setChecked(False) self.logg_const.stateChanged.connect( lambda: self.const_param(self.logg_const, 2)) grid_layout.addWidget(self.logg_const, 1, 2, -1) # Metallicity. label = QtGui.QLabel(self) label.setText("[M/H]") label.setSizePolicy( QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Minimum)) grid_layout.addWidget(label, 2, 0, 1, 1) self.edit_metallicity = QtGui.QLineEdit(self) self.edit_metallicity.setMinimumSize(QtCore.QSize(40, 0)) self.edit_metallicity.setMaximumSize(QtCore.QSize(50, 16777215)) self.edit_metallicity.setAlignment(QtCore.Qt.AlignCenter) self.edit_metallicity.setValidator( QtGui.QDoubleValidator(-5, 1, 3, self.edit_metallicity)) self.edit_metallicity.setSizePolicy( QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Minimum)) self.edit_metallicity.textChanged.connect(self._check_lineedit_state) grid_layout.addWidget(self.edit_metallicity, 2, 1) # E. Holmbeck added checkbox self.feh_const = QtGui.QCheckBox("Hold constant") self.feh_const.setChecked(False) self.feh_const.stateChanged.connect( lambda: self.const_param(self.feh_const, 3)) grid_layout.addWidget(self.feh_const, 2, 2, -1) # Microturbulence. label = QtGui.QLabel(self) label.setText("vt") label.setSizePolicy( QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Minimum)) grid_layout.addWidget(label, 3, 0, 1, 1) self.edit_xi = QtGui.QLineEdit(self) self.edit_xi.setMinimumSize(QtCore.QSize(40, 0)) self.edit_xi.setMaximumSize(QtCore.QSize(50, 16777215)) self.edit_xi.setAlignment(QtCore.Qt.AlignCenter) self.edit_xi.setValidator(QtGui.QDoubleValidator( 0, 5, 3, self.edit_xi)) self.edit_xi.setSizePolicy( QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Minimum)) self.edit_xi.textChanged.connect(self._check_lineedit_state) grid_layout.addWidget(self.edit_xi, 3, 1) # E. Holmbeck added checkbox self.vt_const = QtGui.QCheckBox("Hold constant") self.vt_const.setChecked(False) self.vt_const.stateChanged.connect( lambda: self.const_param(self.vt_const, 1)) grid_layout.addWidget(self.vt_const, 3, 2, -1) # Alpha-enhancement. label = QtGui.QLabel(self) label.setText("alpha") label.setSizePolicy( QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Minimum)) grid_layout.addWidget(label, 4, 0, 1, 1) self.edit_alpha = QtGui.QLineEdit(self) self.edit_alpha.setMinimumSize(QtCore.QSize(40, 0)) self.edit_alpha.setMaximumSize(QtCore.QSize(50, 16777215)) self.edit_alpha.setAlignment(QtCore.Qt.AlignCenter) self.edit_alpha.setValidator( QtGui.QDoubleValidator(-1, 1, 3, self.edit_alpha)) #self.edit_alpha.setValidator(QtGui.QDoubleValidator(0, 0.4, 3, self.edit_alpha)) self.edit_alpha.setSizePolicy( QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Minimum)) self.edit_alpha.textChanged.connect(self._check_lineedit_state) grid_layout.addWidget(self.edit_alpha, 4, 1) self.edit_teff.returnPressed.connect(self.measure_abundances) self.edit_logg.returnPressed.connect(self.measure_abundances) self.edit_metallicity.returnPressed.connect(self.measure_abundances) self.edit_xi.returnPressed.connect(self.measure_abundances) self.edit_alpha.returnPressed.connect(self.measure_abundances) return grid_layout def _init_rt_buttons(self, parent): # Buttons for solving/measuring. # E. Holmbeck changed Box to Grid and # added the positions in each "hbox.addWidget" line hbox = QtGui.QHBoxLayout() #hbox = QtGui.QGridLayout() self.btn_measure = QtGui.QPushButton(self) self.btn_measure.setAutoDefault(True) self.btn_measure.setDefault(True) self.btn_measure.setText("Derive abundances") self.btn_measure.clicked.connect(self.measure_abundances) hbox.addWidget(self.btn_measure) self.btn_options = QtGui.QPushButton(self) self.btn_options.setText("Options...") self.btn_options.clicked.connect(self.options) hbox.addWidget(self.btn_options) self.btn_solve = QtGui.QPushButton(self) self.btn_solve.setText("Solve") #self.btn_solve.clicked.connect(self.solve_parameters) # E. Holmbeck edited this button. # TODO: just overwrite/rename the function self.btn_solve.clicked.connect(self.solve_feh) hbox.addWidget(self.btn_solve) # E. Holmbeck added these three lines. #self.btn_solve_feh = QtGui.QPushButton(self) #self.btn_solve_feh.setText("Solve [M/H] and vt") #self.btn_solve_feh.clicked.connect(self.solve_feh) #hbox.addWidget(self.btn_solve_feh, 1,1) return hbox def _init_state_table(self, parent): grid_layout = QtGui.QGridLayout() def create_label(text, row, col, rowspan=1, colspan=1, align=QtCore.Qt.AlignCenter): label = QtGui.QLabel(self) label.setText(text) label.setSizePolicy( QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Minimum)) grid_layout.addWidget(label, row, col, rowspan, colspan, align) return label # Create Header create_label("Species", 0, 0, align=QtCore.Qt.AlignLeft) create_label(u"〈[X/H]〉", 0, 1) create_label(u"∂A/∂χ", 0, 2) create_label(u"∂A/∂REW", 0, 3) # Create State Labels self.state_fe1_N = create_label(u"Fe I (nan)", 1, 0, align=QtCore.Qt.AlignLeft) self.state_fe1_XH = create_label(u"nan ± nan", 1, 1) self.state_fe1_dAdchi = create_label(u"nan ± nan", 1, 2) self.state_fe1_dAdREW = create_label(u"nan ± nan", 1, 3) self.state_fe2_N = create_label(u"Fe II (nan)", 2, 0, align=QtCore.Qt.AlignLeft) self.state_fe2_XH = create_label(u"nan ± nan", 2, 1) self.state_fe2_dAdchi = create_label(u"nan ± nan", 2, 2) self.state_fe2_dAdREW = create_label(u"nan ± nan", 2, 3) return grid_layout def _init_measurement_table(self, parent): self.full_measurement_model = MeasurementTableModelBase( self, self.parent.session, [ "is_acceptable", "wavelength", "species", "equivalent_width", "equivalent_width_uncertainty", "abundances", "abundance_uncertainties", "is_upper_limit", "user_flag", "expot", "reduced_equivalent_width" ]) self.measurement_model = MeasurementTableModelProxy(self) self.measurement_model.setSourceModel(self.full_measurement_model) vbox, measurement_view, btn_filter, btn_refresh = base.create_measurement_table_with_buttons( self, self.measurement_model, self.parent.session, callbacks_after_menu=[self.new_session_loaded], display_fitting_options=False) self.measurement_view = measurement_view self.measurement_model.add_view_to_update(self.measurement_view) _ = self.measurement_view.selectionModel() _.selectionChanged.connect(self.selected_measurement_changed) self.measurement_view.setSizePolicy( QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.MinimumExpanding)) self.measurement_model.add_filter_function( "use_for_stellar_parameter_inference", lambda model: model.use_for_stellar_parameter_inference) self.btn_filter_acceptable = btn_filter self.btn_filter_acceptable.clicked.connect(self.refresh_plots) self.btn_refresh = btn_refresh self.btn_refresh.clicked.connect(self.new_session_loaded) return vbox def _init_other_buttons(self, parent): hbox = QtGui.QHBoxLayout() self.btn_quality_control = QtGui.QPushButton(self) self.btn_quality_control.setText("Quality control..") self.btn_quality_control.clicked.connect(self.quality_control) self.btn_sperrors = QtGui.QPushButton(self) self.btn_sperrors.setText("Stellar Parameter Uncertainties..") self.btn_sperrors.clicked.connect(self.sperrors_dialog) hbox.addItem( QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Minimum)) hbox.addWidget(self.btn_quality_control) hbox.addWidget(self.btn_sperrors) return hbox def _init_scatterplots(self, parent): ## Only plot acceptable measurements that are not upper limits filters = [ lambda x: (x.is_acceptable) and (x.species[0] == 26.0) and (not x.is_upper_limit), lambda x: (x.is_acceptable) and (x.species[0] == 26.1) and (not x.is_upper_limit), lambda x: (x.is_acceptable) and (x.species[0] == 26.0) and (x.user_flag) and (not x.is_upper_limit), lambda x: (x.is_acceptable) and (x.species[0] == 26.1) and (x.user_flag) and (not x.is_upper_limit), ] point_styles = [ { "s": 40, "facecolor": "#FFFFFF", "edgecolor": "k", "linewidths": 1, "zorder": 1 }, { "s": 40, "facecolor": "r", "edgecolor": "k", "linewidths": 1, "zorder": 9 }, { "s": 70, "facecolor": "none", "edgecolor": "red", "linewidths": 3, "zorder": 10 }, { "s": 70, "facecolor": "none", "edgecolor": "red", "linewidths": 3, "zorder": 19 }, ] linefit_styles = [{ "color": "k", "linestyle": "--", "zorder": -99 }, { "color": "r", "linestyle": "--", "zorder": -99 }, None, None] linemean_styles = [{ "color": "k", "linestyle": ":", "zorder": -999 }, { "color": "r", "linestyle": ":", "zorder": -999 }, None, None] self.expotfig = SMHScatterplot(None, "expot", "abundances", tableview=self.measurement_view, filters=filters, point_styles=point_styles, linefit_styles=linefit_styles, linemean_styles=linemean_styles, do_not_select_unacceptable=True) self.rewfig = SMHScatterplot(None, "reduced_equivalent_width", "abundances", tableview=self.measurement_view, filters=filters, point_styles=point_styles, linefit_styles=linefit_styles, linemean_styles=linemean_styles, do_not_select_unacceptable=True) sp = QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.MinimumExpanding) for fig in [self.expotfig, self.rewfig]: fig.setSizePolicy(sp) return None def _init_specfig(self, parent): self.specfig = SMHSpecDisplay( None, self.parent.session, enable_masks=True, get_selected_model=self._get_selected_model) sp = QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.MinimumExpanding) self.specfig.setSizePolicy(sp) self.specfig.add_callback_after_fit(self.refresh_current_model) self.ax_spectrum = self.specfig.ax_spectrum self.ax_residual = self.specfig.ax_residual def refresh_current_model(self): spectral_model, proxy_index, index = self._get_selected_model(True) if spectral_model is None: return None self.measurement_view.update_row(proxy_index.row()) def _check_lineedit_state(self, *args, **kwargs): """ Update the background color of a QLineEdit object based on whether the input is valid. """ # TODO: Implement from # http://stackoverflow.com/questions/27159575/pyside-modifying-widget-colour-at-runtime-without-overwriting-stylesheet sender = self.sender() validator = sender.validator() state = validator.validate(sender.text(), 0)[0] if state == QtGui.QValidator.Acceptable: color = 'none' # normal background color elif state == QtGui.QValidator.Intermediate: color = '#fff79a' # yellow else: color = '#f6989d' # red sender.setStyleSheet('QLineEdit { background-color: %s }' % color) return None def _check_for_spectral_models(self): """ Check the session for any valid spectral models that are associated with the determination of stellar parameters. """ # Are there any spectral models to be used for the determination of # stellar parameters? for sm in self.parent.session.metadata.get("spectral_models", []): if sm.use_for_stellar_parameter_inference: break else: reply = QtGui.QMessageBox.information( self, "No spectral models found", "No spectral models are currently associated with the " "determination of stellar parameters.\n\n" "Click 'OK' to load the transitions manager.") if reply == QtGui.QMessageBox.Ok: # Load line list manager. dialog = TransitionsDialog( self.parent.session, callbacks=[self.parent.transition_dialog_callback]) dialog.exec_() # Do we even have any spectral models now? for sm in self.parent.session.metadata.get( "spectral_models", []): if sm.use_for_stellar_parameter_inference: break else: return False else: return False return True # E. Holmbeck added this function def const_param(self, param_selected, param_index): # Param_index: 0 = teff, 1 = vt, 2 = logg, 3 = feh if param_selected.isChecked() == True: self.params_to_optimize[param_index] = False else: self.params_to_optimize[param_index] = True
class ReviewTab(QtGui.QWidget): def __init__(self, parent): super(ReviewTab, self).__init__(parent) self.parent = parent self.parent_layout = QtGui.QHBoxLayout(self) ####################################### #### LHS: Summary and Measurement Table ####################################### lhs_layout = QtGui.QVBoxLayout() self._init_summary_table() self._current_species = None lhs_layout.addWidget(self.summary_view) vbox = self._init_measurement_table() #lhs_layout.addWidget(self.measurement_view) lhs_layout.addLayout(vbox) self.parent_layout.addLayout(lhs_layout) ################################## #### RHS: Interactive Scatterplots ################################## rhs_layout = QtGui.QVBoxLayout() rhs_layout.setSpacing(0) self._init_scatterplots() rhs_layout.addWidget(self.plot1) rhs_layout.addWidget(self.plot2) rhs_layout.addWidget(self.plot3) self.parent_layout.addLayout(rhs_layout) return None def new_session_loaded(self): session = self.parent.session if session is None: return None self.summary_model.new_session(session) self.full_measurement_model.new_session(session) self.measurement_model.reset() self.measurement_view.update_session(session) self.refresh_plots() return None def selected_summary_changed(self): """ Called when you select a new summary """ start = time.time() # Get the species try: row = self.summary_view.selectionModel().selectedRows()[0].row() except IndexError: species = None else: species = self.summary_view.model().all_species[row] # Change measurement table filter logger.debug("species={}".format(species)) self.change_measurement_table_species(species) # Change plots self.refresh_plots() logger.debug("selected_summary_changed to {}: {:.1f}".format( species, time.time() - start)) return None def change_measurement_table_species(self, species): # Update the filter if self._current_species is not None: _current_species_str = "{:.1f}".format(self._current_species) try: self.measurement_model.delete_filter_function( _current_species_str) except KeyError as e: logger.debug(e) logger.debug(self.measurement_model.filter_functions) raise if species is not None: filterfn = lambda model: _model_has_species(model, species) speciesstr = "{:.1f}".format(species) self.measurement_model.add_filter_function(speciesstr, filterfn) self._current_species = species # Reset the model (and its views) self.measurement_model.reset() def refresh_plots(self): self.plot1.update_scatterplot(False) self.plot2.update_scatterplot(False) self.plot3.update_scatterplot(False) self.plot1.update_selected_points(True) self.plot2.update_selected_points(True) self.plot3.update_selected_points(True) def refresh_selected_points(self): self.plot1.update_selected_points(True) self.plot2.update_selected_points(True) self.plot3.update_selected_points(True) def selected_measurement_changed(self): self.refresh_selected_points() return None def _init_summary_table(self): # Create summary model self.summary_model = MeasurementSummaryTableModel( self, self.parent.session) # Create and link summary view self.summary_view = BaseTableView(self) self.summary_view.setSelectionMode( QtGui.QAbstractItemView.SingleSelection) self.summary_view.setModel(self.summary_model) _ = self.summary_view.selectionModel() _.selectionChanged.connect(self.selected_summary_changed) def _init_measurement_table(self): self.full_measurement_model = MeasurementTableModelBase( self, self.parent.session, [ "is_acceptable", "wavelength", "expot", "loggf", "equivalent_width", "reduced_equivalent_width", "abundances", "abundances_to_solar", "is_upper_limit", "user_flag" ]) self.measurement_model = MeasurementTableModelProxy(self) self.measurement_model.setSourceModel(self.full_measurement_model) #self.measurement_view = MeasurementTableView(self) #self.measurement_view.setModel(self.measurement_model) vbox, measurement_view, btn_filter, btn_refresh = base.create_measurement_table_with_buttons( self, self.measurement_model, self.parent.session, callbacks_after_menu=[self.new_session_loaded], display_fitting_options=False) self.measurement_view = measurement_view self.measurement_model.add_view_to_update(self.measurement_view) _ = self.measurement_view.selectionModel() _.selectionChanged.connect(self.selected_measurement_changed) ## Sorting crashes :( #self.measurement_view.setSortingEnabled(True) #self.measurement_view.setItemDelegate(MeasurementTableDelegate(self,self.measurement_view)) self.measurement_view.setSizePolicy( QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.MinimumExpanding)) self.btn_filter_acceptable = btn_filter self.btn_filter_acceptable.clicked.connect(self.refresh_plots) self.btn_refresh = btn_refresh self.btn_refresh.clicked.connect(self.new_session_loaded) return vbox def _init_scatterplots(self): filters = [ lambda x: (x.is_acceptable) and (not x.user_flag) and (not x.is_upper_limit), lambda x: not x.is_acceptable, lambda x: x.user_flag, lambda x: x.is_upper_limit ] point_styles = [{ "s": 30, "facecolor": "k", "edgecolor": "k", "alpha": 0.5 }, { "s": 30, "c": "c", "marker": "x", "linewidths": 3 }, { "s": 30, "edgecolor": "r", "facecolor": "k", "alpha": 0.5, "linewidths": 3 }, { "s": 30, "edgecolor": "r", "facecolor": "none", "marker": "v" }] linefit_styles = [{ "color": "k", "linestyle": "--", "zorder": -99 }, None, None, None] linemean_styles = [{ "color": "k", "linestyle": ":", "zorder": -999 }, None, None, None] self.plot1 = SMHScatterplot(None, "expot", "abundances", tableview=self.measurement_view, filters=filters, point_styles=point_styles, linefit_styles=linefit_styles, linemean_styles=linemean_styles) self.plot2 = SMHScatterplot(None, "reduced_equivalent_width", "abundances", tableview=self.measurement_view, filters=filters, point_styles=point_styles, linefit_styles=linefit_styles, linemean_styles=linemean_styles) self.plot3 = SMHScatterplot(None, "wavelength", "abundances", tableview=self.measurement_view, filters=filters, point_styles=point_styles, linefit_styles=linefit_styles, linemean_styles=linemean_styles) sp = QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.MinimumExpanding) for fig in [self.plot1, self.plot2, self.plot3]: fig.setSizePolicy(sp) return None