Alignment options for waterfall plot

This commit is contained in:
Jan Käberich 2022-03-16 23:56:44 +01:00
parent bd69646c32
commit 1a779531ea
6 changed files with 120 additions and 30 deletions

View File

@ -5,6 +5,7 @@
#include "Util/util.h" #include "Util/util.h"
#include "waterfallaxisdialog.h" #include "waterfallaxisdialog.h"
#include "appwindow.h" #include "appwindow.h"
#include "tracexyplot.h"
#include <QFileDialog> #include <QFileDialog>
#include <QPainter> #include <QPainter>
@ -14,6 +15,7 @@ using namespace std;
TraceWaterfall::TraceWaterfall(TraceModel &model, QWidget *parent) TraceWaterfall::TraceWaterfall(TraceModel &model, QWidget *parent)
: TracePlot(model, parent), : TracePlot(model, parent),
dir(Direction::TopToBottom), dir(Direction::TopToBottom),
align(Alignment::PrimaryOnly),
trace(nullptr), trace(nullptr),
pixelsPerLine(1), pixelsPerLine(1),
keepDataBeyondPlotSize(false), keepDataBeyondPlotSize(false),
@ -63,6 +65,10 @@ void TraceWaterfall::fromJSON(nlohmann::json j)
} else { } else {
dir = Direction::BottomToTop; dir = Direction::BottomToTop;
} }
align = AlignmentFromString(QString::fromStdString(j.value("alignment", "")));
if(align == Alignment::Last) {
align = Alignment::PrimaryOnly;
}
for(unsigned int hash : j["traces"]) { for(unsigned int hash : j["traces"]) {
// attempt to find the traces with this hash // attempt to find the traces with this hash
@ -87,6 +93,7 @@ nlohmann::json TraceWaterfall::toJSON()
j["direction"] = dir == Direction::TopToBottom ? "TopToBottom" : "BottomToTop"; j["direction"] = dir == Direction::TopToBottom ? "TopToBottom" : "BottomToTop";
j["keepDataBeyondPlot"] = keepDataBeyondPlotSize; j["keepDataBeyondPlot"] = keepDataBeyondPlotSize;
j["maxLines"] = maxDataSweeps; j["maxLines"] = maxDataSweeps;
j["alignment"] = AlignmentToString(align).toStdString();
nlohmann::json jtraces; nlohmann::json jtraces;
for(auto t : traces) { for(auto t : traces) {
if(t.second) { if(t.second) {
@ -202,26 +209,40 @@ void TraceWaterfall::draw(QPainter &p)
{ {
auto pref = Preferences::getInstance(); auto pref = Preferences::getInstance();
constexpr int yAxisLegendSpace = 25; // constexpr int yAxisLegendSpace = 25;
constexpr int yAxisDisabledSpace = 10; // constexpr int yAxisDisabledSpace = 10;
constexpr int xAxisSpace = 30; constexpr int xAxisSpace = 30;
constexpr int topMargin = 10;
auto w = p.window(); auto w = p.window();
auto pen = QPen(pref.Graphs.Color.axis, 0); auto pen = QPen(pref.Graphs.Color.axis, 0);
pen.setCosmetic(true); pen.setCosmetic(true);
p.setPen(pen); p.setPen(pen);
plotAreaLeft = yAxisDisabledSpace; // plotAreaLeft = yAxisDisabledSpace;
plotAreaWidth = w.width() - 3 * yAxisDisabledSpace - yAxisLegendSpace; // plotAreaWidth = w.width() - 3 * yAxisDisabledSpace - yAxisLegendSpace;
plotAreaTop = 10;
plotAreaBottom = w.height() - xAxisSpace; auto leftMargin = TraceXYPlot::sideMargin(align == Alignment::PrimaryOnly || align == Alignment::BothAxes);
auto rightMargin = TraceXYPlot::sideMargin(align == Alignment::SecondaryOnly || align == Alignment::BothAxes);
auto plotRect = QRect(leftMargin, topMargin, w.width() - leftMargin - rightMargin, w.height()-topMargin-xAxisSpace);
plotAreaTop = plotRect.y();
plotAreaLeft = plotRect.x();
plotAreaWidth = plotRect.width();
plotAreaBottom = plotRect.y()+plotRect.height();
// draw Y legend // draw Y legend
auto plotRect = QRect(w.width() - yAxisDisabledSpace - yAxisLegendSpace, plotAreaTop, yAxisLegendSpace, plotAreaBottom-plotAreaTop); QRect legendRect;
p.drawRect(plotRect); constexpr int legendMargin = 10;
if(leftMargin < rightMargin) {
legendRect = QRect(QPoint(plotRect.x()+plotRect.width()+legendMargin, plotAreaTop), QPoint(width() - legendMargin, plotAreaBottom));
} else {
legendRect = QRect(QPoint(legendMargin, plotAreaTop), QPoint(leftMargin - legendMargin, plotAreaBottom));
}
p.drawRect(legendRect);
for(int i=plotAreaTop + 1;i<plotAreaBottom;i++) { for(int i=plotAreaTop + 1;i<plotAreaBottom;i++) {
auto color = getColor(Util::Scale<double>(i, plotAreaTop, plotAreaBottom, 1.0, 0.0)); auto color = getColor(Util::Scale<double>(i, plotAreaTop, plotAreaBottom, 1.0, 0.0));
p.setPen(QColor(color)); p.setPen(QColor(color));
pen.setCosmetic(true); pen.setCosmetic(true);
p.drawLine(w.width() - yAxisDisabledSpace - yAxisLegendSpace + 1, i, w.width() - yAxisDisabledSpace - 1, i); p.drawLine(legendRect.x()+1, i, legendRect.x()+legendRect.width()-1, i);
} }
QString unit = ""; QString unit = "";
if(pref.Graphs.showUnits) { if(pref.Graphs.showUnits) {
@ -231,17 +252,17 @@ void TraceWaterfall::draw(QPainter &p)
QString labelMax = Unit::ToString(yAxis.getRangeMax(), unit, yAxis.Prefixes(), 4); QString labelMax = Unit::ToString(yAxis.getRangeMax(), unit, yAxis.Prefixes(), 4);
p.setPen(QPen(pref.Graphs.Color.axis, 1)); p.setPen(QPen(pref.Graphs.Color.axis, 1));
p.save(); p.save();
p.translate(w.width() - yAxisDisabledSpace - yAxisLegendSpace, w.height()); p.translate(legendRect.x(), w.height());
p.rotate(-90); p.rotate(-90);
p.drawText(QRect(xAxisSpace + 10, 0, plotAreaBottom - plotAreaTop - 20, yAxisLegendSpace), Qt::AlignRight | Qt::AlignVCenter, labelMax); p.drawText(QRect(xAxisSpace + 10, 0, plotAreaBottom - plotAreaTop - 20, legendRect.width()), Qt::AlignRight | Qt::AlignVCenter, labelMax);
p.drawText(QRect(xAxisSpace + 10, 0, plotAreaBottom - plotAreaTop - 20, yAxisLegendSpace), Qt::AlignLeft | Qt::AlignVCenter, labelMin); p.drawText(QRect(xAxisSpace + 10, 0, plotAreaBottom - plotAreaTop - 20, legendRect.width()), Qt::AlignLeft | Qt::AlignVCenter, labelMin);
p.drawText(QRect(xAxisSpace + 10, 0, plotAreaBottom - plotAreaTop - 20, legendRect.width()), Qt::AlignHCenter | Qt::AlignVCenter, yAxis.TypeToName());
p.restore(); p.restore();
pen = QPen(pref.Graphs.Color.axis, 0); pen = QPen(pref.Graphs.Color.axis, 0);
pen.setCosmetic(true); pen.setCosmetic(true);
p.setPen(pen); p.setPen(pen);
plotRect = QRect(plotAreaLeft, plotAreaTop, plotAreaWidth + 1, plotAreaBottom-plotAreaTop);
p.drawRect(plotRect); p.drawRect(plotRect);
// draw axis types // draw axis types
@ -557,3 +578,24 @@ QColor TraceWaterfall::getColor(double scale)
return Qt::black; return Qt::black;
} }
} }
QString TraceWaterfall::AlignmentToString(Alignment a)
{
switch(a) {
case Alignment::PrimaryOnly: return "Primary Y axis only";
case Alignment::SecondaryOnly: return "Secondary Y axis only";
case Alignment::BothAxes: return "Both Y axes";
case Alignment::Last:
default: return "Invalid";
}
}
TraceWaterfall::Alignment TraceWaterfall::AlignmentFromString(QString s)
{
for(unsigned int i=0;i<(int) Alignment::Last;i++) {
if(s == AlignmentToString((Alignment) i)) {
return (Alignment) i;
}
}
return Alignment::Last;
}

View File

@ -54,7 +54,19 @@ private:
BottomToTop, BottomToTop,
}; };
// match alignment of XYplot with either one or both Y axes enabled
enum class Alignment {
PrimaryOnly = 0,
SecondaryOnly = 1,
BothAxes = 2,
Last,
};
static QString AlignmentToString(Alignment a);
static Alignment AlignmentFromString(QString s);
Direction dir; Direction dir;
Alignment align;
Trace *trace; Trace *trace;

View File

@ -189,6 +189,15 @@ bool TraceXYPlot::isTDRtype(YAxis::Type type)
} }
} }
int TraceXYPlot::sideMargin(bool YAxisEnabled)
{
if(YAxisEnabled) {
return yAxisSpace;
} else {
return yAxisDisabledSpace;
}
}
void TraceXYPlot::axisSetupDialog() void TraceXYPlot::axisSetupDialog()
{ {
auto setup = new XYplotAxisDialog(this); auto setup = new XYplotAxisDialog(this);
@ -321,9 +330,6 @@ void TraceXYPlot::draw(QPainter &p)
{ {
auto pref = Preferences::getInstance(); auto pref = Preferences::getInstance();
constexpr int yAxisSpace = 55;
constexpr int yAxisDisabledSpace = 10;
constexpr int xAxisSpace = 30;
auto w = p.window(); auto w = p.window();
auto pen = QPen(pref.Graphs.Color.axis, 0); auto pen = QPen(pref.Graphs.Color.axis, 0);
pen.setCosmetic(true); pen.setCosmetic(true);

View File

@ -32,6 +32,8 @@ public:
bool isTDRtype(YAxis::Type type); bool isTDRtype(YAxis::Type type);
static int sideMargin(bool YAxisEnabled);
public slots: public slots:
void axisSetupDialog(); void axisSetupDialog();
@ -45,6 +47,9 @@ private slots:
void updateAxisTicks(); void updateAxisTicks();
private: private:
static constexpr int AxisLabelSize = 10; static constexpr int AxisLabelSize = 10;
static constexpr int yAxisSpace = 55;
static constexpr int yAxisDisabledSpace = 10;
static constexpr int xAxisSpace = 30;
static QString AxisModeToName(XAxisMode mode); static QString AxisModeToName(XAxisMode mode);
static XAxisMode AxisModeFromName(QString name); static XAxisMode AxisModeFromName(QString name);
void enableTraceAxis(Trace *t, int axis, bool enabled); void enableTraceAxis(Trace *t, int axis, bool enabled);

View File

@ -39,6 +39,10 @@ WaterfallAxisDialog::WaterfallAxisDialog(TraceWaterfall *plot) :
} }
} }
for(unsigned int i=0;i<(int) TraceWaterfall::Alignment::Last;i++) {
ui->Xalignment->addItem(TraceWaterfall::AlignmentToString((TraceWaterfall::Alignment) i));
}
// Setup GUI connections // Setup GUI connections
connect(ui->Wtype, qOverload<int>(&QComboBox::currentIndexChanged), [=](int index) { connect(ui->Wtype, qOverload<int>(&QComboBox::currentIndexChanged), [=](int index) {
//ui->Y1log->setEnabled(index != 0); //ui->Y1log->setEnabled(index != 0);
@ -95,6 +99,7 @@ WaterfallAxisDialog::WaterfallAxisDialog(TraceWaterfall *plot) :
} else { } else {
ui->Xlinear->setChecked(true); ui->Xlinear->setChecked(true);
} }
ui->Xalignment->setCurrentIndex((int) plot->align);
} }
WaterfallAxisDialog::~WaterfallAxisDialog() WaterfallAxisDialog::~WaterfallAxisDialog()
@ -119,6 +124,7 @@ void WaterfallAxisDialog::on_buttonBox_accepted()
} else { } else {
plot->keepDataBeyondPlotSize = true; plot->keepDataBeyondPlotSize = true;
} }
plot->align = (TraceWaterfall::Alignment) ui->Xalignment->currentIndex();
} }
void WaterfallAxisDialog::XAxisTypeChanged(int XAxisIndex) void WaterfallAxisDialog::XAxisTypeChanged(int XAxisIndex)
@ -158,7 +164,6 @@ std::set<YAxis::Type> WaterfallAxisDialog::supportedYAxis(XAxis::Type type)
ret.insert(YAxis::Type::Magnitude); ret.insert(YAxis::Type::Magnitude);
ret.insert(YAxis::Type::MagnitudeLinear); ret.insert(YAxis::Type::MagnitudeLinear);
ret.insert(YAxis::Type::Phase); ret.insert(YAxis::Type::Phase);
ret.insert(YAxis::Type::UnwrappedPhase);
ret.insert(YAxis::Type::VSWR); ret.insert(YAxis::Type::VSWR);
ret.insert(YAxis::Type::Real); ret.insert(YAxis::Type::Real);
ret.insert(YAxis::Type::Imaginary); ret.insert(YAxis::Type::Imaginary);
@ -167,7 +172,6 @@ std::set<YAxis::Type> WaterfallAxisDialog::supportedYAxis(XAxis::Type type)
ret.insert(YAxis::Type::Capacitance); ret.insert(YAxis::Type::Capacitance);
ret.insert(YAxis::Type::Inductance); ret.insert(YAxis::Type::Inductance);
ret.insert(YAxis::Type::QualityFactor); ret.insert(YAxis::Type::QualityFactor);
ret.insert(YAxis::Type::GroupDelay);
break; break;
case XAxis::Type::Time: case XAxis::Type::Time:
case XAxis::Type::Distance: case XAxis::Type::Distance:

