Hi!

I'd like to write a browser for nucleotide sequence alignments. You could see "alignments" as huge matrices of coloured tiles, with the background colour of the tile and the letter printed on it indicating the type of nucleotide at that position. The matrix is full and, when displayed, the area is completely covered by the tiles. The content of the matrix doesn't change and we only want to display it. The size of the matrix varies a lot: it can be from 20 (rows) x 500 (columns) up to hundreds or thousands of rows and tens or hundreds of thousands of columns. We can here assume that it is 80 rows times 5000 columns, giving in total 400k tiles. "Browsing the alignment" means that we can move around to see different parts of the matrix and zoom in/out to see either exact details or an overview.

I have an implementation that seems to work reasonably well but there are details that could be improved (see blow for the code). I followed the 4k Chips example and used objects inheriting QGraphicsItem to show more details (letter) when zoomed in and only the colour when zoomed out. The main problem in my implementation is its slowness when zooming out and showing lots of items simultaneously.

My idea to get around this bottleneck is to render an image of the matrix when the zoom-out level is such that the exact details won't anyway be shown, and scale that pixmap to zoom further out. When zooming in, the pixmap would be replaced by the individually drawn tiles. This is my idea but I don't know how to do that. I'm quite sure it's doable and possibly someone has already done something similar. Can you give links to existing code or suggestions how you would do it. If you know a much better way to get around this zooming problem, I'd obviously be very happy to hear about that.

I've attached code that generates dummy data and displays these in a browser window. When you zoom out (Ctrl+mouse wheel) you can see that the scaling isn't smooth and the application becomes unresponsive.

Thanks a lot for any help!

Qt Code:
  1. #include <qapplication.h>
  2. #include <qmainwindow.h>
  3. #include <qgraphicsview.h>
  4. #include <qgraphicsscene.h>
  5. #include <qgraphicsitem.h>
  6. #include <QWheelEvent>
  7. #include <QtOpenGL>
  8. #include <qmath.h>
  9. #include <qcolor.h>
  10.  
  11. using namespace std;
  12.  
  13.  
  14. class BaseTile : public QGraphicsItem
  15. {
  16. public:
  17. BaseTile(int i);
  18. QRectF boundingRect() const{ return QRectF(0, 0, 20, 20); }
  19.  
  20. void paint(QPainter *painter, const QStyleOptionGraphicsItem *item, QWidget *widget);
  21. private:
  22. QColor color;
  23. QChar base_char;
  24. };
  25.  
  26.  
  27. class MainWindow : public QMainWindow
  28. {
  29. public:
  30. MainWindow(QWidget *parent = 0);
  31. private:
  32. void wheelEvent(QWheelEvent * event);
  33.  
  34. QGraphicsView *graphicsView;
  35. };
  36.  
  37. /////////////////////
  38.  
  39. BaseTile::BaseTile(int i)
  40. {
  41. QString alpha = "ACGT";
  42. QColor tile_colors[] = { QColor("blue"), QColor("green"), QColor("yellow"), QColor("red") };
  43.  
  44. base_char = alpha.at(i);
  45. color = tile_colors[i];
  46. }
  47.  
  48. void BaseTile::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
  49. {
  50. Q_UNUSED(widget);
  51.  
  52. const qreal lod = option->levelOfDetailFromTransform(painter->worldTransform());
  53. if (lod < 0.5) {
  54. painter->fillRect(QRectF(0, 0, 20, 20), color);
  55. return;
  56. }
  57.  
  58. QBrush b = painter->brush();
  59. painter->fillRect(QRectF(0, 0, 20, 20), color);
  60. painter->setFont(QFont("Times",10));
  61. painter->setPen(QColor("black"));
  62. painter->drawText(0, 0, 20, 20,0x0084, QString(base_char));
  63. }
  64.  
  65. /////////////////////
  66.  
  67. void MainWindow::wheelEvent(QWheelEvent * e)
  68. {
  69. if ( e->modifiers() == Qt::ControlModifier )
  70. {
  71. int numSteps = ( e->delta() / 8 ) / 15;
  72.  
  73. QMatrix mat = graphicsView->matrix();
  74.  
  75. if ( numSteps > 0 )
  76. mat.scale( numSteps * 1.2, numSteps * 1.2 );
  77. else
  78. mat.scale( -1 / ( numSteps * 1.2 ), -1 / ( numSteps * 1.2 ) );
  79.  
  80. graphicsView->setMatrix(mat);
  81. e->accept();
  82. }
  83. }
  84.  
  85. MainWindow::MainWindow(QWidget *parent) :
  86. QMainWindow(parent)
  87. {
  88.  
  89. // generate random data to display
  90. //
  91. vector< vector<int> > data;
  92. int seq_length = 5000;
  93. int num_seq = 80;
  94.  
  95. vector<int> seq0;
  96. for(int j=0;j<seq_length;j++)
  97. {
  98. seq0.push_back( int(rand()/float(RAND_MAX)*4) );
  99. }
  100. data.push_back(seq0);
  101.  
  102. for(int i=1;i<num_seq;i++)
  103. {
  104. vector<int> seq_i;
  105. for(int j=0;j<seq_length;j++)
  106. {
  107. if(rand()/float(RAND_MAX)*20 < 1)
  108. seq_i.push_back( int(rand()/float(RAND_MAX)*4) );
  109. else
  110. seq_i.push_back( data.at(0).at(j) );
  111. }
  112. data.push_back(seq_i);
  113. }
  114.  
  115.  
  116.  
  117. // the browser stuff
  118. //
  119. scene = new QGraphicsScene();
  120.  
  121. int y_pos = 0;
  122. for (int i = 0; i < num_seq; i++)
  123. {
  124. int x_pos = 0;
  125.  
  126. for (int j = 0; j < seq_length; j++)
  127. {
  128. int base = data.at(i).at(j);
  129.  
  130. BaseTile *item = new BaseTile(base);
  131. item->setPos(QPointF(x_pos, y_pos));
  132. scene->addItem(item);
  133.  
  134. x_pos += 20;
  135. }
  136. y_pos += 20;
  137. }
  138.  
  139.  
  140. graphicsView = new QGraphicsView(this);
  141. graphicsView->setRenderHint(QPainter::Antialiasing, false);
  142. graphicsView->setDragMode(QGraphicsView::ScrollHandDrag);
  143. graphicsView->setOptimizationFlags(QGraphicsView::DontSavePainterState);
  144. graphicsView->setViewportUpdateMode(QGraphicsView::SmartViewportUpdate);
  145. graphicsView->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
  146. graphicsView->setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));
  147. graphicsView->setScene(scene);
  148. graphicsView->setGeometry(QRect(50, 50, 100, 100));
  149. graphicsView->show();
  150.  
  151.  
  152. this->setCentralWidget(graphicsView);
  153.  
  154. }
  155.  
  156. /////////////////////
  157.  
  158. int main(int argc, char *argv[])
  159. {
  160. QApplication a(argc, argv);
  161.  
  162. MainWindow w;
  163. w.show();
  164. return a.exec();
  165. }
  166.  
  167. /////////////////////
  168.  
  169. /*
  170. g++ -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4/QtOpenGL -I/usr/include/qt4 -L/usr/lib -lQtOpenGL -lQtGui -lQtCore -lGLU -lGL -lpthread test.cpp -o test
  171. */
To copy to clipboard, switch view to plain text mode