Skip to content

Commit 73b4970

Browse files
committed
add image() and matrix() methods to Plot
1 parent d5fb483 commit 73b4970

20 files changed

Lines changed: 908 additions & 85 deletions

QtSLiM/QtSLiMGraphView_CustomPlot.cpp

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,12 @@ void QtSLiMGraphView_CustomPlot::freeData(void)
7070
for (std::vector<QColor> *colorbuffer : color_)
7171
delete colorbuffer;
7272

73-
for (std::vector<double> *alphabuffer : alpha_)
74-
delete alphabuffer;
75-
7673
for (std::vector<QColor> *borderbuffer : border_)
7774
delete borderbuffer;
7875

76+
for (std::vector<double> *alphabuffer : alpha_)
77+
delete alphabuffer;
78+
7979
for (std::vector<double> *lwdbuffer : line_width_)
8080
delete lwdbuffer;
8181

@@ -89,12 +89,13 @@ void QtSLiMGraphView_CustomPlot::freeData(void)
8989
labels_.clear();
9090
symbol_.clear();
9191
color_.clear();
92-
alpha_.clear();
9392
border_.clear();
93+
alpha_.clear();
9494
line_width_.clear();
9595
size_.clear();
9696
xadj_.clear();
9797
yadj_.clear();
98+
image_.clear();
9899

