Skip to content

Commit 325c6f8

Browse files
committed
multichrom improvements to the chromosome view
1 parent f8ef49f commit 325c6f8

8 files changed

+294
-211
lines changed

QtSLiM/QtSLiMChromosomeWidget.cpp

Lines changed: 230 additions & 92 deletions
Large diffs are not rendered by default.

QtSLiM/QtSLiMChromosomeWidget.h

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -140,18 +140,14 @@ class QtSLiMChromosomeWidget : public QWidget
140140
QRect contentRectForTrackedChromosome_;
141141
slim_position_t trackingStartBase_ = 0, trackingLastBase_ = 0;
142142
int trackingXAdjust_ = 0; // to keep the cursor stuck on a knob that is click-dragged
143+
bool trackingStartedInFocalChromosome_ = false; // used to keep track of whether we could deselect on mouse-up
143144
//SLiMSelectionMarker *startMarker, *endMarker;
144145

145-
// Haplotype display
146-
int64_t *haplotype_previous_bincounts = nullptr; // used by QtSLiMHaplotypeManager to keep the sort order stable
147-
QtSLiMHaplotypeManager *haplotype_mgr_ = nullptr; // the haplotype manager constructed for the current display; cached
148-
149146
public:
150147
explicit QtSLiMChromosomeWidget(QWidget *p_parent = nullptr, QtSLiMChromosomeWidgetController *controller = nullptr, Species *displaySpecies = nullptr, Qt::WindowFlags f = Qt::WindowFlags());
151148
virtual ~QtSLiMChromosomeWidget() override;
152149

153150
void setController(QtSLiMChromosomeWidgetController *controller);
154-
Chromosome *resetToDefaultChromosome(void);
155151
void setFocalDisplaySpecies(Species *displaySpecies);
156152
Species *focalDisplaySpecies(void);
157153
void setFocalChromosome(Chromosome *chromosome);
@@ -186,16 +182,17 @@ class QtSLiMChromosomeWidget : public QWidget
186182
QRect rectEncompassingBaseToBase(slim_position_t startBase, slim_position_t endBase, QRect interiorRect, QtSLiMRange displayedRange);
187183
slim_position_t baseForPosition(double position, QRect interiorRect, QtSLiMRange displayedRange);
188184
QRect getContentRect(void);
189-
QRect getInteriorRect(void);
190185

191186
void drawOverview(Species *displaySpecies, QPainter &painter);
187+
void drawFullGenome(Species *displaySpecies, QPainter &painter);
188+
192189
void drawTicksInContentRect(QRect contentRect, Species *displaySpecies, QtSLiMRange displayedRange, QPainter &painter);
193190
void overlaySelection(QRect interiorRect, QtSLiMRange displayedRange, QPainter &painter);
194191
void updateDisplayedMutationTypes(Species *displaySpecies);
195192

196193
// OpenGL drawing; this is the primary drawing code
197194
#ifndef SLIM_NO_OPENGL
198-
void glDrawRect(Species *displaySpecies);
195+
void glDrawRect(QRect contentRect, Species *displaySpecies, Chromosome *chromosome);
199196
void glDrawGenomicElements(QRect &interiorRect, Chromosome *chromosome, QtSLiMRange displayedRange);
200197
void glDrawFixedSubstitutions(QRect &interiorRect, Chromosome *chromosome, QtSLiMRange displayedRange);
201198
void glDrawMutations(QRect &interiorRect, Chromosome *chromosome, QtSLiMRange displayedRange);
@@ -206,7 +203,7 @@ class QtSLiMChromosomeWidget : public QWidget
206203
#endif
207204

208205
// Qt-based drawing, provided as a backup if OpenGL has problems on a given platform
209-
void qtDrawRect(Species *displaySpecies, QPainter &painter);
206+
void qtDrawRect(QRect contentRect, Species *displaySpecies, Chromosome *chromosome, QPainter &painter);
210207
void qtDrawGenomicElements(QRect &interiorRect, Chromosome *chromosome, QtSLiMRange displayedRange, QPainter &painter);
211208
void qtDrawFixedSubstitutions(QRect &interiorRect, Chromosome *chromosome, QtSLiMRange displayedRange, QPainter &painter);
212209
void qtDrawMutations(QRect &interiorRect, Chromosome *chromosome, QtSLiMRange displayedRange, QPainter &painter);

QtSLiM/QtSLiMChromosomeWidget_GL.cpp

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@
3535
// OpenGL-based drawing; maintain this in parallel with the Qt-based drawing!
3636
//
3737

