Holoviews Annotator in panel.serve environment

I’m trying to create a simple rectangle annotator, that works under servable Panel environment and allows the user to annotate initial list of rectangles and offers option to add new ones.
Based on the documentation example, I created the following minimal code:

import holoviews as hv
import panel as pn

initial_data = {"x0": [1, 2], "y0": [4, 5], "x1": [7, 6], "y1": [2, 9],
                  "Label": ["abc", "def"], "Color": ["red", "yellow"]}

boxes = hv.Rectangles(initial_data).opts(color="Color")
box_annotator = hv.annotate.instance()
annotator_layout = box_annotator(boxes.opts(width=800, height=400, fill_alpha=0.5, responsive=False),
                                 annotations={'Label': str, 'Color': str})
button = pn.widgets.Button(name='Get data', button_type='primary')

def on_click(event):
    df = box_annotator.annotated.dframe()

layout1 = pn.Column(annotator_layout, button)

if __name__ == "__main__":

The code runs, shows two rectangles and a table + button to get the data back. Now, if I go to the table and directly try to update the Label (important: without touching the plot widget first), the on_click handler prints incorrect data. Namely, if I enter label text longer than the text coming from initial_data (e.g. replace “abc” with “bokeh”), the printed data frame will have only 3 characters of label - i.e. only “bok”.

    x0   y0   x1   y1 Label   Color
0  1.0  2.0  7.0  4.0   bok     red
1  2.0  5.0  6.0  9.0   def  yellow

Now, the things get interesting. If I go to the plot, activate the BoxEdit tool and draw a new rectangle, then the data frame will start to look correct and contain full labels.
If I run the same code in Jupyter (reading box_annotator.annotated.dframe() in a separate cell instead of using a button), the updates work fine.

Do you have any idea what I’m doing wrong in the Panel environment?
And also extra question: is there any way that the editable “Color” column can be linked to the color property of rectangles? Changing color from there does not trigger plot updates.

Try adding pn.extension() under hv.extension(), not sure it resolves your issues because I’m not fully following but if I don’t have it the code doesn’t really work, when it’s added the box select tool works better and can see the table updating straight away hope it helps,

Thanks, Carl

thanks for reply. Adding pn.extension() didn’t help. It still has problems with updates of the label.

Hi @kda

I tried running your code and trying to understand how HoloViews works. But it impossible for me as

  • I get no help to “go to definition” in VS Code as VS Code cannot understand HoloViews for many reasons
    • Missing or poor docstrings
    • Very abstract programming style that is impossible to follow for static analysers
  • I was not able to explore and follow the object interactively using Ipython. Its very difficult to find out what to look for as there are so many nested parameters.
  • I was not able to find any useful documentation at the HoloViews site to help me get a mental model of how the hv.annotate.instance() works.

I hope the original developers will chime in as I believe its needed here.

Hi @Marc,
I also tried to understand the code by myself. I figured out, that the actual implementation of the hv.annotate.instance is in the file annotators.py (actual location depends on how Holoviews package was installed). There is a class called Annotator and its descendant RectangleAnnotator.
Also, the connection between table and plot (using JavaScript) is set by the class RectanglesTableLinkCallback (file: plotting\bokeh\callbacks.py). The actual binding seems to be executed from a compiled code (in PyCharm at some point I stopped at no-symbols stack trace).
However, I couldn’t still figure it out how can I control that manually.

1 Like