99100
// reset the legend state
100101
legend_added_ = false;
@@ -385,6 +386,7 @@ void QtSLiMGraphView_CustomPlot::addABLineData(double *a_values, double *b_value
385386
size_.push_back(nullptr); // unused for abline
386387
xadj_.push_back(-1); // unused for abline
387388
yadj_.push_back(-1); // unused for abline
389+
image_.push_back(QImage()); // unused for abline
388390

389391
//rescaleAxesForDataRange(); // not needed for abline
390392
update();
@@ -407,6 +409,7 @@ void QtSLiMGraphView_CustomPlot::addLineData(double *x_values, double *y_values,
407409
size_.push_back(nullptr); // unused for lines
408410
xadj_.push_back(-1); // unused for lines
409411
yadj_.push_back(-1); // unused for lines
412+
image_.push_back(QImage()); // unused for lines
410413

411414
rescaleAxesForDataRange();
412415
update();
@@ -429,6 +432,7 @@ void QtSLiMGraphView_CustomPlot::addPointData(double *x_values, double *y_values
429432
size_.push_back(size);
430433
xadj_.push_back(-1); // unused for points
431434
yadj_.push_back(-1); // unused for points
435+
image_.push_back(QImage()); // unused for points
432436

433437
rescaleAxesForDataRange();
434438
update();
@@ -451,6 +455,29 @@ void QtSLiMGraphView_CustomPlot::addTextData(double *x_values, double *y_values,
451455
size_.push_back(size);
452456
xadj_.push_back(adj[0]);
453457
yadj_.push_back(adj[1]);
458+
image_.push_back(QImage()); // unused for text
459+
460+
rescaleAxesForDataRange();
461+
update();
462+
}
463+
464+
void QtSLiMGraphView_CustomPlot::addImageData(double *x_values, double *y_values, int data_count,
465+
QImage image, std::vector<double> *alpha)
466+
{
467+
plot_type_.push_back(QtSLiM_CustomPlotType::kImage);
468+
xdata_.push_back(x_values);
469+
ydata_.push_back(y_values);
470+
labels_.push_back(nullptr); // unused for image
471+
data_count_.push_back(data_count);
472+
symbol_.push_back(nullptr); // unused for image
473+
color_.push_back(nullptr); // unused for image
474+
border_.push_back(nullptr); // unused for image
475+
alpha_.push_back(alpha);
476+
line_width_.push_back(nullptr); // unused for image
477+
size_.push_back(nullptr); // unused for image
478+
xadj_.push_back(-1); // unused for image
479+
yadj_.push_back(-1); // unused for image
480+
image_.push_back(image);
454481

455482
rescaleAxesForDataRange();
456483
update();
@@ -532,6 +559,9 @@ void QtSLiMGraphView_CustomPlot::drawGraph(QPainter &painter, QRect interiorRect
532559
case QtSLiM_CustomPlotType::kVLines:
533560
drawVLines(painter, interiorRect, i);
534561
break;
562+
case QtSLiM_CustomPlotType::kImage:
563+
drawImage(painter, interiorRect, i);
564+
break;
535565
}
536566
}
537567
}
@@ -850,6 +880,39 @@ void QtSLiMGraphView_CustomPlot::drawText(QPainter &painter, QRect interiorRect,
850880
}
851881
}
852882

883+
void QtSLiMGraphView_CustomPlot::drawImage(QPainter &painter, QRect interiorRect, int dataIndex)
884+
{
885+
double *xdata = xdata_[dataIndex];
886+
double *ydata = ydata_[dataIndex];
887+
std::vector<double> &imageAlphas = *alpha_[dataIndex];
888+
double alpha = imageAlphas[0];
889+
890+
double user_x1 = xdata[0], user_y1 = ydata[0];
891+
double user_x2 = xdata[1], user_y2 = ydata[1];
892+
893+
double x1 = plotToDeviceX(user_x1, interiorRect);
894+
double y1 = plotToDeviceY(user_y1, interiorRect);
895+
double x2 = plotToDeviceX(user_x2, interiorRect);
896+
double y2 = plotToDeviceY(user_y2, interiorRect);
897+
898+
// the coordinates are absolute, but Qt wants them as width/height
899+
double target_width = x2 - x1;
900+
double target_height = y2 - y1;
901+
902+
// get the image data
903+
const QImage &image = image_[dataIndex];
904+
905+
QRectF target(x1, y1, target_width, target_height);
906+
907+
if (alpha != 1.0)
908+
painter.setOpacity(alpha);
909+
910+
painter.drawImage(target, image);
911+
912+
if (alpha != 1.0)
913+
painter.setOpacity(1.0);
914+
}
915+
853916

854917

855918

QtSLiM/QtSLiMGraphView_CustomPlot.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ enum class QtSLiM_CustomPlotType : int {
3636
kABLines, // from abline()
3737
kHLines, // from abline()
3838
kVLines, // from abline()
39+
kImage,
3940
};
4041

4142
class QtSLiMGraphView_CustomPlot : public QtSLiMGraphView
@@ -67,6 +68,8 @@ class QtSLiMGraphView_CustomPlot : public QtSLiMGraphView
6768
double *h_values, double *v_values, int data_count,
6869
std::vector<QColor> *color, std::vector<double> *alpha,
6970
std::vector<double> *lwd);
71+
void addImageData(double *x_values, double *y_values, int data_count,
72+
QImage image, std::vector<double> *alpha);
7073
void addLineData(double *x_values, double *y_values, int data_count,
7174
std::vector<QColor> *color, std::vector<double> *alpha,
7275
std::vector<double> *lwd);
@@ -117,6 +120,7 @@ public slots:
117120
std::vector<std::vector<double> *> size_; // one size per point, OR one size for all points
118121
std::vector<double> xadj_; // one xadj for all points
119122
std::vector<double> yadj_; // one yadj for all points
123+
std::vector<QImage> image_; // one QImage per image data; QImage() if unused
120124

121125
void dataRange(std::vector<double *> &data, double *p_min, double *p_max);
122126
void rescaleAxesForDataRange(void);
@@ -126,6 +130,7 @@ public slots:
126130
void drawLines(QPainter &painter, QRect interiorRect, int dataIndex);
127131
void drawPoints(QPainter &painter, QRect interiorRect, int dataIndex);
128132
void drawText(QPainter &painter, QRect interiorRect, int dataIndex);
133+
void drawImage(QPainter &painter, QRect interiorRect, int dataIndex);
129134

130135
bool legend_added_ = false; // set to true by addLegend()
131136
QtSLiMLegendSpec legend_entries_; // unlike most graph types, we keep our legend around

QtSLiM/QtSLiMIndividualsWidget.cpp

