GOFIGURE2  0.9.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
QGoLineageViewerWidget.cxx
Go to the documentation of this file.
1 /*=========================================================================
2  Authors: The GoFigure Dev. Team.
3  at Megason Lab, Systems biology, Harvard Medical school, 2009-11
4 
5  Copyright (c) 2009-11, President and Fellows of Harvard College.
6  All rights reserved.
7 
8  Redistribution and use in source and binary forms, with or without
9  modification, are permitted provided that the following conditions are met:
10 
11  Redistributions of source code must retain the above copyright notice,
12  this list of conditions and the following disclaimer.
13  Redistributions in binary form must reproduce the above copyright notice,
14  this list of conditions and the following disclaimer in the documentation
15  and/or other materials provided with the distribution.
16  Neither the name of the President and Fellows of Harvard College
17  nor the names of its contributors may be used to endorse or promote
18  products derived from this software without specific prior written
19  permission.
20 
21  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
23  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
25  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
26  OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
27  OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
28  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
30  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 
33 =========================================================================*/
34 
35 #include <QApplication>
36 
37 #include "ui_QGoLineageViewerWidget.h"
38 #include "QGoLineageViewerWidget.h"
39 
40 // QT general
41 #include <QGridLayout>
42 
43 // Delete Lineage
44 #include <QInputDialog>
45 #include <QStringList>
46 
47 // tab view
48 #include <vtkQtTreeView.h>
49 
50 // graph view
51 #include "vtkGraphLayoutView.h"
52 #include "vtkRenderWindow.h"
53 #include "vtkTreeLayoutStrategy.h"
54 // color coding
55 #include "vtkLookupTable.h"
56 #include "vtkViewTheme.h"
57 
58 // create the tree
59 #include "vtkAdjacentVertexIterator.h"
60 #include "vtkMutableDirectedGraph.h"
61 #include "vtkStringArray.h"
62 #include "vtkDoubleArray.h"
63 #include "vtkPoints.h"
64 #include "vtkTree.h"
65 
66 // get data representation
67 #include "vtkDataRepresentation.h"
68 // get vertex data
69 #include "vtkDataSetAttributes.h"
70 
71 //connect table and graph
72 #include "vtkAnnotationLink.h"
73 #include <vtkEventQtSlotConnect.h>
74 
75 // back plane
76 #include "vtkDelaunay2D.h"
77 #include "vtkGraphToPolyData.h"
78 #include "vtkPolyDataMapper.h"
79 #include "vtkActor.h"
80 #include "vtkRendererCollection.h"
81 
82 //reader
83 #include <QFileDialog>
84 #include <QString>
85 #include "vtkTreeReader.h"
86 
87 //----------------------------------------------------------------------------
88 // Constructor
91  QDockWidget( iParent )
92 {
93  this->ui = new Ui_QGoLineageViewerWidget;
94  this->ui->setupUi(this);
95 
96  // we nee a graph as input of the graph view
97  m_Graph = vtkSmartPointer<vtkMutableDirectedGraph>::New();
98 
99  // we need a tree as input for the table
100  m_Tree = vtkSmartPointer<vtkTree>::New();
101  m_Tree->CheckedDeepCopy(m_Graph);
102 
103  //Create the table View
104  this->m_treeTableView = vtkSmartPointer<vtkQtTreeView>::New();
105  this->ConfigureTableView();
106 
107  //Create the graph View
108  this->m_treeGraphView = vtkSmartPointer<vtkGraphLayoutView>::New();
109  this->ConfigureGraphView();
110 
111  this->FillQtComboBoxes();
112 
113  // add link table and graph annotations
114  this->m_annotationLink = vtkSmartPointer<vtkAnnotationLink>::New();
115  this->m_treeGraphView->GetRepresentation()->SetAnnotationLink(this->m_annotationLink);
116  this->m_treeTableView->GetRepresentation()->SetAnnotationLink(this->m_annotationLink);
117 
118  // connect table and graph
119  this->m_connect = vtkSmartPointer<vtkEventQtSlotConnect>::New();
120  this->m_connect->Connect(this->m_treeTableView->GetRepresentation(),
121  vtkCommand::SelectionChangedEvent,
122  this, SLOT(selectionChanged(vtkObject*, unsigned long, void*, void*)));
123  this->m_connect->Connect(this->m_treeGraphView->GetRepresentation(),
124  vtkCommand::SelectionChangedEvent,
125  this, SLOT(selectionChanged(vtkObject*, unsigned long, void*, void*)));
126 
127  this->ConnectQtButtons();
128 
130 
131  // create the back plane
132  //this->m_backPlane = vtkSmartPointer<vtkDelaunay2D>::New();
133  //this->m_graphToPolyData = vtkSmartPointer<vtkGraphToPolyData>::New();
134  //this->m_graphToPolyData->SetInput(graph);
135  //this->m_graphToPolyData->Update();
136  //this->m_planeMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
137  //this->m_planeActor = vtkSmartPointer<vtkActor>::New();
138 }
139 //----------------------------------------------------------------------------
140 
141 //----------------------------------------------------------------------------
143 {
144 }
145 //----------------------------------------------------------------------------
146 
147 //----------------------------------------------------------------------------
149 {
150  this->m_treeGraphView->AddRepresentationFromInput(m_Graph);
151  this->m_treeGraphView->SetEdgeSelection(false);
152  this->m_treeGraphView->SetLayoutStrategyToTree();
153  this->m_treeGraphView->ResetCamera();
154  this->m_treeGraphView->SetInteractor(
155  this->ui->graphViewWidget->GetInteractor() );
156  this->ui->graphViewWidget->SetRenderWindow(
157  this->m_treeGraphView->GetRenderWindow() );
158 
159  // create LUT
160  this->m_lut = vtkSmartPointer<vtkLookupTable>::New();
161  this->m_lut->SetHueRange(0.667, 0.0);
162  this->m_lut->Build();
163 
164  // create theme
165  vtkSmartPointer<vtkViewTheme> theme =
166  vtkSmartPointer<vtkViewTheme>::New();
167  theme->SetPointLookupTable(this->m_lut);
168  theme->SetCellLookupTable(this->m_lut);
169 
170  this->m_treeGraphView->ApplyViewTheme(theme);
171 
172  // create the layout strategy
173  this->m_treeLayoutStrategy = vtkSmartPointer<vtkTreeLayoutStrategy>::New();
174  this->m_treeLayoutStrategy->SetAngle(90);
175  this->m_treeLayoutStrategy->SetRadial(false);
176  this->m_treeLayoutStrategy->SetLogSpacingValue(1);
177  this->m_treeGraphView->SetLayoutStrategy(this->m_treeLayoutStrategy);
178 }
179 //----------------------------------------------------------------------------
180 
181 //----------------------------------------------------------------------------
183 {
184  QGridLayout* tableLayout = new QGridLayout(this->ui->tableFrame);
185  tableLayout->addWidget(this->m_treeTableView->GetWidget());
186  this->m_treeTableView->AddRepresentationFromInput(m_Tree);
187  this->m_treeTableView->ColorByArrayOn();
188  this->m_treeTableView->SetShowRootNode(false);
189  this->m_treeTableView->Update();
190 }
191 //----------------------------------------------------------------------------
192 
193 //----------------------------------------------------------------------------
195 {
196  // add a lineage
197  connect(this->ui->addLineagePushButton, SIGNAL(pressed()),
198  this, SLOT(slotAddLineage()));
199 
200  connect(this->ui->deleteLineagePushButton, SIGNAL(pressed()),
201  this, SLOT(slotDeleteLineage()));
202 
203  // color coding
204  connect(this->ui->colorCheckBox, SIGNAL(stateChanged(int)),
205  this, SLOT(slotEnableColorCode(int)));
206  connect(this->ui->colorComboBox, SIGNAL(currentIndexChanged(QString)),
207  this, SLOT(slotChangeColorCode(QString)));
208 
209  // scaling
210  connect(this->ui->scaleCheckBox, SIGNAL(stateChanged(int)),
211  this, SLOT(slotEnableScale(int)));
212  connect(this->ui->scaleComboBox, SIGNAL(currentIndexChanged(QString)),
213  this, SLOT(slotChangeScale(QString)));
214 
215  // labeling
216  connect(this->ui->labelCheckBox, SIGNAL(stateChanged(int)),
217  this, SLOT(slotEnableLabel(int)));
218  connect(this->ui->labelComboBox, SIGNAL(currentIndexChanged(QString)),
219  this, SLOT(slotChangeLabel(QString)));
220 
221  // radial rendering
222  connect(this->ui->radialCheckBox, SIGNAL(stateChanged(int)),
223  this, SLOT(slotEnableRadialLayout(int)));
224  connect(this->ui->radialSlider, SIGNAL(valueChanged(int)),
225  this, SLOT(slotChangeRadialLayout(int)));
226 
227  // log rendering
228  connect(this->ui->logCheckBox, SIGNAL(stateChanged(int)),
229  this, SLOT(slotEnableLog(int)));
230  connect(this->ui->logSpinBox, SIGNAL(valueChanged(double)),
231  this, SLOT(slotChangeLog(double)));
232 
233  // back plane
234  connect(this->ui->backCheckBox, SIGNAL(stateChanged(int)),
235  this, SLOT(slotEnableBackPlane(int)));
236 }
237 //----------------------------------------------------------------------------
238 
239 //----------------------------------------------------------------------------
241 {
242  // Fill combo boxes
243  // Update combo boxes (fill content with arrays names)
244  int numberOfArrays = m_Graph->GetVertexData()->GetNumberOfArrays();
245  this->ui->colorComboBox->clear();
246  this->ui->scaleComboBox->clear();
247  this->ui->labelComboBox->clear();
248 
249  // fill comboxes according to the data
250  for(int i=0;i<numberOfArrays; i++)
251  {
252  const char* name =
253  m_Graph->GetVertexData()->GetArrayName(i);
254  this->ui->labelComboBox->addItem(name);
255  // if data array (i.e. numbers), add it
256  if(m_Graph->GetVertexData()->GetArray(name))
257  {
258  this->ui->colorComboBox->addItem(name);
259  this->ui->scaleComboBox->addItem(name);
260  }
261  }
262 
263  // requiered to properly initialize the view since the scaling changes
264  // when we fill the combo box
265  this->slotEnableScale(false);
266 }
267 //----------------------------------------------------------------------------
268 
269 //----------------------------------------------------------------------------
271  unsigned long,
272  void* vtkNotUsed(clientData),
273  void* callData)
274 {
275  this->m_treeTableView->Update();
276  this->m_treeGraphView->Render();
277  }
278 //----------------------------------------------------------------------------
279 
280 //----------------------------------------------------------------------------
282 {
283  QStringList files = QFileDialog::getOpenFileNames( NULL, tr("Select lineages"));
284 
285  for( int i = 0; i < files.size(); i++ )
286  {
287  vtkSmartPointer<vtkTreeReader> reader =
288  vtkSmartPointer<vtkTreeReader>::New();
289  reader->SetFileName(files[i].toLocal8Bit().data());
290  reader->Update();
291 
292  vtkSmartPointer<vtkTree> tree =
293  vtkSmartPointer<vtkTree>::New();
294  tree->CheckedDeepCopy(reader->GetOutput());
295 
296  // update list of graphs
297  std::pair<QString, vtkSmartPointer<vtkTree> > treePair;
298  treePair.first = files[i];
299  treePair.second = tree;
300  m_ListOfTrees.push_back(treePair);
301  }
302 
303  UpdateGraph();
304 }
305 //----------------------------------------------------------------------------
306 
307 //----------------------------------------------------------------------------
309 {
310  // create New graph
311  vtkSmartPointer<vtkMutableDirectedGraph> newGraph =
312  vtkSmartPointer<vtkMutableDirectedGraph>::New();
313  vtkIdType rootID = newGraph->AddVertex();
314 
315  // info
316  vtkSmartPointer<vtkDoubleArray> id =
317  vtkSmartPointer<vtkDoubleArray>::New();
318  id->SetName("Track ID");
319  id->InsertValue(rootID, 0);
320 
321  vtkSmartPointer<vtkDoubleArray> depth =
322  vtkSmartPointer<vtkDoubleArray>::New();
323  depth->SetName("Lineage Depth");
324  depth->InsertValue(rootID, 0);
325 
326  // fill the new graph
327  std::list<std::pair<QString, vtkSmartPointer<vtkTree> > >::iterator
328  it = m_ListOfTrees.begin();
329 
330  while(it != m_ListOfTrees.end())
331  {
332  UpdateTree( rootID, // new ID
333  it->second->GetRoot(), // old ID
334  it->second, // old graph
335  newGraph, // new graph
336  id, // Track ID array
337  1, depth); // original depth, depth array
338 
339  ++it;
340  }
341 
342  newGraph->GetVertexData()->AddArray(id);
343  newGraph->GetVertexData()->AddArray(depth);
344 
345 
346  m_Graph->CheckedDeepCopy(newGraph);
347  m_Tree->CheckedDeepCopy(newGraph);
348 
349  this->ConfigureTableView();
350  this->ConfigureGraphView();
351 
352  this->FillQtComboBoxes();
353 }
354 //----------------------------------------------------------------------------
355 
356 //----------------------------------------------------------------------------
357 void QGoLineageViewerWidget::UpdateTree(vtkIdType iParentID,
358  vtkIdType iOldID,
359  vtkSmartPointer<vtkTree> iOldTree,
360  vtkSmartPointer<vtkMutableDirectedGraph> iNewGraph,
361  vtkDoubleArray* iTrackIDArray,
362  unsigned int iDepth, vtkDoubleArray* iDepthArray)
363 {
364  // build new tree
365  vtkIdType newRoot = iNewGraph->AddChild(iParentID);
366 
367  // update information array
368  vtkDataArray* id = iOldTree->GetVertexData()->GetArray("Track ID");
369  double value = id->GetTuple1(iOldID);
370  iTrackIDArray->InsertValue( newRoot, value );
371 
372  iDepthArray->InsertValue(newRoot, iDepth);
373 
374  // go through tree
375  vtkSmartPointer<vtkAdjacentVertexIterator> it =
376  vtkSmartPointer<vtkAdjacentVertexIterator>::New();
377  iOldTree->GetChildren(iOldID, it);
378 
379  while(it->HasNext())
380  {
381  UpdateTree(newRoot, it->Next() , iOldTree, iNewGraph,
382  iTrackIDArray,
383  iDepth+1, iDepthArray);
384  }
385 
386 }
387 //----------------------------------------------------------------------------
388 
389 //----------------------------------------------------------------------------
391 {
392  bool ok;
393  QStringList lineages;
394 
395  std::list<std::pair<QString, vtkSmartPointer<vtkTree> > >::iterator
396  it = m_ListOfTrees.begin();
397 
398  while(it != m_ListOfTrees.end())
399  {
400  lineages << it->first;
401  ++it;
402  }
403 
404  QString item =
406  tr("Lineage selection"),
407  tr("Please select the lineage you want to delete"),
408  lineages, 0, false, &ok);
409 
410  // Remove from the list
411  it = m_ListOfTrees.begin();
412  while(it != m_ListOfTrees.end())
413  {
414  if( ! it->first.compare(item) ) // compare returns 0 if QStrings are equal
415  {
416  m_ListOfTrees.erase(it);
417  break;
418  }
419  ++it;
420  }
421 
422  // update the graph
423  UpdateGraph();
424 }
425 //----------------------------------------------------------------------------
426 
427 //----------------------------------------------------------------------------
429 {
430  this->m_treeGraphView->SetColorVertices(state);
431 
432  //update visu
433  this->m_treeGraphView->Render();
434 }
435 //----------------------------------------------------------------------------
436 
437 //----------------------------------------------------------------------------
439 {
440  this->m_treeGraphView->SetVertexColorArrayName(array.toLocal8Bit().data());
441  this->m_treeGraphView->SetEdgeColorArrayName(array.toLocal8Bit().data());
442 
443  //update visu
444  this->m_treeGraphView->Render();
445 }
446 //----------------------------------------------------------------------------
447 
448 //----------------------------------------------------------------------------
450 {
451  //scale
452  this->m_treeLayoutStrategy->SetDistanceArrayName
453  (state ? this->ui->scaleComboBox->currentText().toLocal8Bit().data() : NULL);
454 
455  //update visu
456  this->m_treeGraphView->ResetCamera();
457  this->m_treeGraphView->Render();
458 }
459 //----------------------------------------------------------------------------
460 
461 //----------------------------------------------------------------------------
463 {
464  this->m_treeLayoutStrategy->SetDistanceArrayName(array.toLocal8Bit().data());
465 
466  //update visu
467  this->m_treeGraphView->ResetCamera();
468  this->m_treeGraphView->Render();
469 }
470 //----------------------------------------------------------------------------
471 
472 //----------------------------------------------------------------------------
474 {
475  //scale
476  this->m_treeGraphView->SetVertexLabelVisibility(state);
477 
478  //update visu
479  this->m_treeGraphView->Render();
480 }
481 //----------------------------------------------------------------------------
482 
483 //----------------------------------------------------------------------------
485 {
486  this->m_treeGraphView->SetVertexLabelArrayName(array.toLocal8Bit().data());
487 
488  //update visu
489  this->m_treeGraphView->Render();
490 }
491 //----------------------------------------------------------------------------
492 
493 //----------------------------------------------------------------------------
495 {
496  if(!state)
497  {
498  this->m_treeLayoutStrategy->SetAngle(90);
499  }
500  else
501  {
502  this->m_treeLayoutStrategy->SetAngle( this->ui->radialSlider->value() );
503  }
504 
505  //radial layout
506  this->m_treeLayoutStrategy->SetRadial(state);
507 
508  //update visu
509  this->m_treeGraphView->ResetCamera();
510  this->m_treeGraphView->Render();
511 }
512 //----------------------------------------------------------------------------
513 
514 //----------------------------------------------------------------------------
516 {
517  if(this->ui->radialCheckBox->isChecked() )
518  {
519  // change the layout angle
520  this->m_treeLayoutStrategy->SetAngle( angle );
521 
522  //update visu
523  this->m_treeGraphView->ResetCamera();
524  this->m_treeGraphView->Render();
525  }
526 }
527 //----------------------------------------------------------------------------
528 
529 //----------------------------------------------------------------------------
531 {
532  if(!state)
533  {
534  this->m_treeLayoutStrategy->SetLogSpacingValue(1);
535  }
536  else
537  {
538  this->m_treeLayoutStrategy->SetLogSpacingValue( this->ui->logSpinBox->value() );
539  }
540 
541  //update visu
542  this->m_treeGraphView->ResetCamera();
543  this->m_treeGraphView->Render();
544 }
545 //----------------------------------------------------------------------------
546 
547 //----------------------------------------------------------------------------
549 {
550  if(this->ui->logCheckBox->isChecked() )
551  {
552  // change the layout angle
553  this->m_treeLayoutStrategy->SetLogSpacingValue( angle );
554 
555  //update visu
556  this->m_treeGraphView->ResetCamera();
557  this->m_treeGraphView->Render();
558  }
559 }
560 //----------------------------------------------------------------------------
561 
562 //----------------------------------------------------------------------------
564 {
565  if(state)
566  {
567  //this->m_backPlane->SetInput(
568  // this->m_graphToPolyData->GetOutput());
569  this->m_planeMapper->SetInput(
570  this->m_graphToPolyData->GetOutput());
571  this->m_planeActor->SetMapper(this->m_planeMapper);
572  this->ui->graphViewWidget->GetRenderWindow()->GetRenderers()
573  ->GetFirstRenderer()->AddActor(this->m_planeActor);
574  }
575  else
576  {
577  this->ui->graphViewWidget->GetRenderWindow()->GetRenderers()
578  ->GetFirstRenderer()->RemoveActor(this->m_planeActor);
579  }
580 
581  //update visu
582  this->m_treeGraphView->Render();
583 }
584 //----------------------------------------------------------------------------
vtkSmartPointer< vtkGraphToPolyData > m_graphToPolyData
QGoLineageViewerWidget(QWidget *iParent=0)
QString getItem(QWidget *parent, const QString &title, const QString &label, const QStringList &items, int current, bool editable, bool *ok, QFlags< Qt::WindowType > flags, QFlags< Qt::InputMethodHint > inputMethodHints)
void slotChangeColorCode(QString array)
void addWidget(QWidget *widget, int row, int column, QFlags< Qt::AlignmentFlag > alignment)
vtkSmartPointer< vtkActor > m_planeActor
void slotChangeScale(QString array)
QString tr(const char *sourceText, const char *disambiguation, int n)
int size() const
vtkSmartPointer< vtkMutableDirectedGraph > m_Graph
const char * name() const
std::list< std::pair< QString, vtkSmartPointer< vtkTree > > > m_ListOfTrees
T & first()
vtkSmartPointer< vtkTree > m_Tree
vtkSmartPointer< vtkQtTreeView > m_treeTableView
void slotChangeLabel(QString array)
QByteArray toLocal8Bit() const
vtkSmartPointer< vtkAnnotationLink > m_annotationLink
vtkSmartPointer< vtkLookupTable > m_lut
void selectionChanged(vtkObject *, unsigned long, void *, void *)
vtkSmartPointer< vtkEventQtSlotConnect > m_connect
char * data()
void UpdateTree(vtkIdType iParentID, vtkIdType iOldID, vtkSmartPointer< vtkTree > iOldTree, vtkSmartPointer< vtkMutableDirectedGraph > iNewGraph, vtkDoubleArray *iTrackIDArray, unsigned int iDepth, vtkDoubleArray *iDepthArray)
vtkSmartPointer< vtkPolyDataMapper > m_planeMapper
Ui_QGoLineageViewerWidget * ui
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
int depth() const
vtkSmartPointer< vtkTreeLayoutStrategy > m_treeLayoutStrategy
vtkSmartPointer< vtkGraphLayoutView > m_treeGraphView
QStringList getOpenFileNames(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFlags< QFileDialog::Option > options)