File indexing completed on 2025-07-13 03:32:47
0001 /* 0002 File : XYCorrelationCurveDock.cpp 0003 Project : LabPlot 0004 Description : widget for editing properties of correlation curves 0005 -------------------------------------------------------------------- 0006 SPDX-FileCopyrightText: 2018-2021 Stefan Gerlach <stefan.gerlach@uni.kn> 0007 0008 SPDX-License-Identifier: GPL-2.0-or-later 0009 */ 0010 0011 #include "XYCorrelationCurveDock.h" 0012 #include "backend/worksheet/plots/cartesian/XYCorrelationCurve.h" 0013 #include "commonfrontend/widgets/TreeViewComboBox.h" 0014 0015 #include <KConfigGroup> 0016 0017 #include <QMenu> 0018 #include <QWidgetAction> 0019 0020 extern "C" { 0021 #include "backend/nsl/nsl_corr.h" 0022 } 0023 0024 /*! 0025 \class XYCorrelationCurveDock 0026 \brief Provides a widget for editing the properties of the XYCorrelationCurves 0027 (2D-curves defined by a correlation) currently selected in 0028 the project explorer. 0029 0030 If more than one curves are set, the properties of the first column are shown. 0031 The changes of the properties are applied to all curves. 0032 The exclusions are the name, the comment and the datasets (columns) of 0033 the curves - these properties can only be changed if there is only one single curve. 0034 0035 \ingroup kdefrontend 0036 */ 0037 0038 XYCorrelationCurveDock::XYCorrelationCurveDock(QWidget* parent) 0039 : XYAnalysisCurveDock(parent, XYAnalysisCurveDock::RequiredDataSource::YY2) { 0040 } 0041 0042 /*! 0043 * // Tab "General" 0044 */ 0045 void XYCorrelationCurveDock::setupGeneral() { 0046 auto* generalTab = new QWidget(ui.tabGeneral); 0047 uiGeneralTab.setupUi(generalTab); 0048 setPlotRangeCombobox(uiGeneralTab.cbPlotRanges); 0049 setBaseWidgets(uiGeneralTab.leName, uiGeneralTab.teComment, uiGeneralTab.pbRecalculate, uiGeneralTab.cbDataSourceType); 0050 setVisibilityWidgets(uiGeneralTab.chkVisible, uiGeneralTab.chkLegendVisible); 0051 0052 auto* gridLayout = static_cast<QGridLayout*>(generalTab->layout()); 0053 gridLayout->setContentsMargins(2, 2, 2, 2); 0054 gridLayout->setHorizontalSpacing(2); 0055 gridLayout->setVerticalSpacing(2); 0056 0057 cbDataSourceCurve = new TreeViewComboBox(generalTab); 0058 gridLayout->addWidget(cbDataSourceCurve, 5, 2, 1, 3); 0059 cbXDataColumn = new TreeViewComboBox(generalTab); 0060 gridLayout->addWidget(cbXDataColumn, 6, 2, 1, 3); 0061 cbYDataColumn = new TreeViewComboBox(generalTab); 0062 gridLayout->addWidget(cbYDataColumn, 8, 2, 1, 3); 0063 cbY2DataColumn = new TreeViewComboBox(generalTab); 0064 gridLayout->addWidget(cbY2DataColumn, 9, 2, 1, 3); 0065 0066 uiGeneralTab.leMin->setValidator(new QDoubleValidator(uiGeneralTab.leMin)); 0067 uiGeneralTab.leMax->setValidator(new QDoubleValidator(uiGeneralTab.leMax)); 0068 0069 for (int i = 0; i < NSL_CORR_TYPE_COUNT; i++) 0070 uiGeneralTab.cbType->addItem(i18n(nsl_corr_type_name[i])); 0071 // nsl_corr_method_type not exposed to user 0072 for (int i = 0; i < NSL_CORR_NORM_COUNT; i++) 0073 uiGeneralTab.cbNorm->addItem(i18n(nsl_corr_norm_name[i])); 0074 0075 auto* layout = new QHBoxLayout(ui.tabGeneral); 0076 layout->setContentsMargins(0, 0, 0, 0); 0077 layout->addWidget(generalTab); 0078 0079 DEBUG("XYCorrelationCurveDock::setupGeneral() DONE"); 0080 0081 // Slots 0082 connect(uiGeneralTab.cbDataSourceType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &XYCorrelationCurveDock::dataSourceTypeChanged); 0083 connect(uiGeneralTab.sbSamplingInterval, QOverload<double>::of(&NumberSpinBox::valueChanged), this, &XYCorrelationCurveDock::samplingIntervalChanged); 0084 connect(uiGeneralTab.cbAutoRange, &QCheckBox::clicked, this, &XYCorrelationCurveDock::autoRangeChanged); 0085 connect(uiGeneralTab.leMin, &QLineEdit::textChanged, this, &XYCorrelationCurveDock::xRangeMinChanged); 0086 connect(uiGeneralTab.leMax, &QLineEdit::textChanged, this, &XYCorrelationCurveDock::xRangeMaxChanged); 0087 connect(uiGeneralTab.cbType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &XYCorrelationCurveDock::typeChanged); 0088 connect(uiGeneralTab.cbNorm, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &XYCorrelationCurveDock::normChanged); 0089 connect(uiGeneralTab.pbRecalculate, &QPushButton::clicked, this, &XYCorrelationCurveDock::recalculateClicked); 0090 connect(uiGeneralTab.cbPlotRanges, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &XYCorrelationCurveDock::plotRangeChanged); 0091 0092 connect(cbDataSourceCurve, &TreeViewComboBox::currentModelIndexChanged, this, &XYCorrelationCurveDock::dataSourceCurveChanged); 0093 connect(cbXDataColumn, &TreeViewComboBox::currentModelIndexChanged, this, &XYCorrelationCurveDock::xDataColumnChanged); 0094 connect(cbYDataColumn, &TreeViewComboBox::currentModelIndexChanged, this, &XYCorrelationCurveDock::yDataColumnChanged); 0095 connect(cbY2DataColumn, &TreeViewComboBox::currentModelIndexChanged, this, &XYCorrelationCurveDock::y2DataColumnChanged); 0096 } 0097 0098 void XYCorrelationCurveDock::initGeneralTab() { 0099 // show the properties of the first curve 0100 // hide x-Range per default 0101 uiGeneralTab.lXRange->setEnabled(false); 0102 uiGeneralTab.cbAutoRange->setEnabled(false); 0103 0104 uiGeneralTab.cbDataSourceType->setCurrentIndex(static_cast<int>(m_correlationCurve->dataSourceType())); 0105 this->dataSourceTypeChanged(uiGeneralTab.cbDataSourceType->currentIndex()); 0106 cbDataSourceCurve->setAspect(m_correlationCurve->dataSourceCurve()); 0107 cbXDataColumn->setColumn(m_correlationCurve->xDataColumn(), m_correlationCurve->xDataColumnPath()); 0108 cbYDataColumn->setColumn(m_correlationCurve->yDataColumn(), m_correlationCurve->yDataColumnPath()); 0109 cbY2DataColumn->setColumn(m_correlationCurve->y2DataColumn(), m_correlationCurve->y2DataColumnPath()); 0110 uiGeneralTab.sbSamplingInterval->setValue(m_correlationData.samplingInterval); 0111 uiGeneralTab.cbAutoRange->setChecked(m_correlationData.autoRange); 0112 0113 const auto numberLocale = QLocale(); 0114 uiGeneralTab.leMin->setText(numberLocale.toString(m_correlationData.xRange.first())); 0115 uiGeneralTab.leMax->setText(numberLocale.toString(m_correlationData.xRange.last())); 0116 this->autoRangeChanged(); 0117 y2DataColumnChanged(cbY2DataColumn->currentModelIndex()); 0118 0119 // settings 0120 uiGeneralTab.cbType->setCurrentIndex(m_correlationData.type); 0121 // m_correlationData.method not used 0122 uiGeneralTab.cbNorm->setCurrentIndex(m_correlationData.normalize); 0123 0124 this->showCorrelationResult(); 0125 0126 uiGeneralTab.chkLegendVisible->setChecked(m_curve->legendVisible()); 0127 uiGeneralTab.chkVisible->setChecked(m_curve->isVisible()); 0128 0129 // Slots 0130 connect(m_correlationCurve, &XYCorrelationCurve::dataSourceTypeChanged, this, &XYCorrelationCurveDock::curveDataSourceTypeChanged); 0131 connect(m_correlationCurve, &XYCorrelationCurve::dataSourceCurveChanged, this, &XYCorrelationCurveDock::curveDataSourceCurveChanged); 0132 connect(m_correlationCurve, &XYCorrelationCurve::xDataColumnChanged, this, &XYCorrelationCurveDock::curveXDataColumnChanged); 0133 connect(m_correlationCurve, &XYCorrelationCurve::yDataColumnChanged, this, &XYCorrelationCurveDock::curveYDataColumnChanged); 0134 connect(m_correlationCurve, &XYCorrelationCurve::y2DataColumnChanged, this, &XYCorrelationCurveDock::curveY2DataColumnChanged); 0135 connect(m_correlationCurve, &XYCorrelationCurve::correlationDataChanged, this, &XYCorrelationCurveDock::curveCorrelationDataChanged); 0136 connect(m_correlationCurve, &XYCorrelationCurve::sourceDataChanged, this, &XYCorrelationCurveDock::enableRecalculate); 0137 } 0138 0139 void XYCorrelationCurveDock::setModel() { 0140 auto list = defaultColumnTopLevelClasses(); 0141 list.append(AspectType::XYCorrelationCurve); 0142 0143 XYAnalysisCurveDock::setModel(list); 0144 } 0145 0146 /*! 0147 sets the curves. The properties of the curves in the list \c list can be edited in this widget. 0148 */ 0149 void XYCorrelationCurveDock::setCurves(QList<XYCurve*> list) { 0150 CONDITIONAL_LOCK_RETURN; 0151 m_curvesList = list; 0152 m_curve = list.first(); 0153 setAspects(list); 0154 setAnalysisCurves(list); 0155 m_correlationCurve = static_cast<XYCorrelationCurve*>(m_curve); 0156 this->setModel(); 0157 m_correlationData = m_correlationCurve->correlationData(); 0158 0159 const auto numberLocale = QLocale(); 0160 uiGeneralTab.sbSamplingInterval->setLocale(numberLocale); 0161 0162 initGeneralTab(); 0163 initTabs(); 0164 setSymbols(list); 0165 0166 updatePlotRangeList(); 0167 } 0168 0169 //************************************************************* 0170 //**** SLOTs for changes triggered in XYCorrelationCurveDock ** 0171 //************************************************************* 0172 void XYCorrelationCurveDock::dataSourceTypeChanged(int index) { 0173 auto type = (XYAnalysisCurve::DataSourceType)index; 0174 if (type == XYAnalysisCurve::DataSourceType::Spreadsheet) { 0175 uiGeneralTab.lDataSourceCurve->hide(); 0176 cbDataSourceCurve->hide(); 0177 uiGeneralTab.lXColumn->show(); 0178 cbXDataColumn->show(); 0179 uiGeneralTab.lYColumn->show(); 0180 cbYDataColumn->show(); 0181 uiGeneralTab.lY2Column->show(); 0182 cbY2DataColumn->show(); 0183 uiGeneralTab.lSamplingInterval->show(); 0184 uiGeneralTab.l2SamplingInterval->show(); 0185 uiGeneralTab.sbSamplingInterval->show(); 0186 } else { 0187 uiGeneralTab.lDataSourceCurve->show(); 0188 cbDataSourceCurve->show(); 0189 uiGeneralTab.lXColumn->hide(); 0190 cbXDataColumn->hide(); 0191 uiGeneralTab.lYColumn->hide(); 0192 cbYDataColumn->hide(); 0193 uiGeneralTab.lY2Column->hide(); 0194 cbY2DataColumn->hide(); 0195 uiGeneralTab.lSamplingInterval->hide(); 0196 uiGeneralTab.l2SamplingInterval->hide(); 0197 uiGeneralTab.sbSamplingInterval->hide(); 0198 } 0199 0200 CONDITIONAL_LOCK_RETURN; 0201 0202 for (auto* curve : m_curvesList) 0203 static_cast<XYCorrelationCurve*>(curve)->setDataSourceType(type); 0204 0205 enableRecalculate(); 0206 } 0207 0208 void XYCorrelationCurveDock::xDataColumnChanged(const QModelIndex& index) { 0209 CONDITIONAL_LOCK_RETURN; 0210 0211 auto* column = static_cast<AbstractColumn*>(index.internalPointer()); 0212 for (auto* curve : m_curvesList) 0213 static_cast<XYCorrelationCurve*>(curve)->setXDataColumn(column); 0214 0215 if (column && uiGeneralTab.cbAutoRange->isChecked()) { 0216 const auto numberLocale = QLocale(); 0217 uiGeneralTab.leMin->setText(numberLocale.toString(column->minimum())); 0218 uiGeneralTab.leMax->setText(numberLocale.toString(column->maximum())); 0219 } 0220 0221 enableRecalculate(); 0222 } 0223 0224 void XYCorrelationCurveDock::samplingIntervalChanged() { 0225 double samplingInterval = uiGeneralTab.sbSamplingInterval->value(); 0226 m_correlationData.samplingInterval = samplingInterval; 0227 0228 enableRecalculate(); 0229 } 0230 0231 void XYCorrelationCurveDock::autoRangeChanged() { 0232 bool autoRange = uiGeneralTab.cbAutoRange->isChecked(); 0233 m_correlationData.autoRange = autoRange; 0234 0235 if (autoRange) { 0236 uiGeneralTab.lMin->setEnabled(false); 0237 uiGeneralTab.leMin->setEnabled(false); 0238 uiGeneralTab.lMax->setEnabled(false); 0239 uiGeneralTab.leMax->setEnabled(false); 0240 0241 const AbstractColumn* xDataColumn = nullptr; 0242 if (m_correlationCurve->dataSourceType() == XYAnalysisCurve::DataSourceType::Spreadsheet) 0243 xDataColumn = m_correlationCurve->xDataColumn(); 0244 else { 0245 if (m_correlationCurve->dataSourceCurve()) 0246 xDataColumn = m_correlationCurve->dataSourceCurve()->xColumn(); 0247 } 0248 0249 if (xDataColumn) { 0250 const auto numberLocale = QLocale(); 0251 uiGeneralTab.leMin->setText(numberLocale.toString(xDataColumn->minimum())); 0252 uiGeneralTab.leMax->setText(numberLocale.toString(xDataColumn->maximum())); 0253 } 0254 } else { 0255 uiGeneralTab.lMin->setEnabled(true); 0256 uiGeneralTab.leMin->setEnabled(true); 0257 uiGeneralTab.lMax->setEnabled(true); 0258 uiGeneralTab.leMax->setEnabled(true); 0259 } 0260 } 0261 void XYCorrelationCurveDock::xRangeMinChanged() { 0262 SET_DOUBLE_FROM_LE_REC(m_correlationData.xRange.first(), uiGeneralTab.leMin); 0263 } 0264 0265 void XYCorrelationCurveDock::xRangeMaxChanged() { 0266 SET_DOUBLE_FROM_LE_REC(m_correlationData.xRange.last(), uiGeneralTab.leMax); 0267 } 0268 0269 void XYCorrelationCurveDock::typeChanged() { 0270 auto type = (nsl_corr_type_type)uiGeneralTab.cbType->currentIndex(); 0271 m_correlationData.type = type; 0272 0273 enableRecalculate(); 0274 } 0275 0276 void XYCorrelationCurveDock::normChanged() { 0277 auto norm = (nsl_corr_norm_type)uiGeneralTab.cbNorm->currentIndex(); 0278 m_correlationData.normalize = norm; 0279 0280 enableRecalculate(); 0281 } 0282 0283 void XYCorrelationCurveDock::recalculateClicked() { 0284 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); 0285 0286 for (auto* curve : m_curvesList) 0287 static_cast<XYCorrelationCurve*>(curve)->setCorrelationData(m_correlationData); 0288 0289 uiGeneralTab.pbRecalculate->setEnabled(false); 0290 Q_EMIT info(i18n("Correlation status: %1", m_correlationCurve->correlationResult().status)); 0291 QApplication::restoreOverrideCursor(); 0292 } 0293 0294 /*! 0295 * show the result and details of the correlation 0296 */ 0297 void XYCorrelationCurveDock::showCorrelationResult() { 0298 showResult(m_correlationCurve, uiGeneralTab.teResult); 0299 } 0300 0301 //************************************************************* 0302 //*********** SLOTs for changes triggered in XYCurve ********** 0303 //************************************************************* 0304 // General-Tab 0305 void XYCorrelationCurveDock::curveXDataColumnChanged(const AbstractColumn* column) { 0306 DEBUG("XYCorrelationCurveDock::curveXDataColumnChanged()"); 0307 if (column) { 0308 DEBUG("X Column available"); 0309 uiGeneralTab.lXRange->setEnabled(true); 0310 uiGeneralTab.cbAutoRange->setEnabled(true); 0311 uiGeneralTab.lSamplingInterval->setEnabled(false); 0312 uiGeneralTab.l2SamplingInterval->setEnabled(false); 0313 uiGeneralTab.sbSamplingInterval->setEnabled(false); 0314 } else { 0315 DEBUG("X Column not available"); 0316 uiGeneralTab.lXRange->setEnabled(false); 0317 uiGeneralTab.cbAutoRange->setEnabled(false); 0318 uiGeneralTab.lSamplingInterval->setEnabled(true); 0319 uiGeneralTab.l2SamplingInterval->setEnabled(true); 0320 uiGeneralTab.sbSamplingInterval->setEnabled(true); 0321 } 0322 CONDITIONAL_LOCK_RETURN; 0323 cbXDataColumn->setColumn(column, m_correlationCurve->xDataColumnPath()); 0324 enableRecalculate(); 0325 } 0326 0327 void XYCorrelationCurveDock::curveY2DataColumnChanged(const AbstractColumn* column) { 0328 CONDITIONAL_LOCK_RETURN; 0329 cbY2DataColumn->setColumn(column, m_correlationCurve->y2DataColumnPath()); 0330 enableRecalculate(); 0331 } 0332 0333 void XYCorrelationCurveDock::curveCorrelationDataChanged(const XYCorrelationCurve::CorrelationData& correlationData) { 0334 CONDITIONAL_LOCK_RETURN; 0335 m_correlationData = correlationData; 0336 0337 this->showCorrelationResult(); 0338 }