Lines changed: 3 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -635,7 +635,7 @@ void QtSLiMIndividualsWidget::cacheDisplayBufferForMapForSubpopulation(SpatialMa
635635
// The sizing logic here is taken from drawRect:, assuming that we are not constrained in width.
636636

637637
// By the way, it may occur to the reader to wonder why we keep the buffer as uint8_t values, given that we
638-
// convert to and from uin8_t for the display code that uses float RGB components. My rationale is that
638+
// convert to and from uint_8 for the display code that uses float RGB components. My rationale is that
639639
// this drastically cuts the amount of memory that has to be accessed, and that the display code, in particular,
640640
// is probably memory-bound since most of the work is done in the GPU. I haven't done any speed tests to
641641
// confirm that hunch, though. In any case, it's plenty fast and I don't see significant display artifacts.
@@ -666,61 +666,8 @@ void QtSLiMIndividualsWidget::cacheDisplayBufferForMapForSubpopulation(SpatialMa
666666
background_map->buffer_width_ = max_width;
667667
background_map->buffer_height_ = max_height;
668668
background_map->buffer_flipped_ = flipped;
669-
670-
uint8_t *buf_ptr = display_buf;
671-
int64_t xsize = background_map->grid_size_[0];
672-
int64_t ysize = background_map->grid_size_[1];
673-
double *values = background_map->values_;
674-
bool interpolate = background_map->interpolate_;
675-
676-
for (int yc = 0; yc < max_height; yc++)
677-
{
678-
double y_fraction = (flipped ? (((max_height - 1) - yc) + 0.5) / max_height : (yc + 0.5) / max_height); // pixel center
679-
680-
for (int xc = 0; xc < max_width; xc++)
681-
{
682-
// Look up the nearest map point and get its value; interpolate if requested
683-
double x_fraction = (xc + 0.5) / max_width; // pixel center
684-
double value;
685-
686-
if (interpolate)
687-
{
688-
double x_map = x_fraction * (xsize - 1);
689-
double y_map = y_fraction * (ysize - 1);
690-
int x1_map = static_cast<int>(floor(x_map));
691-
int y1_map = static_cast<int>(floor(y_map));
692-
int x2_map = static_cast<int>(ceil(x_map));
693-
int y2_map = static_cast<int>(ceil(y_map));
694-
double fraction_x2 = x_map - x1_map;
695-
double fraction_x1 = 1.0 - fraction_x2;
696-
double fraction_y2 = y_map - y1_map;
697-
double fraction_y1 = 1.0 - fraction_y2;
698-
double value_x1_y1 = values[x1_map + y1_map * xsize] * fraction_x1 * fraction_y1;
699-
double value_x2_y1 = values[x2_map + y1_map * xsize] * fraction_x2 * fraction_y1;
700-
double value_x1_y2 = values[x1_map + y2_map * xsize] * fraction_x1 * fraction_y2;
701-
double value_x2_y2 = values[x2_map + y2_map * xsize] * fraction_x2 * fraction_y2;
702-
703-
value = value_x1_y1 + value_x2_y1 + value_x1_y2 + value_x2_y2;
704-
}
705-
else
706-
{
707-
int x_map = qRound(x_fraction * (xsize - 1));
708-
int y_map = qRound(y_fraction * (ysize - 1));
709-
710-
value = values[x_map + y_map * xsize];
711-
}
712-
713-
// Given the (interpolated?) value, look up the color, interpolating if necessary
714-
double rgb[3];
715-
716-
background_map->ColorForValue(value, rgb);
717-
718-
// Write the color values to the buffer
719-
*(buf_ptr++) = static_cast<uint8_t>(round(rgb[0] * 255.0));
720-
*(buf_ptr++) = static_cast<uint8_t>(round(rgb[1] * 255.0));
721-
*(buf_ptr++) = static_cast<uint8_t>(round(rgb[2] * 255.0));
722-
}
723-
}
669+
670+
background_map->FillRGBBuffer(display_buf, max_width, max_height, flipped, /* no_interpolation */ false);
724671
}
725672
}
726673

0 commit comments

Comments
 (0)