38-
void QtSLiMChromosomeWidget::glDrawRect(Species *displaySpecies)
38+
void QtSLiMChromosomeWidget::glDrawRect(QRect contentRect, Species *displaySpecies, Chromosome *chromosome)
3939
{
4040
bool ready = isEnabled() && !controller_->invalidSimulation();
41-
QRect interiorRect = getInteriorRect();
41+
QRect interiorRect = contentRect.marginsRemoved(QMargins(1, 1, 1, 1));
4242

4343
// if the simulation is at tick 0, it is not ready
4444
if (ready)
@@ -51,7 +51,6 @@ void QtSLiMChromosomeWidget::glDrawRect(Species *displaySpecies)
5151
glColor3f(0.0f, 0.0f, 0.0f);
5252
glRecti(interiorRect.left(), interiorRect.top(), interiorRect.left() + interiorRect.width(), interiorRect.top() + interiorRect.height());
5353

54-
Chromosome *chromosome = focalChromosome();
5554
QtSLiMRange displayedRange = getDisplayedRange(chromosome);
5655

5756
bool splitHeight = (shouldDrawRateMaps() && shouldDrawGenomicElements());
@@ -86,16 +85,13 @@ void QtSLiMChromosomeWidget::glDrawRect(Species *displaySpecies)
8685
{
8786
// display mutations as a haplotype plot, courtesy of QtSLiMHaplotypeManager; we use ClusterNearestNeighbor and
8887
// ClusterNoOptimization because they're fast, and NN might also provide a bit more run-to-run continuity
89-
// we cache the haplotype manager here, so our display remains constant across window resizes and other
90-
// invalidations; we toss the cache only when the simulation tells us that the model state has changed
91-
if (!haplotype_mgr_)
92-
{
93-
size_t interiorHeight = static_cast<size_t>(interiorRect.height()); // one sample per available pixel line, for simplicity and speed; 47, in the current UI layout
94-
haplotype_mgr_ = new QtSLiMHaplotypeManager(nullptr, QtSLiMHaplotypeManager::ClusterNearestNeighbor, QtSLiMHaplotypeManager::ClusterNoOptimization, controller_, displaySpecies, displayedRange, interiorHeight, false);
95-
}
88+
size_t interiorHeight = static_cast<size_t>(interiorRect.height()); // one sample per available pixel line, for simplicity and speed; 47, in the current UI layout
89+
QtSLiMHaplotypeManager *haplotype_mgr = new QtSLiMHaplotypeManager(nullptr, QtSLiMHaplotypeManager::ClusterNearestNeighbor, QtSLiMHaplotypeManager::ClusterNoOptimization, controller_, displaySpecies, chromosome, displayedRange, interiorHeight, false);
9690

97-
if (haplotype_mgr_)
98-
haplotype_mgr_->glDrawHaplotypes(interiorRect, false, false, false, &haplotype_previous_bincounts);
91+
if (haplotype_mgr)
92+
haplotype_mgr->glDrawHaplotypes(interiorRect, false, false, false);
93+
94+
delete haplotype_mgr;
9995
}
10096
else
10197
{

QtSLiM/QtSLiMChromosomeWidget_QT.cpp

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,10 @@
3333
// OpenGL-based drawing; maintain this in parallel with the Qt-based drawing!
3434
//
3535

36-
void QtSLiMChromosomeWidget::qtDrawRect(Species *displaySpecies, QPainter &painter)
36+
void QtSLiMChromosomeWidget::qtDrawRect(QRect contentRect, Species *displaySpecies, Chromosome *chromosome, QPainter &painter)
3737
{
3838
bool ready = isEnabled() && !controller_->invalidSimulation();
39-
QRect interiorRect = getInteriorRect();
39+
QRect interiorRect = contentRect.marginsRemoved(QMargins(1, 1, 1, 1));
4040

4141
// if the simulation is at tick 0, it is not ready
4242
if (ready)
@@ -48,7 +48,6 @@ void QtSLiMChromosomeWidget::qtDrawRect(Species *displaySpecies, QPainter &paint
4848
// erase the content area itself
4949
painter.fillRect(interiorRect, Qt::black);
5050

51-
Chromosome *chromosome = focalChromosome();
5251
QtSLiMRange displayedRange = getDisplayedRange(chromosome);
5352

5453
bool splitHeight = (shouldDrawRateMaps() && shouldDrawGenomicElements());
@@ -83,16 +82,13 @@ void QtSLiMChromosomeWidget::qtDrawRect(Species *displaySpecies, QPainter &paint
8382
{
8483
// display mutations as a haplotype plot, courtesy of QtSLiMHaplotypeManager; we use ClusterNearestNeighbor and
8584
// ClusterNoOptimization because they're fast, and NN might also provide a bit more run-to-run continuity
86-
// we cache the haplotype manager here, so our display remains constant across window resizes and other
87-
// invalidations; we toss the cache only when the simulation tells us that the model state has changed
88-
if (!haplotype_mgr_)
89-
{
90-
size_t interiorHeight = static_cast<size_t>(interiorRect.height()); // one sample per available pixel line, for simplicity and speed; 47, in the current UI layout
91-
haplotype_mgr_ = new QtSLiMHaplotypeManager(nullptr, QtSLiMHaplotypeManager::ClusterNearestNeighbor, QtSLiMHaplotypeManager::ClusterNoOptimization, controller_, displaySpecies, displayedRange, interiorHeight, false);
92-
}
85+
size_t interiorHeight = static_cast<size_t>(interiorRect.height()); // one sample per available pixel line, for simplicity and speed; 47, in the current UI layout
86+
QtSLiMHaplotypeManager *haplotype_mgr = new QtSLiMHaplotypeManager(nullptr, QtSLiMHaplotypeManager::ClusterNearestNeighbor, QtSLiMHaplotypeManager::ClusterNoOptimization, controller_, displaySpecies, chromosome, displayedRange, interiorHeight, false);
9387

94-
if (haplotype_mgr_)
95-
haplotype_mgr_->qtDrawHaplotypes(interiorRect, false, false, false, &haplotype_previous_bincounts, painter);
88+
if (haplotype_mgr)
89+
haplotype_mgr->qtDrawHaplotypes(interiorRect, false, false, false, painter);
90+
91+
delete haplotype_mgr;
9692
}
9793
else
9894
{

QtSLiM/QtSLiMHaplotypeManager.cpp

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,10 @@ void QtSLiMHaplotypeManager::CreateHaplotypePlot(QtSLiMChromosomeWidgetControlle
6464

6565
// First generate the haplotype plot data, with a progress panel
6666
// FIXME MULTICHROM this code path should work with all of the chromosomes, probably...
67-
QtSLiMHaplotypeManager *haplotypeManager = new QtSLiMHaplotypeManager(nullptr, clusteringMethod, clusteringOptimization,
68-
controller, displaySpecies, QtSLiMRange(0,0), haplosomeSampleSize, true);
67+
Chromosome *chromosome = &displaySpecies->TheChromosome();
68+
69+
QtSLiMHaplotypeManager *haplotypeManager = new QtSLiMHaplotypeManager(nullptr, clusteringMethod, clusteringOptimization, controller,
70+
displaySpecies, chromosome, QtSLiMRange(0,0), haplosomeSampleSize, true);
6971

7072
if (haplotypeManager->valid_)
7173
{
@@ -151,8 +153,8 @@ void QtSLiMHaplotypeManager::CreateHaplotypePlot(QtSLiMChromosomeWidgetControlle
151153
}
152154

153155
QtSLiMHaplotypeManager::QtSLiMHaplotypeManager(QObject *p_parent, ClusteringMethod clusteringMethod, ClusteringOptimization optimizationMethod,
154-
QtSLiMChromosomeWidgetController *controller, Species *displaySpecies, QtSLiMRange displayedRange,
155-
size_t sampleSize, bool showProgress) :
156+
QtSLiMChromosomeWidgetController *controller, Species *displaySpecies, Chromosome *chromosome,
157+
QtSLiMRange displayedRange, size_t sampleSize, bool showProgress) :
156158
QObject(p_parent)
157159
{
158160
controller_ = controller;
@@ -216,15 +218,17 @@ QtSLiMHaplotypeManager::QtSLiMHaplotypeManager(QObject *p_parent, ClusteringMeth
216218
subpopCount = static_cast<int>(selected_subpops.size());
217219

218220
// Fetch haplosomes and figure out what we're going to plot; note that we plot only non-null haplosomes
219-
int haplosome_count_per_individual = graphSpecies->HaplosomeCountPerIndividual();
221+
slim_chromosome_index_t chromosome_index = chromosome->Index();
222+
int first_haplosome_index = graphSpecies->FirstHaplosomeIndices()[chromosome_index];
223+
int last_haplosome_index = graphSpecies->LastHaplosomeIndices()[chromosome_index];
220224

221225
for (Subpopulation *subpop : selected_subpops)
222226
{
223227
for (Individual *ind : subpop->parent_individuals_)
224228
{
225229
Haplosome **ind_haplosomes = ind->haplosomes_;
226230

227-
for (int haplosome_index = 0; haplosome_index < haplosome_count_per_individual; haplosome_index++)
231+
for (int haplosome_index = first_haplosome_index; haplosome_index <= last_haplosome_index; haplosome_index++)
228232
{
229233
Haplosome *haplosome = ind_haplosomes[haplosome_index];
230234

@@ -242,7 +246,7 @@ QtSLiMHaplotypeManager::QtSLiMHaplotypeManager(QObject *p_parent, ClusteringMeth
242246
}
243247

244248
// Cache all the information about the mutations that we're going to need
245-
configureMutationInfoBuffer();
249+
configureMutationInfoBuffer(chromosome);
246250

247251
// Keep track of the range of subpop IDs we reference, even if not represented by any haplosomes here
248252
maxSubpopID = 0;
@@ -332,7 +336,7 @@ void QtSLiMHaplotypeManager::finishClusteringAnalysis(void)
332336
haplosomes.resize(0);
333337
}
334338

335-
void QtSLiMHaplotypeManager::configureMutationInfoBuffer()
339+
void QtSLiMHaplotypeManager::configureMutationInfoBuffer(Chromosome *chromosome)
336340
{
337341
Species *graphSpecies = focalDisplaySpecies();
338342

@@ -347,6 +351,10 @@ void QtSLiMHaplotypeManager::configureMutationInfoBuffer()
347351
MutationIndex biggest_index = 0;
348352

349353
// First, find the biggest index presently in use; that's how many entries we need
354+
// BCH 12/25/2024: With multiple chromosomes, this is rather wasteful; I think this class
355+
// could be redesigned to capture just the subset of mutations that are live for a given
356+
// chromosome, essentially re-indexing the mutations, but it's not clear this matters
357+
// to performance; we just waste a bit of memory here, but it's not a big deal.
350358
for (const MutationIndex *reg_ptr = registry; reg_ptr != reg_end_ptr; ++reg_ptr)
351359
{
352360
MutationIndex mut_index = *reg_ptr;
@@ -391,7 +399,7 @@ void QtSLiMHaplotypeManager::configureMutationInfoBuffer()
391399
}
392400

393401
// Remember the chromosome length
394-
mutationLastPosition = graphSpecies->TheChromosome().last_position_;
402+
mutationLastPosition = chromosome->last_position_;
395403
}
396404

397405
void QtSLiMHaplotypeManager::sortHaplosomes(void)
@@ -583,7 +591,7 @@ int64_t QtSLiMHaplotypeManager::distanceForBincounts(int64_t *bincounts1, int64_
583591
}
584592

585593
#ifndef SLIM_NO_OPENGL
586-
void QtSLiMHaplotypeManager::glDrawHaplotypes(QRect interior, bool displayBW, bool showSubpopStrips, bool eraseBackground, int64_t **previousFirstBincounts)
594+
void QtSLiMHaplotypeManager::glDrawHaplotypes(QRect interior, bool displayBW, bool showSubpopStrips, bool eraseBackground)
587595
{
588596
// Erase the background to either black or white, depending on displayBW
589597
if (eraseBackground)
@@ -608,11 +616,11 @@ void QtSLiMHaplotypeManager::glDrawHaplotypes(QRect interior, bool displayBW, bo
608616
}
609617

610618
// Draw the haplotypes in the remaining portion of the interior
611-
glDrawDisplayListInRect(interior, displayBW, previousFirstBincounts);
619+
glDrawDisplayListInRect(interior, displayBW);
612620
}
613621
#endif
614622

615-
void QtSLiMHaplotypeManager::qtDrawHaplotypes(QRect interior, bool displayBW, bool showSubpopStrips, bool eraseBackground, int64_t **previousFirstBincounts, QPainter &painter)
623+
void QtSLiMHaplotypeManager::qtDrawHaplotypes(QRect interior, bool displayBW, bool showSubpopStrips, bool eraseBackground, QPainter &painter)
616624
{
617625
// Erase the background to either black or white, depending on displayBW
618626
if (eraseBackground)
@@ -633,7 +641,7 @@ void QtSLiMHaplotypeManager::qtDrawHaplotypes(QRect interior, bool displayBW, bo
633641
}
634642

635643
// Draw the haplotypes in the remaining portion of the interior
636-
qtDrawDisplayListInRect(interior, displayBW, previousFirstBincounts, painter);
644+
qtDrawDisplayListInRect(interior, displayBW, painter);
637645
}
638646

639647
// Traveling Salesman Problem code
@@ -1561,13 +1569,13 @@ void QtSLiMHaplotypeView::paintEvent(QPaintEvent * /* p_paint_event */)
15611569
if (QtSLiMPreferencesNotifier::instance().useOpenGLPref())
15621570
{
15631571
painter.beginNativePainting();
1564-
delegate_->glDrawHaplotypes(interior, displayBlackAndWhite_, showSubpopulationStrips_, true, nullptr);
1572+
delegate_->glDrawHaplotypes(interior, displayBlackAndWhite_, showSubpopulationStrips_, true);
15651573
painter.endNativePainting();
15661574
}
15671575
else
15681576
#endif
15691577
{
1570-
delegate_->qtDrawHaplotypes(interior, displayBlackAndWhite_, showSubpopulationStrips_, true, nullptr, painter);
1578+
delegate_->qtDrawHaplotypes(interior, displayBlackAndWhite_, showSubpopulationStrips_, true, painter);
15711579
}
15721580
}
15731581
}

QtSLiM/QtSLiMHaplotypeManager.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,14 @@ class QtSLiMHaplotypeManager : public QObject
6767

6868
// Constructing a QtSLiMHaplotypeManager directly is also allowing, if you don't want options or progress
6969
QtSLiMHaplotypeManager(QObject *p_parent, ClusteringMethod clusteringMethod, ClusteringOptimization optimizationMethod,
70-
QtSLiMChromosomeWidgetController *controller, Species *displaySpecies, QtSLiMRange displayedRange,
71-
size_t sampleSize, bool showProgress);
70+
QtSLiMChromosomeWidgetController *controller, Species *displaySpecies, Chromosome *chromosome,
71+
QtSLiMRange displayedRange, size_t sampleSize, bool showProgress);
7272
~QtSLiMHaplotypeManager(void);
7373

7474
#ifndef SLIM_NO_OPENGL
75-
void glDrawHaplotypes(QRect interior, bool displayBW, bool showSubpopStrips, bool eraseBackground, int64_t **previousFirstBincounts);
75+
void glDrawHaplotypes(QRect interior, bool displayBW, bool showSubpopStrips, bool eraseBackground);
7676
#endif
77-
void qtDrawHaplotypes(QRect interior, bool displayBW, bool showSubpopStrips, bool eraseBackground, int64_t **previousFirstBincounts, QPainter &painter);
77+
void qtDrawHaplotypes(QRect interior, bool displayBW, bool showSubpopStrips, bool eraseBackground, QPainter &painter);
7878

7979
// Public properties
8080
QString titleString;
@@ -128,7 +128,7 @@ class QtSLiMHaplotypeManager : public QObject
128128
bool displayingMuttypeSubset = false;
129129

130130
void finishClusteringAnalysis(void);
131-
void configureMutationInfoBuffer(void);
131+
void configureMutationInfoBuffer(Chromosome *chromosome);
132132
void sortHaplosomes(void);
133133
void configureDisplayBuffers(void);
134134
void allocateGLBuffers(void);
@@ -138,12 +138,12 @@ class QtSLiMHaplotypeManager : public QObject
138138
// OpenGL drawing; this is the primary drawing code
139139
#ifndef SLIM_NO_OPENGL
140140
void glDrawSubpopStripsInRect(QRect interior);
141-
void glDrawDisplayListInRect(QRect interior, bool displayBW, int64_t **previousFirstBincounts);
141+
void glDrawDisplayListInRect(QRect interior, bool displayBW);
142142
#endif
143143

144144
// Qt-based drawing, provided as a backup if OpenGL has problems on a given platform
145145
void qtDrawSubpopStripsInRect(QRect interior, QPainter &painter);
146-
void qtDrawDisplayListInRect(QRect interior, bool displayBW, int64_t **previousFirstBincounts, QPainter &painter);
146+
void qtDrawDisplayListInRect(QRect interior, bool displayBW, QPainter &painter);
147147

148148
int64_t *buildDistanceArray(void);
149149
int64_t *buildDistanceArrayForSubrange(void);

0 commit comments

Comments
 (0)