View File

@ -9,7 +9,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>539</width> <width>451</width>
<height>351</height> <height>351</height>
</rect> </rect>
</property> </property>
@ -19,9 +19,9 @@
<property name="modal"> <property name="modal">
<bool>true</bool> <bool>true</bool>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_2"> <layout class="QVBoxLayout" name="verticalLayout_4">
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="1,0,1"> <layout class="QHBoxLayout" name="horizontalLayout_2">
<item> <item>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item> <item>
@ -198,6 +198,9 @@
</item> </item>
<item row="6" column="1"> <item row="6" column="1">
<widget class="QSpinBox" name="WmaxSweeps"> <widget class="QSpinBox" name="WmaxSweeps">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimum"> <property name="minimum">
<number>1</number> <number>1</number>
</property> </property>
@ -292,6 +295,32 @@
</item> </item>
</layout> </layout>
</item> </item>
<item>
<widget class="Line" name="line_8">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Alignment</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="label_11">
<property name="text">
<string>Match XY-Plot with:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="Xalignment"/>
</item>
</layout>
</widget>
</item>
<item> <item>
<spacer name="verticalSpacer"> <spacer name="verticalSpacer">
<property name="orientation"> <property name="orientation">
@ -305,13 +334,6 @@
</property> </property>
</spacer> </spacer>
</item> </item>
<item>
<widget class="Line" name="line_8">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
</layout> </layout>
</item> </item>
</layout> </layout>
@ -371,8 +393,7 @@
</connection> </connection>
</connections> </connections>
<buttongroups> <buttongroups>
<buttongroup name="Y1group"/>
<buttongroup name="Y2group"/>
<buttongroup name="Xgroup"/> <buttongroup name="Xgroup"/>
<buttongroup name="Y1group"/>
</buttongroups> </buttongroups>
</ui> </ui>