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:
- Easy to plot trees with a "time" y-axis
- Good performance with large (~2**8 branch) trees
- Ability to easily embed in
QT
so it can be anapari
widget. - 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
- Not easy to do simple graph plots (the vispy.plot subpackage is currently experimental)
- Probably good performance
- Easy to embed (see this StackOverflow post)
- No easy way to do tooltips
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
?