File indexing completed on 2025-11-02 03:43:45
0001 /* 0002 File : FitOptionsWidget.cpp 0003 Project : LabPlot 0004 Description : widget for editing advanced fit options 0005 -------------------------------------------------------------------- 0006 SPDX-FileCopyrightText: 2014-2020 Alexander Semke <alexander.semke@web.de> 0007 SPDX-FileCopyrightText: 2017-2022 Stefan Gerlach <stefan.gerlach@uni.kn> 0008 SPDX-License-Identifier: GPL-2.0-or-later 0009 */ 0010 0011 #include "FitOptionsWidget.h" 0012 #include "backend/core/AbstractColumn.h" 0013 #include "backend/worksheet/plots/cartesian/CartesianCoordinateSystem.h" 0014 #include "backend/worksheet/plots/cartesian/CartesianPlot.h" 0015 #include "backend/worksheet/plots/cartesian/Histogram.h" 0016 0017 /*! 0018 \class FitOptionsWidget 0019 \brief Widget for editing advanced fit options. 0020 0021 \ingroup kdefrontend 0022 */ 0023 FitOptionsWidget::FitOptionsWidget(QWidget* parent, XYFitCurve::FitData* fitData, XYFitCurve* fitCurve) 0024 : QWidget(parent) 0025 , m_fitData(fitData) 0026 , m_fitCurve(fitCurve) { 0027 ui.setupUi(this); 0028 ui.pbApply->setIcon(QIcon::fromTheme(QStringLiteral("dialog-ok-apply"))); 0029 ui.pbCancel->setIcon(QIcon::fromTheme(QStringLiteral("dialog-cancel"))); 0030 0031 // TODO: show "robust" option when robust fitting is possible 0032 // ui.cbRobust->addItem(i18n("on")); 0033 // ui.cbRobust->addItem(i18n("off")); 0034 ui.lRobust->setVisible(false); 0035 ui.cbRobust->setVisible(false); 0036 0037 ui.leMaxIterations->setValidator(new QIntValidator(ui.leMaxIterations)); 0038 ui.leEps->setValidator(new QDoubleValidator(ui.leEps)); 0039 ui.leEvaluatedPoints->setValidator(new QIntValidator(ui.leEvaluatedPoints)); 0040 0041 const auto numberLocale = QLocale(); 0042 ui.leMaxIterations->setText(numberLocale.toString(m_fitData->maxIterations)); 0043 ui.leEps->setText(numberLocale.toString(m_fitData->eps)); 0044 ui.leEvaluatedPoints->setText(numberLocale.toString(static_cast<qulonglong>(m_fitData->evaluatedPoints))); 0045 ui.sbConfidenceInterval->setLocale(numberLocale); 0046 0047 // range widgets 0048 const auto* plot = static_cast<const CartesianPlot*>(fitCurve->parentAspect()); 0049 const int xIndex = plot->coordinateSystem(m_fitCurve->coordinateSystemIndex())->index(CartesianCoordinateSystem::Dimension::X); 0050 m_dateTimeRange = (plot->xRangeFormat(xIndex) != RangeT::Format::Numeric); 0051 if (!m_dateTimeRange) { 0052 ui.leMin->setText(numberLocale.toString(m_fitData->fitRange.start())); 0053 ui.leMax->setText(numberLocale.toString(m_fitData->fitRange.end())); 0054 ui.leEvalMin->setText(numberLocale.toString(m_fitData->evalRange.start())); 0055 ui.leEvalMax->setText(numberLocale.toString(m_fitData->evalRange.end())); 0056 } else { 0057 ui.dateTimeEditMin->setMSecsSinceEpochUTC(m_fitData->fitRange.start()); 0058 ui.dateTimeEditMax->setMSecsSinceEpochUTC(m_fitData->fitRange.end()); 0059 ui.dateTimeEditEvalMin->setMSecsSinceEpochUTC(m_fitData->evalRange.start()); 0060 ui.dateTimeEditEvalMax->setMSecsSinceEpochUTC(m_fitData->evalRange.end()); 0061 } 0062 // changing data range not supported by ML 0063 if (fitData->algorithm == nsl_fit_algorithm_ml) 0064 ui.cbAutoRange->setEnabled(false); 0065 0066 ui.leMin->setVisible(!m_dateTimeRange); 0067 ui.leMax->setVisible(!m_dateTimeRange); 0068 ui.lXRange->setVisible(!m_dateTimeRange); 0069 ui.leEvalMin->setVisible(!m_dateTimeRange); 0070 ui.leEvalMax->setVisible(!m_dateTimeRange); 0071 ui.lEvalRange->setVisible(!m_dateTimeRange); 0072 ui.dateTimeEditMin->setVisible(m_dateTimeRange); 0073 ui.dateTimeEditMax->setVisible(m_dateTimeRange); 0074 ui.lXRangeDateTime->setVisible(m_dateTimeRange); 0075 ui.dateTimeEditEvalMin->setVisible(m_dateTimeRange); 0076 ui.dateTimeEditEvalMax->setVisible(m_dateTimeRange); 0077 ui.lEvalRangeDateTime->setVisible(m_dateTimeRange); 0078 0079 // auto range 0080 ui.cbAutoRange->setChecked(m_fitData->autoRange); 0081 ui.cbAutoEvalRange->setChecked(m_fitData->autoEvalRange); 0082 this->autoRangeChanged(); 0083 this->autoEvalRangeChanged(); 0084 0085 ui.cbUseDataErrors->setChecked(m_fitData->useDataErrors); 0086 ui.cbUseResults->setChecked(m_fitData->useResults); 0087 ui.cbPreview->setChecked(m_fitData->previewEnabled); 0088 ui.sbConfidenceInterval->setValue(m_fitData->confidenceInterval); 0089 0090 // SLOTS 0091 connect(ui.leEps, &QLineEdit::textChanged, this, &FitOptionsWidget::changed); 0092 connect(ui.leMaxIterations, &QLineEdit::textChanged, this, &FitOptionsWidget::changed); 0093 connect(ui.leEvaluatedPoints, &QLineEdit::textChanged, this, &FitOptionsWidget::changed); 0094 connect(ui.cbUseDataErrors, &QCheckBox::clicked, this, &FitOptionsWidget::changed); 0095 connect(ui.cbUseResults, &QCheckBox::clicked, this, &FitOptionsWidget::changed); 0096 connect(ui.cbPreview, &QCheckBox::clicked, this, &FitOptionsWidget::changed); 0097 connect(ui.sbConfidenceInterval, QOverload<double>::of(&NumberSpinBox::valueChanged), this, &FitOptionsWidget::changed); 0098 connect(ui.pbApply, &QPushButton::clicked, this, &FitOptionsWidget::applyClicked); 0099 connect(ui.pbCancel, &QPushButton::clicked, this, &FitOptionsWidget::finished); 0100 connect(ui.cbAutoRange, &QCheckBox::clicked, this, &FitOptionsWidget::autoRangeChanged); 0101 connect(ui.cbAutoEvalRange, &QCheckBox::clicked, this, &FitOptionsWidget::autoEvalRangeChanged); 0102 connect(ui.leMin, &QLineEdit::textChanged, this, &FitOptionsWidget::fitRangeMinChanged); 0103 connect(ui.leMax, &QLineEdit::textChanged, this, &FitOptionsWidget::fitRangeMaxChanged); 0104 connect(ui.dateTimeEditMin, &UTCDateTimeEdit::mSecsSinceEpochUTCChanged, this, &FitOptionsWidget::fitRangeMinDateTimeChanged); 0105 connect(ui.dateTimeEditMax, &UTCDateTimeEdit::mSecsSinceEpochUTCChanged, this, &FitOptionsWidget::fitRangeMaxDateTimeChanged); 0106 connect(ui.leEvalMin, &QLineEdit::textChanged, this, &FitOptionsWidget::evalRangeMinChanged); 0107 connect(ui.leEvalMax, &QLineEdit::textChanged, this, &FitOptionsWidget::evalRangeMaxChanged); 0108 connect(ui.dateTimeEditEvalMin, &UTCDateTimeEdit::mSecsSinceEpochUTCChanged, this, &FitOptionsWidget::evalRangeMinDateTimeChanged); 0109 connect(ui.dateTimeEditEvalMax, &UTCDateTimeEdit::mSecsSinceEpochUTCChanged, this, &FitOptionsWidget::evalRangeMaxDateTimeChanged); 0110 } 0111 0112 void FitOptionsWidget::autoRangeChanged() { 0113 const bool autoRange = ui.cbAutoRange->isChecked(); 0114 m_fitData->autoRange = autoRange; 0115 0116 ui.leMin->setEnabled(!autoRange); 0117 ui.lXRange->setEnabled(!autoRange); 0118 ui.leMax->setEnabled(!autoRange); 0119 ui.dateTimeEditMin->setEnabled(!autoRange); 0120 ui.lXRange->setEnabled(!autoRange); 0121 ui.dateTimeEditMax->setEnabled(!autoRange); 0122 0123 if (autoRange) { 0124 const AbstractColumn* xDataColumn = nullptr; 0125 if (m_fitCurve->dataSourceType() == XYAnalysisCurve::DataSourceType::Spreadsheet) 0126 xDataColumn = m_fitCurve->xDataColumn(); 0127 else { 0128 if (m_fitCurve->dataSourceCurve()) 0129 xDataColumn = m_fitCurve->dataSourceCurve()->xColumn(); 0130 } 0131 0132 if (xDataColumn) { 0133 const double xMin = xDataColumn->minimum(); 0134 const double xMax = xDataColumn->maximum(); 0135 m_fitData->fitRange.setRange(xMin, xMax); 0136 0137 const auto numberLocale = QLocale(); 0138 if (!m_dateTimeRange) { 0139 ui.leMin->setText(numberLocale.toString(xMin)); 0140 ui.leMax->setText(numberLocale.toString(xMax)); 0141 } else { 0142 ui.dateTimeEditMin->setMSecsSinceEpochUTC(xMin); 0143 ui.dateTimeEditMax->setMSecsSinceEpochUTC(xMax); 0144 } 0145 } 0146 } 0147 } 0148 0149 void FitOptionsWidget::autoEvalRangeChanged() { 0150 const bool autoRange = ui.cbAutoEvalRange->isChecked(); 0151 m_fitData->autoEvalRange = autoRange; 0152 0153 ui.leEvalMin->setEnabled(!autoRange); 0154 ui.lEvalRange->setEnabled(!autoRange); 0155 ui.leEvalMax->setEnabled(!autoRange); 0156 ui.dateTimeEditEvalMin->setEnabled(!autoRange); 0157 ui.lEvalRange->setEnabled(!autoRange); 0158 ui.dateTimeEditEvalMax->setEnabled(!autoRange); 0159 0160 if (autoRange) { 0161 const AbstractColumn* xDataColumn = nullptr; 0162 switch (m_fitCurve->dataSourceType()) { 0163 case XYAnalysisCurve::DataSourceType::Spreadsheet: 0164 xDataColumn = m_fitCurve->xDataColumn(); 0165 break; 0166 case XYAnalysisCurve::DataSourceType::Curve: 0167 if (m_fitCurve->dataSourceCurve()) 0168 xDataColumn = m_fitCurve->dataSourceCurve()->xColumn(); 0169 break; 0170 case XYAnalysisCurve::DataSourceType::Histogram: 0171 if (m_fitCurve->dataSourceHistogram()) 0172 xDataColumn = m_fitCurve->dataSourceHistogram()->bins(); 0173 } 0174 0175 if (xDataColumn) { 0176 const double xMin = xDataColumn->minimum(); 0177 const double xMax = xDataColumn->maximum(); 0178 m_fitData->evalRange.setRange(xMin, xMax); 0179 0180 const auto numberLocale = QLocale(); 0181 if (!m_dateTimeRange) { 0182 ui.leEvalMin->setText(numberLocale.toString(xMin)); 0183 ui.leEvalMax->setText(numberLocale.toString(xMax)); 0184 } else { 0185 ui.dateTimeEditEvalMin->setMSecsSinceEpochUTC(xMin); 0186 ui.dateTimeEditEvalMax->setMSecsSinceEpochUTC(xMax); 0187 } 0188 } 0189 } 0190 } 0191 0192 void FitOptionsWidget::fitRangeMinChanged() { 0193 SET_DOUBLE_FROM_LE(m_fitData->fitRange.start(), ui.leMin); 0194 changed(); 0195 } 0196 void FitOptionsWidget::fitRangeMaxChanged() { 0197 SET_DOUBLE_FROM_LE(m_fitData->fitRange.end(), ui.leMax); 0198 changed(); 0199 } 0200 0201 void FitOptionsWidget::fitRangeMinDateTimeChanged(qint64 value) { 0202 m_fitData->fitRange.setStart(value); 0203 changed(); 0204 } 0205 0206 void FitOptionsWidget::fitRangeMaxDateTimeChanged(qint64 value) { 0207 m_fitData->fitRange.setEnd(value); 0208 changed(); 0209 } 0210 0211 void FitOptionsWidget::evalRangeMinChanged() { 0212 SET_DOUBLE_FROM_LE(m_fitData->evalRange.start(), ui.leEvalMin); 0213 changed(); 0214 } 0215 void FitOptionsWidget::evalRangeMaxChanged() { 0216 SET_DOUBLE_FROM_LE(m_fitData->evalRange.end(), ui.leEvalMax); 0217 changed(); 0218 } 0219 0220 void FitOptionsWidget::evalRangeMinDateTimeChanged(qint64 value) { 0221 m_fitData->evalRange.setStart(value); 0222 changed(); 0223 } 0224 0225 void FitOptionsWidget::evalRangeMaxDateTimeChanged(qint64 value) { 0226 m_fitData->evalRange.setEnd(value); 0227 changed(); 0228 } 0229 0230 void FitOptionsWidget::applyClicked() { 0231 SET_INT_FROM_LE(m_fitData->maxIterations, ui.leMaxIterations); 0232 SET_DOUBLE_FROM_LE(m_fitData->eps, ui.leEps); 0233 SET_INT_FROM_LE(m_fitData->evaluatedPoints, ui.leEvaluatedPoints); 0234 0235 m_fitData->useDataErrors = ui.cbUseDataErrors->isChecked(); 0236 m_fitData->useResults = ui.cbUseResults->isChecked(); 0237 m_fitData->previewEnabled = ui.cbPreview->isChecked(); 0238 m_fitData->confidenceInterval = ui.sbConfidenceInterval->value(); 0239 0240 if (m_changed) 0241 Q_EMIT optionsChanged(); 0242 0243 Q_EMIT finished(); 0244 } 0245 0246 void FitOptionsWidget::changed() { 0247 m_changed = true; 0248 }