feat(nmNum): 调整结果入口与阈值显示

- 移除 Results 按钮和 Valid runs 提示。
- 右键控制图内阈值显示,随拖动和重置更新。
- 删除阈值悬停提示,保留散点参数提示。
feature/Sensitivity-20261012
lvjunjie 1 week ago
parent 111f496579
commit a1356f5555

@ -73,7 +73,6 @@ signals:
void sigGenerateClicked(); // 点击生成按钮时发出的信号 void sigGenerateClicked(); // 点击生成按钮时发出的信号
// 敏感性批量任务交给所属主窗口,复用普通求解进度框。 // 敏感性批量任务交给所属主窗口,复用普通求解进度框。
void sigSensitivityTaskReady(nmWxSensitive* dialog, nmCalculationDllPebiSolverTask* task); void sigSensitivityTaskReady(nmWxSensitive* dialog, nmCalculationDllPebiSolverTask* task);
void sigSensitiveResultsRequested();
void sigIncludeWells(); // 包含其他井后刷新参数栏的信号 void sigIncludeWells(); // 包含其他井后刷新参数栏的信号
/** @brief 用户切换结果井时发送快照中的稳定井 UUID。 */ /** @brief 用户切换结果井时发送快照中的稳定井 UUID。 */
void sigResultWellChanged(const QString& sWellInstanceId); void sigResultWellChanged(const QString& sWellInstanceId);

