lowe-lab-ucl / arboretum

Track and lineage visualization with btrack and Napari :evergreen_tree:

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Changing the plotting backend

dstansby opened this issue · comments

I think it has been decided to move away from using pyqtgraph as the plotting backend, based on performance issues with large trees (#16). Requirements for the plotting backend are:

  1. Easy to plot trees with a "time" y-axis
  2. Good performance with large (~2**8 branch) trees
  3. Ability to easily embed in QT so it can be a napari widget.
  4. Easy to implement tooltips for hovering over the tree and reading off the value represented by the tree colour

Perhaps there are more requiremenst? If anyone has any please edit this or leave a comment below!

Options to consider are:

Vispy

Matplotlib

  • Easy to do simple graph plots
  • Probably good performance
  • Easy to embed (see this GH issue comment)
  • No easy way to do tooltips

Bokeh

  • Easy to do simple graph plots
  • Not sure how good performance is?
  • Easy to embed - we can embed a HTML page directly into a QWidget
  • First class support for tooltips

Are there any other backends we should consider? And are there any other points anyone else can add to the above considerations based on their experience?

A while ago, I had a quick go at making a VisPy tree renderer. I'll post the code here, FYI:

from vispy import scene

class ArboretumCanvas(scene.SceneCanvas):
    def __init__(self):
        scene.SceneCanvas.__init__(self, keys=None, size=(600, 1200))

        self.unfreeze()
        self.size = 600, 1200
        self.view = self.central_widget.add_view()
        self.view.camera = scene.PanZoomCamera()
        self.tree = TreeVisual(parent=None) #self.view.parent)
        self.view.add(self.tree)
        self.freeze()
        

class TreeVisual(scene.visuals.Compound):
    def __init__(self, parent):
        scene.visuals.Compound.__init__(self, [])
        self.parent = parent
        self.unfreeze()
        self.tracks = []

    def add_track(self, pos, color):
        visual = scene.visuals.Line(pos=pos, color=color, width=3)
        scene.visuals.Compound.add_subvisual(self, visual)
        self.tracks.append(visual)

    def clear(self):
        while self.tracks:
            track = self.tracks.pop()
            scene.visuals.Compound.remove_subvisual(self, track)

The ArboretumCanvas can be added to the main QWidget pretty easily, and the VisPy LineVisual is quite flexible for setting lines with properties such as colors. In fact, this is how the Tracks layer works in napari, so I know the performance is really good with very large numbers of vertices.

Thanks for the code - myself and @alessandrofelder adapted it this morning into a proof of concept, and we believe that vispy is the right way forward here 👍 .

what about plotly?