Skip to content

Commit 113ae55

Browse files
committed
add segments() and rects() to Plot
1 parent c8457a6 commit 113ae55

11 files changed

Lines changed: 751 additions & 71 deletions

QtSLiM/QtSLiMGraphView_CustomPlot.cpp

Lines changed: 249 additions & 62 deletions
Large diffs are not rendered by default.

QtSLiM/QtSLiMGraphView_CustomPlot.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ class Plot;
3131

3232
enum class QtSLiM_CustomPlotType : int {
3333
kLines,
34+
kSegments,
35+
kRects,
3436
kPoints,
3537
kText,
3638
kABLines, // from abline()
@@ -76,6 +78,12 @@ class QtSLiMGraphView_CustomPlot : public QtSLiMGraphView
7678
void addPointData(double *x_values, double *y_values, int data_count,
7779
std::vector<int> *symbol, std::vector<QColor> *color, std::vector<QColor> *border,
7880
std::vector<double> *alpha, std::vector<double> *lwd, std::vector<double> *size);
81+
void addRectData(double *x1_values, double *y1_values, double *x2_values, double *y2_values,
82+
int data_count, std::vector<QColor> *color, std::vector<QColor> *border,
83+
std::vector<double> *alpha, std::vector<double> *lwd);
84+
void addSegmentData(double *x1_values, double *y1_values, double *x2_values, double *y2_values,
85+
int data_count, std::vector<QColor> *color,
86+
std::vector<double> *alpha, std::vector<double> *lwd);
7987
void addTextData(double *x_values, double *y_values, std::vector<QString> *labels, int data_count,
8088
std::vector<QColor> *color, std::vector<double> *alpha, std::vector<double> *size, double *adj);
8189

@@ -108,8 +116,10 @@ public slots:
108116
bool has_finite_data_;
109117

110118
std::vector<QtSLiM_CustomPlotType> plot_type_;
111-
std::vector<double *> xdata_;
112-
std::vector<double *> ydata_;
119+
std::vector<double *> x1data_;
120+
std::vector<double *> y1data_;
121+
std::vector<double *> x2data_;
122+
std::vector<double *> y2data_;
113123
std::vector<int> data_count_; // the count for the xdata / ydata buffers
114124
std::vector<std::vector<QString> *> labels_; // one label per point
115125
std::vector<std::vector<int> *> symbol_; // one symbol per point, OR one symbol for all points
@@ -128,6 +138,8 @@ public slots:
128138
void drawHLines(QPainter &painter, QRect interiorRect, int dataIndex);
129139
void drawVLines(QPainter &painter, QRect interiorRect, int dataIndex);
130140
void drawLines(QPainter &painter, QRect interiorRect, int dataIndex);
141+
void drawSegments(QPainter &painter, QRect interiorRect, int dataIndex);
142+
void drawRects(QPainter &painter, QRect interiorRect, int dataIndex);
131143
void drawPoints(QPainter &painter, QRect interiorRect, int dataIndex);
132144
void drawText(QPainter &painter, QRect interiorRect, int dataIndex);
133145
void drawImage(QPainter &painter, QRect interiorRect, int dataIndex);

QtSLiM/QtSLiM_Plot.cpp

Lines changed: 315 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ EidosValue_SP Plot::ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const
113113
case gID_lines: return ExecuteMethod_lines(p_method_id, p_arguments, p_interpreter);
114114
case gID_matrix: return ExecuteMethod_matrix(p_method_id, p_arguments, p_interpreter);
115115
case gID_points: return ExecuteMethod_points(p_method_id, p_arguments, p_interpreter);
116+
case gID_rects: return ExecuteMethod_rects(p_method_id, p_arguments, p_interpreter);
117+
case gID_segments: return ExecuteMethod_segments(p_method_id, p_arguments, p_interpreter);
116118
case gID_setBorderless: return ExecuteMethod_setBorderless(p_method_id, p_arguments, p_interpreter);
117119
case gID_text: return ExecuteMethod_text(p_method_id, p_arguments, p_interpreter);
118120
case gEidosID_write: return ExecuteMethod_write(p_method_id, p_arguments, p_interpreter);
@@ -1210,6 +1212,310 @@ EidosValue_SP Plot::ExecuteMethod_points(EidosGlobalStringID p_method_id, const
12101212
return gStaticEidosValueVOID;
12111213
}
12121214

1215+
// ********************* – (void)rects(numeric x1, numeric y1, numeric x2, numeric y2, [string color = "red"], [string border = "black"], [numeric lwd = 1.0], [float alpha = 1.0])
1216+
//
1217+
EidosValue_SP Plot::ExecuteMethod_rects(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)
1218+
{
1219+
#pragma unused (p_method_id, p_interpreter)
1220+
EidosValue *x1_value = p_arguments[0].get();
1221+
EidosValue *y1_value = p_arguments[1].get();
1222+
EidosValue *x2_value = p_arguments[2].get();
1223+
EidosValue *y2_value = p_arguments[3].get();
1224+
EidosValue *color_value = p_arguments[4].get();
1225+
EidosValue *border_value = p_arguments[5].get();
1226+
EidosValue *lwd_value = p_arguments[6].get();
1227+
EidosValue *alpha_value = p_arguments[7].get();
1228+
1229+
// x1, y1, x2, y2
1230+
int segment_count = x1_value->Count();
1231+
int y1count = y1_value->Count();
1232+
int x2count = x2_value->Count();
1233+
int y2count = y2_value->Count();
1234+
1235+
if ((segment_count != y1count) || (segment_count != x2count) || (segment_count != y2count))
1236+
EIDOS_TERMINATION << "ERROR (Plot::ExecuteMethod_segments): segments() requires x1, y1, x2, and y2 to be the same length." << EidosTerminate();
1237+
1238+
double *x1 = (double *)malloc(segment_count * sizeof(double));
1239+
double *y1 = (double *)malloc(segment_count * sizeof(double));
1240+
double *x2 = (double *)malloc(segment_count * sizeof(double));
1241+
double *y2 = (double *)malloc(segment_count * sizeof(double));
1242+
1243+
if (!x1 || !y1 || !x2 || !y2)
1244+
EIDOS_TERMINATION << "ERROR (Plot::ExecuteMethod_segments): allocation failed; you may need to raise the memory limit for SLiM." << EidosTerminate(nullptr);
1245+
1246+
if (x1_value->Type() == EidosValueType::kValueFloat)
1247+
{
1248+
memcpy(x1, x1_value->FloatData(), segment_count * sizeof(double));
1249+
}
1250+
else
1251+
{
1252+
const int64_t *int_data = x1_value->IntData();
1253+
1254+
for (int index = 0; index < segment_count; ++index)
1255+
x1[index] = int_data[index];
1256+
}
1257+
1258+
if (y1_value->Type() == EidosValueType::kValueFloat)
1259+
{
1260+
memcpy(y1, y1_value->FloatData(), segment_count * sizeof(double));
1261+
}
1262+
else
1263+
{
1264+
const int64_t *int_data = y1_value->IntData();
1265+
1266+
for (int index = 0; index < segment_count; ++index)
1267+
y1[index] = int_data[index];
1268+
}
1269+
1270+
if (x2_value->Type() == EidosValueType::kValueFloat)
1271+
{
1272+
memcpy(x2, x2_value->FloatData(), segment_count * sizeof(double));
1273+
}
1274+
else
1275+
{
1276+
const int64_t *int_data = x2_value->IntData();
1277+
1278+
for (int index = 0; index < segment_count; ++index)
1279+
x2[index] = int_data[index];
1280+
}
1281+
1282+
if (y2_value->Type() == EidosValueType::kValueFloat)
1283+
{
1284+
memcpy(y2, y2_value->FloatData(), segment_count * sizeof(double));
1285+
}
1286+
else
1287+
{
1288+
const int64_t *int_data = y2_value->IntData();
1289+
1290+
for (int index = 0; index < segment_count; ++index)
1291+
y2[index] = int_data[index];
1292+
}
1293+
1294+
// color
1295+
std::vector<QColor> *colors = new std::vector<QColor>;
1296+
int color_count = color_value->Count();
1297+
1298+
if ((color_count != 1) && (color_count != segment_count))
1299+
EIDOS_TERMINATION << "ERROR (Plot::ExecuteMethod_segments): segments() requires color to match the length of x1/y1/x2/y2, or be singleton." << EidosTerminate();
1300+
1301+
for (int index = 0; index < color_count; ++index)
1302+
{
1303+
std::string color_string = color_value->StringAtIndex_NOCAST(index, nullptr);
1304+
1305+
if (color_string == "none")
1306+
{
1307+
// "none" is a special named color provided by rects() to say you don't want a frame or fill
1308+
colors->emplace_back(Qt::transparent);
1309+
}
1310+
else
1311+
{
1312+
uint8_t colorR, colorG, colorB;
1313+
1314+
Eidos_GetColorComponents(color_string, &colorR, &colorG, &colorB);
1315+
1316+
colors->emplace_back(colorR, colorG, colorB, 255);
1317+
}
1318+
}
1319+
1320+
// border
1321+
std::vector<QColor> *borders = new std::vector<QColor>;
1322+
int border_count = border_value->Count();
1323+
1324+
if ((border_count != 1) && (border_count != segment_count))
1325+
EIDOS_TERMINATION << "ERROR (Plot::ExecuteMethod_points): points() requires border to match the length of x and y, or be singleton." << EidosTerminate();
1326+
1327+
for (int index = 0; index < border_count; ++index)
1328+
{
1329+
std::string border_string = border_value->StringAtIndex_NOCAST(index, nullptr);
1330+
1331+
if (border_string == "none")
1332+
{
1333+
// "none" is a special named color provided by rects() to say you don't want a frame or fill
1334+
borders->emplace_back(Qt::transparent);
1335+
}
1336+
else
1337+
{
1338+
uint8_t borderR, borderG, borderB;
1339+
1340+
Eidos_GetColorComponents(border_string, &borderR, &borderG, &borderB);
1341+
1342+
borders->emplace_back(borderR, borderG, borderB, 255);
1343+
}
1344+
}
1345+
1346+
// lwd
1347+
std::vector<double> *lwds = new std::vector<double>;
1348+
int lwd_count = lwd_value->Count();
1349+
1350+
if ((lwd_count != 1) && (lwd_count != segment_count))
1351+
EIDOS_TERMINATION << "ERROR (Plot::ExecuteMethod_segments): segments() requires lwd to match the length of x1/y1/x2/y2, or be singleton." << EidosTerminate();
1352+
1353+
for (int index = 0; index < lwd_count; ++index)
1354+
{
1355+
double lwd = lwd_value->NumericAtIndex_NOCAST(index, nullptr);
1356+
1357+
if ((lwd < 0.0) || (lwd > 100.0))
1358+
EIDOS_TERMINATION << "ERROR (Plot::ExecuteMethod_segments): segments() requires the elements of lwd to be in [0, 100]." << EidosTerminate(nullptr);
1359+
1360+
lwds->push_back(lwd);
1361+
}
1362+
1363+
// alpha
1364+
std::vector<double> *alphas = new std::vector<double>;
1365+
int alpha_count = alpha_value->Count();
1366+
1367+
if ((alpha_count != 1) && (alpha_count != segment_count))
1368+
EIDOS_TERMINATION << "ERROR (Plot::ExecuteMethod_segments): segments() requires alpha to match the length of x1/y1/x2/y2, or be singleton." << EidosTerminate();
1369+
1370+
for (int index = 0; index < alpha_count; ++index)
1371+
{
1372+
double alpha = alpha_value->FloatAtIndex_NOCAST(index, nullptr);
1373+
1374+
if ((alpha < 0.0) || (alpha > 1.0))
1375+
EIDOS_TERMINATION << "ERROR (Plot::ExecuteMethod_segments): segments() requires the elements of alpha to be in [0, 1]." << EidosTerminate(nullptr);
1376+
1377+
alphas->push_back(alpha);
1378+
}
1379+
1380+
plotview_->addRectData(x1, y1, x2, y2, segment_count, colors, borders, alphas, lwds); // takes ownership of buffers
1381+
1382+
return gStaticEidosValueVOID;
1383+
}
1384+
1385+
// ********************* – (void)segments(numeric x1, numeric y1, numeric x2, numeric y2, [string color = "red"], [numeric lwd = 1.0], [float alpha = 1.0])
1386+
//
1387+
EidosValue_SP Plot::ExecuteMethod_segments(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)
1388+
{
1389+
#pragma unused (p_method_id, p_interpreter)
1390+
EidosValue *x1_value = p_arguments[0].get();
1391+
EidosValue *y1_value = p_arguments[1].get();
1392+
EidosValue *x2_value = p_arguments[2].get();
1393+
EidosValue *y2_value = p_arguments[3].get();
1394+
EidosValue *color_value = p_arguments[4].get();
1395+
EidosValue *lwd_value = p_arguments[5].get();
1396+
EidosValue *alpha_value = p_arguments[6].get();
1397+
1398+
// x1, y1, x2, y2
1399+
int segment_count = x1_value->Count();
1400+
int y1count = y1_value->Count();
1401+
int x2count = x2_value->Count();
1402+
int y2count = y2_value->Count();
1403+
1404+
if ((segment_count != y1count) || (segment_count != x2count) || (segment_count != y2count))
1405+
EIDOS_TERMINATION << "ERROR (Plot::ExecuteMethod_segments): segments() requires x1, y1, x2, and y2 to be the same length." << EidosTerminate();
1406+
1407+
double *x1 = (double *)malloc(segment_count * sizeof(double));
1408+
double *y1 = (double *)malloc(segment_count * sizeof(double));
1409+
double *x2 = (double *)malloc(segment_count * sizeof(double));
1410+
double *y2 = (double *)malloc(segment_count * sizeof(double));
1411+
1412+
if (!x1 || !y1 || !x2 || !y2)
1413+
EIDOS_TERMINATION << "ERROR (Plot::ExecuteMethod_segments): allocation failed; you may need to raise the memory limit for SLiM." << EidosTerminate(nullptr);
1414+
1415+
if (x1_value->Type() == EidosValueType::kValueFloat)
1416+
{
1417+
memcpy(x1, x1_value->FloatData(), segment_count * sizeof(double));
1418+
}
1419+
else
1420+
{
1421+
const int64_t *int_data = x1_value->IntData();
1422+
1423+
for (int index = 0; index < segment_count; ++index)
1424+
x1[index] = int_data[index];
1425+
}
1426+
1427+
if (y1_value->Type() == EidosValueType::kValueFloat)
1428+
{
1429+
memcpy(y1, y1_value->FloatData(), segment_count * sizeof(double));
1430+
}
1431+
else
1432+
{
1433+
const int64_t *int_data = y1_value->IntData();
1434+
1435+
for (int index = 0; index < segment_count; ++index)
1436+
y1[index] = int_data[index];
1437+
}
1438+
1439+
if (x2_value->Type() == EidosValueType::kValueFloat)
1440+
{
1441+
memcpy(x2, x2_value->FloatData(), segment_count * sizeof(double));
1442+
}
1443+
else
1444+
{
1445+
const int64_t *int_data = x2_value->IntData();
1446+
1447+
for (int index = 0; index < segment_count; ++index)
1448+
x2[index] = int_data[index];
1449+
}
1450+
1451+
if (y2_value->Type() == EidosValueType::kValueFloat)
1452+
{
1453+
memcpy(y2, y2_value->FloatData(), segment_count * sizeof(double));
1454+
}
1455+
else
1456+
{
1457+
const int64_t *int_data = y2_value->IntData();
1458+
1459+
for (int index = 0; index < segment_count; ++index)
1460+
y2[index] = int_data[index];
1461+
}
1462+
1463+
// color
1464+
std::vector<QColor> *colors = new std::vector<QColor>;
1465+
int color_count = color_value->Count();
1466+
1467+
if ((color_count != 1) && (color_count != segment_count))
1468+
EIDOS_TERMINATION << "ERROR (Plot::ExecuteMethod_segments): segments() requires color to match the length of x1/y1/x2/y2, or be singleton." << EidosTerminate();
1469+
1470+
for (int index = 0; index < color_count; ++index)
1471+
{
1472+
std::string color_string = color_value->StringAtIndex_NOCAST(index, nullptr);
1473+
uint8_t colorR, colorG, colorB;
1474+
1475+
Eidos_GetColorComponents(color_string, &colorR, &colorG, &colorB);
1476+
1477+
colors->emplace_back(colorR, colorG, colorB, 255);
1478+
}
1479+
1480+
// lwd
1481+
std::vector<double> *lwds = new std::vector<double>;
1482+
int lwd_count = lwd_value->Count();
1483+
1484+
if ((lwd_count != 1) && (lwd_count != segment_count))
1485+
EIDOS_TERMINATION << "ERROR (Plot::ExecuteMethod_segments): segments() requires lwd to match the length of x1/y1/x2/y2, or be singleton." << EidosTerminate();
1486+
1487+
for (int index = 0; index < lwd_count; ++index)
1488+
{
1489+
double lwd = lwd_value->NumericAtIndex_NOCAST(index, nullptr);
1490+
1491+
if ((lwd < 0.0) || (lwd > 100.0))
1492+
EIDOS_TERMINATION << "ERROR (Plot::ExecuteMethod_segments): segments() requires the elements of lwd to be in [0, 100]." << EidosTerminate(nullptr);
1493+
1494+
lwds->push_back(lwd);
1495+
}
1496+
1497+
// alpha
1498+
std::vector<double> *alphas = new std::vector<double>;
1499+
int alpha_count = alpha_value->Count();
1500+
1501+
if ((alpha_count != 1) && (alpha_count != segment_count))
1502+
EIDOS_TERMINATION << "ERROR (Plot::ExecuteMethod_segments): segments() requires alpha to match the length of x1/y1/x2/y2, or be singleton." << EidosTerminate();
1503+
1504+
for (int index = 0; index < alpha_count; ++index)
1505+
{
1506+
double alpha = alpha_value->FloatAtIndex_NOCAST(index, nullptr);
1507+
1508+
if ((alpha < 0.0) || (alpha > 1.0))
1509+
EIDOS_TERMINATION << "ERROR (Plot::ExecuteMethod_segments): segments() requires the elements of alpha to be in [0, 1]." << EidosTerminate(nullptr);
1510+
1511+
alphas->push_back(alpha);
1512+
}
1513+
1514+
plotview_->addSegmentData(x1, y1, x2, y2, segment_count, colors, alphas, lwds); // takes ownership of buffers
1515+
1516+
return gStaticEidosValueVOID;
1517+
}
1518+
12131519
// ********************* – (void)setBorderless([numeric marginLeft = 0.0], [numeric marginTop = 0.0], [numeric marginRight = 0.0], [numeric marginBottom = 0.0])
12141520
//
12151521
EidosValue_SP Plot::ExecuteMethod_setBorderless(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)
@@ -1455,6 +1761,15 @@ const std::vector<EidosMethodSignature_CSP> *Plot_Class::Methods(void) const
14551761
->AddString_O("color", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String("red")))
14561762
->AddString_O("border", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String("black")))
14571763
->AddNumeric_O("lwd", gStaticEidosValue_Float1)->AddNumeric_O("size", gStaticEidosValue_Float1)->AddFloat_O("alpha", gStaticEidosValue_Float1)));
1764+
methods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_rects, kEidosValueMaskVOID))
1765+
->AddNumeric("x1")->AddNumeric("y1")->AddNumeric("x2")->AddNumeric("y2")
1766+
->AddString_O("color", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String("red")))
1767+
->AddString_O("border", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String("black")))
1768+
->AddNumeric_O("lwd", gStaticEidosValue_Float1)->AddFloat_O("alpha", gStaticEidosValue_Float1));
1769+
methods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_segments, kEidosValueMaskVOID))
1770+
->AddNumeric("x1")->AddNumeric("y1")->AddNumeric("x2")->AddNumeric("y2")
1771+
->AddString_O("color", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String("red")))
1772+
->AddNumeric_O("lwd", gStaticEidosValue_Float1)->AddFloat_O("alpha", gStaticEidosValue_Float1));
14581773
methods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_setBorderless, kEidosValueMaskVOID))
14591774
->AddNumeric_OS("marginLeft", gStaticEidosValue_Float0)->AddNumeric_OS("marginTop", gStaticEidosValue_Float0)
14601775
->AddNumeric_OS("marginRight", gStaticEidosValue_Float0)->AddNumeric_OS("marginBottom", gStaticEidosValue_Float0));

QtSLiM/QtSLiM_Plot.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ class Plot : public EidosDictionaryUnretained
7373
EidosValue_SP ExecuteMethod_lines(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);
7474
EidosValue_SP ExecuteMethod_matrix(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);
7575
EidosValue_SP ExecuteMethod_points(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);
76+
EidosValue_SP ExecuteMethod_rects(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);
77+
EidosValue_SP ExecuteMethod_segments(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);
7678
EidosValue_SP ExecuteMethod_setBorderless(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);
7779
EidosValue_SP ExecuteMethod_text(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);
7880
EidosValue_SP ExecuteMethod_write(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);

0 commit comments

Comments
 (0)