@ -25,6 +25,7 @@ class SensitivityDistributionPlot;
class SensitivityResultsModel; class SensitivityResultsModel;
class iGuiPlot; class iGuiPlot;
class QMenu; class QMenu;
class QAction;
class NM_SUB_WXS_EXPORT nmWxSensitivityHistogramOptions : public iDlgBase class NM_SUB_WXS_EXPORT nmWxSensitivityHistogramOptions : public iDlgBase
{ {
@ -54,6 +55,7 @@ private slots:
void updateThreshold(); void updateThreshold();
void resetThreshold(); void resetThreshold();
void adjustContextMenu(QMenu* menu); void adjustContextMenu(QMenu* menu);
void updateLegend();
private: private:
QSharedPointer<nmDataSensitive::BatchResult> m_results; QSharedPointer<nmDataSensitive::BatchResult> m_results;
double m_baseError; double m_baseError;
@ -62,6 +64,7 @@ private:
QComboBox* m_parameter; QComboBox* m_parameter;
double m_threshold; double m_threshold;
QLabel* m_legend; QLabel* m_legend;
QAction* m_resultsInPlot;
iGuiPlot* m_plot; iGuiPlot* m_plot;
QVector<QPointF> m_points; QVector<QPointF> m_points;
QVector<int> m_runRows; QVector<int> m_runRows;
@ -98,7 +101,6 @@ public:
signals: signals:
void sigSensitivityTaskReady(nmWxSensitive* dialog, nmCalculationDllPebiSolverTask* task); void sigSensitivityTaskReady(nmWxSensitive* dialog, nmCalculationDllPebiSolverTask* task);
void sigSensitivityCancelRequested(); void sigSensitivityCancelRequested();
void sigSensitiveResultsRequested();
public slots: public slots:
void reject() override; void reject() override;
@ -118,7 +120,6 @@ protected:
void onPreviewClicked(); void onPreviewClicked();
void onPreviewScrollAction(int action); void onPreviewScrollAction(int action);
void onSensitivityFinished(); void onSensitivityFinished();
void onResultsClicked();
void onResultsChanged(); void onResultsChanged();
void onModelResultChanged(); void onModelResultChanged();
@ -149,7 +150,6 @@ private:
QPushButton *generateButton; QPushButton *generateButton;
QPushButton *cancelButton; QPushButton *cancelButton;
QPushButton *previewButton; QPushButton *previewButton;
QPushButton *resultsButton;
// 各个变量页面的控件列表 // 各个变量页面的控件列表
QList<QComboBox*> m_modeCombos; QList<QComboBox*> m_modeCombos;

@ -2013,7 +2013,7 @@ void nmSubWndMain::onShowSensitiveResults()
curve->setVisible(!hidden.contains(curve->getName())); curve->setVisible(!hidden.contains(curve->getName()));
plot->setReadOnly(true); plot->setReadOnly(true);
plot->freshAxisScales(true, false); plot->freshAxisScales(true, false);
// 关闭后仍可通过 Results 恢复;只有新建或恢复窗口时才重新调整内部布局。 // 只有新建或恢复窗口时才重新调整内部布局。
QMdiSubWindow* subWindow = nullptr; QMdiSubWindow* subWindow = nullptr;
for(QWidget* parent = plot->parentWidget(); parent && !subWindow; parent = parent->parentWidget()) for(QWidget* parent = plot->parentWidget(); parent && !subWindow; parent = parent->parentWidget())
subWindow = qobject_cast<QMdiSubWindow*>(parent); subWindow = qobject_cast<QMdiSubWindow*>(parent);
@ -2206,9 +2206,6 @@ void nmSubWndMain::updateSensitiveHistogramPlot()
settings->setObjectName("nmHistogramOptionsButton"); settings->setObjectName("nmHistogramOptionsButton");
options->addWidget(scatter); options->addWidget(scatter);
options->addWidget(settings); options->addWidget(settings);
QLabel* count = new QLabel(page);
count->setObjectName("nmHistogramCount");
options->addWidget(count);
options->addStretch(); options->addStretch();
layout->addLayout(options); layout->addLayout(options);
iGuiPlot* plot = new iGuiPlot(true, page); iGuiPlot* plot = new iGuiPlot(true, page);
@ -2239,8 +2236,6 @@ void nmSubWndMain::updateSensitiveHistogramPlot()
if(run.m_bSucceeded && !run.m_bCancelled && qIsFinite(run.m_dPressureRmse) && run.m_dPressureRmse >= 0.0) if(run.m_bSucceeded && !run.m_bCancelled && qIsFinite(run.m_dPressureRmse) && run.m_dPressureRmse >= 0.0)
errors.append(run.m_dPressureRmse); errors.append(run.m_dPressureRmse);
} }
window->findChild<QLabel*>("nmHistogramCount")->setText(errors.isEmpty()
? tr("No valid goodness-of-fit results") : tr("Valid runs: %1").arg(errors.size()));
double minimum = 0.0, maximum = 1.0; double minimum = 0.0, maximum = 1.0;
if(!errors.isEmpty()) { if(!errors.isEmpty()) {
minimum = maximum = errors.first(); minimum = maximum = errors.first();

@ -483,8 +483,6 @@ void nmSubWndUtils::setupNumericalDockWidgets(nmDataAnalyzeManager* pDataManager
pSubWndMain, SLOT(onGenerateButtonClicked())); pSubWndMain, SLOT(onGenerateButtonClicked()));
connect(pAnalWx, SIGNAL(sigSensitivityTaskReady(nmWxSensitive*,nmCalculationDllPebiSolverTask*)), connect(pAnalWx, SIGNAL(sigSensitivityTaskReady(nmWxSensitive*,nmCalculationDllPebiSolverTask*)),
pSubWndMain, SLOT(onSensitivityTaskReady(nmWxSensitive*,nmCalculationDllPebiSolverTask*))); pSubWndMain, SLOT(onSensitivityTaskReady(nmWxSensitive*,nmCalculationDllPebiSolverTask*)));
connect(pAnalWx, SIGNAL(sigSensitiveResultsRequested()),
pSubWndMain, SLOT(onShowSensitiveResults()));
connect(pAnalWx, SIGNAL(sigResultWellChanged(QString)), connect(pAnalWx, SIGNAL(sigResultWellChanged(QString)),
pSubWndMain, SLOT(onWellSelected(QString))); pSubWndMain, SLOT(onWellSelected(QString)));

@ -1464,7 +1464,6 @@ void nmWxNumericalDesign::onSensitiveClicked()
// 按数值生成按钮的现有路径,将任务请求转发给所属主窗口。 // 按数值生成按钮的现有路径,将任务请求转发给所属主窗口。
connect(dlg, SIGNAL(sigSensitivityTaskReady(nmWxSensitive*,nmCalculationDllPebiSolverTask*)), connect(dlg, SIGNAL(sigSensitivityTaskReady(nmWxSensitive*,nmCalculationDllPebiSolverTask*)),
this, SIGNAL(sigSensitivityTaskReady(nmWxSensitive*,nmCalculationDllPebiSolverTask*))); this, SIGNAL(sigSensitivityTaskReady(nmWxSensitive*,nmCalculationDllPebiSolverTask*)));
connect(dlg, SIGNAL(sigSensitiveResultsRequested()), this, SIGNAL(sigSensitiveResultsRequested()));
dlg->show(); dlg->show();
} }

