用于散点图的排序浮点向量(C++/QCustomPlot)
Sorted Float Vectors for Scatter Plotting (C++ / QCustomPlot)
问题:
1 - 按相同顺序对多个浮点向量进行排序(保持对应)
2 - QCustomPlot (QCP) 仅绘制散点图的外边界。
(回答这两个问题中的任何一个都可以解决我的问题)
情况:
我有 3 个绘图向量:
std::vector<float> x, y;
std::vector<int> hits;
生成的图是命中或未命中的散点图。生成的图被 QCustomPlot 的曲线使用,它最终是一个圆形 "scribble." 它只需要看起来类似于一个内部没有 "scribbling" 的圆。我需要这个图覆盖另一个图。
我无法控制 x
、y
或 hits
的初始顺序。
x
和 y
在传统的网格索引中排序:
x = -8, -8, -8, -8, -8, -4, -4, -4, -4, -4, ... 8
y = -8, -4, 0, 4, 8, -8, -4, 0, 4, 8, ... 8
hits
是基于是否成功命中(假设是弓箭手的箭)基于快速目标(假设是鸟)的射程和速度。
结果图是以鸟为中心参考的命中外边界。
数据向量可以非常大。
方法一:我可以计算范围和角度。然后对浮点向量进行排序:按顺序对角度进行排序,这样当 QCustomPlot 绘制外边界时,内部没有 'scribbles'。但是,我需要知道如何根据 angle
.
的排序将相应的 x
和 y
值保持在一起
// Make range and angle vectors for sorting
std::vector<float> range, angle;
for(int i = 0; i < x.size(); ++i {
float r = sqrt(x[i]*x[i] + y[i]*y[i]);
range.push_back(r);
float a = 0;
if(y < 0)
a = -acos(x[i]/r);
else
a = acos(x[i]/r);
angle.push_back(a);
}
// Sort all vectors by ascending angle vector.
/* Do stuff here! */
// Set up boundary plot data
QVector<float> plot_x, plot_y;
for(int i = 0; i < x.size(); ++i {
if(hits[i]) {
plot_x.push_back(x[i]);
plot_y.push_back(y[i]);
}
}
// curve is a QCPCurve object already existing.
curve->addData(plot_x, plot_y); // Already sorted QVectors
方法二:获取QCustomPlot
curve->addData(x, y)
成员只绘制hits
散点图的一个"perimeter line"。我曾尝试使用 QCPScatterStyle
、.setCustomPath
,但没有成功。
提前致谢!
-约翰
如果您想使用一些标准对多个向量进行排序并且所有索引都对应创建一个作为索引的新向量并对其进行排序,然后使用这些索引创建新向量:
#include <cmath>
#include <QDebug>
static float calc_angle(float x, float y){
float r = sqrt(x*x + y*y);
float angle = acos(x/r);
return y<0 ? -angle : angle;
}
int main(int argc, char *argv[])
{
std::vector<int> hits{0, 1, 2, 1, 0, 1, 2, 1, 0, 1};
std::vector<float> x{-8, -8, -8, -8, -8, -4, -4, -4, -4, -4};
std::vector<float> y{-8, -4, 0, 4, 8, -8, -4, 0, 4, 8};
Q_ASSERT(x.size() == y.size() && y.size() == hits.size());
std::vector<int> indexes(x.size());
std::iota(indexes.begin(), indexes.end(), 0);
std::sort(indexes.begin(), indexes.end(), [&](const int & i, const int & j) -> bool{
return calc_angle(x[i], y[i]) < calc_angle(x[j], y[i]);
});
QVector<float> plot_x, plot_y;
QVector<int> new_hits;
for(const int & index : indexes){
plot_x<<x[index];
plot_y<<y[index];
new_hits<<hits[index];
}
qDebug()<<indexes;
qDebug()<< plot_x;
qDebug()<<plot_y;
qDebug()<<new_hits;
return 0;//a.exec();
}
输出:
std::vector(8, 0, 1, 2, 3, 4, 5, 6, 7, 9)
QVector(-4, -8, -8, -8, -8, -8, -4, -4, -4, -4)
QVector(4, -8, -4, 0, 4, 8, -8, -4, 0, 8)
QVector(0, 0, 1, 2, 1, 0, 1, 2, 1, 1)
问题:
1 - 按相同顺序对多个浮点向量进行排序(保持对应)
2 - QCustomPlot (QCP) 仅绘制散点图的外边界。
(回答这两个问题中的任何一个都可以解决我的问题)
情况:
我有 3 个绘图向量:
std::vector<float> x, y;
std::vector<int> hits;
生成的图是命中或未命中的散点图。生成的图被 QCustomPlot 的曲线使用,它最终是一个圆形 "scribble." 它只需要看起来类似于一个内部没有 "scribbling" 的圆。我需要这个图覆盖另一个图。
我无法控制 x
、y
或 hits
的初始顺序。
x
和 y
在传统的网格索引中排序:
x = -8, -8, -8, -8, -8, -4, -4, -4, -4, -4, ... 8
y = -8, -4, 0, 4, 8, -8, -4, 0, 4, 8, ... 8
hits
是基于是否成功命中(假设是弓箭手的箭)基于快速目标(假设是鸟)的射程和速度。
结果图是以鸟为中心参考的命中外边界。
数据向量可以非常大。
方法一:我可以计算范围和角度。然后对浮点向量进行排序:按顺序对角度进行排序,这样当 QCustomPlot 绘制外边界时,内部没有 'scribbles'。但是,我需要知道如何根据 angle
.
x
和 y
值保持在一起
// Make range and angle vectors for sorting
std::vector<float> range, angle;
for(int i = 0; i < x.size(); ++i {
float r = sqrt(x[i]*x[i] + y[i]*y[i]);
range.push_back(r);
float a = 0;
if(y < 0)
a = -acos(x[i]/r);
else
a = acos(x[i]/r);
angle.push_back(a);
}
// Sort all vectors by ascending angle vector.
/* Do stuff here! */
// Set up boundary plot data
QVector<float> plot_x, plot_y;
for(int i = 0; i < x.size(); ++i {
if(hits[i]) {
plot_x.push_back(x[i]);
plot_y.push_back(y[i]);
}
}
// curve is a QCPCurve object already existing.
curve->addData(plot_x, plot_y); // Already sorted QVectors
方法二:获取QCustomPlot
curve->addData(x, y)
成员只绘制hits
散点图的一个"perimeter line"。我曾尝试使用 QCPScatterStyle
、.setCustomPath
,但没有成功。
提前致谢! -约翰
如果您想使用一些标准对多个向量进行排序并且所有索引都对应创建一个作为索引的新向量并对其进行排序,然后使用这些索引创建新向量:
#include <cmath>
#include <QDebug>
static float calc_angle(float x, float y){
float r = sqrt(x*x + y*y);
float angle = acos(x/r);
return y<0 ? -angle : angle;
}
int main(int argc, char *argv[])
{
std::vector<int> hits{0, 1, 2, 1, 0, 1, 2, 1, 0, 1};
std::vector<float> x{-8, -8, -8, -8, -8, -4, -4, -4, -4, -4};
std::vector<float> y{-8, -4, 0, 4, 8, -8, -4, 0, 4, 8};
Q_ASSERT(x.size() == y.size() && y.size() == hits.size());
std::vector<int> indexes(x.size());
std::iota(indexes.begin(), indexes.end(), 0);
std::sort(indexes.begin(), indexes.end(), [&](const int & i, const int & j) -> bool{
return calc_angle(x[i], y[i]) < calc_angle(x[j], y[i]);
});
QVector<float> plot_x, plot_y;
QVector<int> new_hits;
for(const int & index : indexes){
plot_x<<x[index];
plot_y<<y[index];
new_hits<<hits[index];
}
qDebug()<<indexes;
qDebug()<< plot_x;
qDebug()<<plot_y;
qDebug()<<new_hits;
return 0;//a.exec();
}
输出:
std::vector(8, 0, 1, 2, 3, 4, 5, 6, 7, 9)
QVector(-4, -8, -8, -8, -8, -8, -4, -4, -4, -4)
QVector(4, -8, -4, 0, 4, 8, -8, -4, 0, 8)
QVector(0, 0, 1, 2, 1, 0, 1, 2, 1, 1)