@ -37,6 +37,7 @@
#include "tCurvePlotView.h" #include "tCurvePlotView.h"
#include "iCurveDesc.h" #include "iCurveDesc.h"
#include <QMenu> #include <QMenu>
#include <QAction>
#include <QHelpEvent> #include <QHelpEvent>
#include <QToolTip> #include <QToolTip>
#include <QTableWidget> #include <QTableWidget>
@ -516,11 +517,12 @@ nmWxSensitivityScatter::nmWxSensitivityScatter(
layout->addWidget(m_plot); layout->addWidget(m_plot);
// 两项固定图例不使用框架的分组标题,覆盖在绘图区左上角。 // 两项固定图例不使用框架的分组标题,覆盖在绘图区左上角。
m_legend = new QLabel(m_plot->m_pPlotView->viewport()); m_legend = new QLabel(m_plot->m_pPlotView->viewport());
m_legend->setText("<table cellspacing='2'><tr><td>&#9633;</td><td>" + tr("sensitivity data")
+ "</td></tr><tr><td style='color:blue'>&#9632;</td><td>" + tr("reference") + "</td></tr></table>");
m_legend->setStyleSheet("QLabel { background: white; color: black; border: 1px solid #cccccc; }"); m_legend->setStyleSheet("QLabel { background: white; color: black; border: 1px solid #cccccc; }");
m_legend->setAttribute(Qt::WA_TransparentForMouseEvents); m_legend->setAttribute(Qt::WA_TransparentForMouseEvents);
m_legend->adjustSize(); m_resultsInPlot = new QAction(tr("Results in plot"), this);
m_resultsInPlot->setCheckable(true);
connect(m_resultsInPlot, SIGNAL(toggled(bool)), this, SLOT(updateLegend()));
updateLegend();
m_plot->m_pPlotView->viewport()->installEventFilter(this); m_plot->m_pPlotView->viewport()->installEventFilter(this);
connect(m_parameter, SIGNAL(currentIndexChanged(int)), this, SLOT(updateParameter())); connect(m_parameter, SIGNAL(currentIndexChanged(int)), this, SLOT(updateParameter()));
connect(m_plot->m_pPlotView, SIGNAL(sigAdjustContextMenu(QMenu*)), this, SLOT(adjustContextMenu(QMenu*))); connect(m_plot->m_pPlotView, SIGNAL(sigAdjustContextMenu(QMenu*)), this, SLOT(adjustContextMenu(QMenu*)));
@ -608,22 +610,13 @@ void nmWxSensitivityScatter::updateParameter()
void nmWxSensitivityScatter::updateThreshold() void nmWxSensitivityScatter::updateThreshold()
{ {
// 阈值以下的点填黑,范围使用这些采样点的参数值,不包含蓝色基准点。 // 阈值以下的点填黑,并同步图例中的阈值显示。
if(m_parameter->currentIndex() < 0) return; if(m_parameter->currentIndex() < 0) return;
updateLegend();
QVector<QPointF> accepted; QVector<QPointF> accepted;
double lower = 0.0, upper = 0.0;
for(int i = 0; i < m_points.size(); ++i) if(m_points[i].y() < m_threshold) { for(int i = 0; i < m_points.size(); ++i) if(m_points[i].y() < m_threshold) {
if(accepted.isEmpty()) lower = upper = m_points[i].x();
lower = qMin(lower, m_points[i].x());
upper = qMax(upper, m_points[i].x());
accepted.append(m_points[i]); accepted.append(m_points[i]);
} }
const int index = m_parameter->itemData(m_parameter->currentIndex()).toInt();
const nmDataSensitive::VariableSampling& variable = m_results->m_variables[index];
m_plot->setToolTip(tr("Threshold: %1 MPa\n").arg(m_threshold, 0, 'g', 6)
+ tr("Below threshold: %1 / %2; %3 range: %4").arg(accepted.size()).arg(m_points.size())
.arg(variable.m_varName).arg(accepted.isEmpty() ? tr("N/A")
: QString::number(lower, 'g', 6) + " - " + QString::number(upper, 'g', 6) + " " + variable.m_modelValue.getUnit()));
if(m_threshold > m_plot->getAxisOf(1)->getRangeMax()) { if(m_threshold > m_plot->getAxisOf(1)->getRangeMax()) {
VecDouble ticks; VecDouble ticks;
const double top = m_threshold * 1.1; const double top = m_threshold * 1.1;
@ -670,9 +663,21 @@ void nmWxSensitivityScatter::resetThreshold()
void nmWxSensitivityScatter::adjustContextMenu(QMenu* menu) void nmWxSensitivityScatter::adjustContextMenu(QMenu* menu)
{ {
// 复用绘图右键菜单,保留框架的缩放、复制与导出入口。 // 复用绘图右键菜单,保留框架的缩放、复制与导出入口。
menu->addAction(m_resultsInPlot);
menu->addAction(tr("Reset line"), this, SLOT(resetThreshold())); menu->addAction(tr("Reset line"), this, SLOT(resetThreshold()));
} }
void nmWxSensitivityScatter::updateLegend()
{
// 勾选后在原有两项图例下追加阈值,拖线和重置时实时更新。
QString text = "<table cellspacing='2'><tr><td>&#9633;</td><td>" + tr("sensitivity data")
+ "</td></tr><tr><td style='color:blue'>&#9632;</td><td>" + tr("reference") + "</td></tr></table>";
if(m_resultsInPlot->isChecked())
text += "<div>" + tr("Threshold: %1 MPa").arg(m_threshold, 0, 'g', 6) + "</div>";
m_legend->setText(text);
m_legend->adjustSize();
}
bool nmWxSensitivityScatter::eventFilter(QObject* object, QEvent* event) bool nmWxSensitivityScatter::eventFilter(QObject* object, QEvent* event)
{ {
if(object != m_plot->m_pPlotView->viewport()) return iDlgBase::eventFilter(object, event); if(object != m_plot->m_pPlotView->viewport()) return iDlgBase::eventFilter(object, event);
@ -707,7 +712,8 @@ bool nmWxSensitivityScatter::eventFilter(QObject* object, QEvent* event)
.arg(run.m_dPressureRmse, 0, 'g', 6), view->viewport()); .arg(run.m_dPressureRmse, 0, 'g', 6), view->viewport());
return true; return true;
} }
QToolTip::showText(help->globalPos(), m_plot->toolTip(), view->viewport()); QToolTip::hideText();
event->ignore();
return true; return true;
} }
return iDlgBase::eventFilter(object, event); return iDlgBase::eventFilter(object, event);
@ -1173,7 +1179,7 @@ nmWxSensitive::nmWxSensitive(QWidget *parent, nmDataAnalyzeManager* manager)
loadDataToUI(); loadDataToUI();
m_loading = false; m_loading = false;
onTreeItemChanged(nullptr, 0); onTreeItemChanged(nullptr, 0);
// 已有批次可直接重新打开,结果发布后同步入口与列表。 // 结果发布或清除后,同步本窗口持有的批次数据。
if(m_pDataManager) { if(m_pDataManager) {
connect(m_pDataManager, SIGNAL(sigSensitiveResultsChanged()), this, SLOT(onResultsChanged())); connect(m_pDataManager, SIGNAL(sigSensitiveResultsChanged()), this, SLOT(onResultsChanged()));
connect(m_pDataManager, SIGNAL(sigPebiResultSnapshotChanged()), this, SLOT(onModelResultChanged())); connect(m_pDataManager, SIGNAL(sigPebiResultSnapshotChanged()), this, SLOT(onModelResultChanged()));
@ -1694,11 +1700,9 @@ void nmWxSensitive::setupUI()
bottomLayout->addWidget(previewButton); bottomLayout->addWidget(previewButton);
bottomLayout->addStretch(); bottomLayout->addStretch();
resultsButton = new QPushButton(tr("Results"), this);
generateButton = new QPushButton(tr("Generate"), this); generateButton = new QPushButton(tr("Generate"), this);
cancelButton = new QPushButton(tr("Cancel"), this); cancelButton = new QPushButton(tr("Cancel"), this);
bottomLayout->addWidget(resultsButton);
bottomLayout->addWidget(generateButton); bottomLayout->addWidget(generateButton);
bottomLayout->addWidget(cancelButton); bottomLayout->addWidget(cancelButton);
@ -1714,7 +1718,6 @@ void nmWxSensitive::createConnections()
connect(cancelButton, SIGNAL(clicked()), connect(cancelButton, SIGNAL(clicked()),
this, SLOT(onCancelClicked())); this, SLOT(onCancelClicked()));
connect(previewButton, SIGNAL(clicked()), this, SLOT(onPreviewClicked())); connect(previewButton, SIGNAL(clicked()), this, SLOT(onPreviewClicked()));
connect(resultsButton, SIGNAL(clicked()), this, SLOT(onResultsClicked()));
connect(calculationTypeCombo, SIGNAL(currentIndexChanged(int)), connect(calculationTypeCombo, SIGNAL(currentIndexChanged(int)),
this, SLOT(onCalculationTypeChanged(int))); this, SLOT(onCalculationTypeChanged(int)));
@ -2408,22 +2411,12 @@ void nmWxSensitive::onSensitivityFinished()
QMessageBox::warning(ownerWindow, tr("Sensitivity"), message); QMessageBox::warning(ownerWindow, tr("Sensitivity"), message);
} }
void nmWxSensitive::onResultsClicked()
{
// Results 只打开或恢复结果图,曲线显示由各图自己的 Show 控制。
onResultsChanged();
if(!resultsButton->isEnabled()) return;
emit sigSensitiveResultsRequested();
hide();
}
void nmWxSensitive::onResultsChanged() void nmWxSensitive::onResultsChanged()
{ {
// 新模型清除旧批次后同步禁用结果入口。 // 同步当前批次,新模型清除旧结果时也清除本地引用。
QSharedPointer<nmDataSensitive::BatchResult> results; QSharedPointer<nmDataSensitive::BatchResult> results;
if(m_pDataManager && m_pDataManager->getSensitiveData()) if(m_pDataManager && m_pDataManager->getSensitiveData())
results = m_pDataManager->getSensitiveData()->getResults(); results = m_pDataManager->getSensitiveData()->getResults();
resultsButton->setEnabled(!results.isNull());
m_sensitiveData.setResults(results); m_sensitiveData.setResults(results);
} }

Loading…
Cancel
Save