A tree widget from jsTree

Hello there,

After some vacation I decided to solve another problem I have: an interactive tree widget. This is essential for me as I have a lot of data (and subdatas) to show in the interface.

I searched a bit over the internet and found jsTree, which I liked very much, particularly because it is customizable as I need.

image

I’ve implemented it in my convoluted way as I wanted it not to feel as a custom widget, but part of panel (and hopefully included through a PR). Be aware that the only thing I know (even if limit as I am not a programmer) is python, I learned to really dislike TypeScript and jQuery.

So…there is a model and a widget, both files named jstree.py. The TypeScript I included as an “__implementation__” because I don’t know how to pre-compile it.

  1. model:jstree.py (4.5 KB) (panel\modulesfolder)

  2. widget:jstree.py (2.2 KB) (panel\widgets folder)

Also, I have changed three other files:

  1. config.py: I added to the _imports:

‘jstree’: ‘panel.models.jstree’

  1. index.ts: I don’t know if it is important or not, but I added

export {jsTreePlot} from “./jstree”

  1. init.py: inside panel/widgets and added

from .jstree import jsTree # noqa

note: I did not create a dist\bundled\jstreeplot folder with tthe js and css files because I am calling it from a CDN, but it is an option run it locally.

I also included a tree.py file with an example. I managed to make the callbacks work, so if you update “value” property with another tree or “show_icons” / “show_dots” with True/False it updates on screen and if you select a node you can get information on that node back to python.
tree.py (1.9 KB)

I’d like to thank @Marc for one of his posts here on custom Bokeh Model which really allowed me to make it work.

I still have a few questions on why somethings exactly as for other widgets/models work and I havd to make it different, andsome other that I included, but I don’t know what it does.

A gif with what i’ve done:
2021-02-27_18-25-09

2 Likes

Awesome @miliante

Some thoughts.

  1. I have for a long time wanted to create a template or repository that should make it much easier to develop and share custom bokeh/ panel extensions. Maybe it’s time and could be used to share this widget?

  2. I think though that a tree widget is important to have in Panel. Why did you choose this one and which competing widgets are there?

  3. Could you share a code example of using the widget a video or gif? That would help users try it out.

2 Likes

Hello @Marc, I’ve updated the post with a GIF. Hope it helps.

Yes, please share as much as possible. Hopefully other people will implement more options as I don’t have time to implement it and i’d love to have more flexibility with the widgets :wink: I use Panel for work, that is, not development of Panel, but as a GUI for post-processing of my motion routines which are in Python (backend) and I only play with these widgets (frontend) when I have time at home. I am cenrtainly not a fornt-end guy. I hope to be an incentive for other people to continuing to implement more into these (or alternative ones)

I chose this one for the same reasons as the terminal: small, functional, free, simple to implement. I confess I did not do an extensive search for all available options and perhaps it may be more interesting to wait for a more “complete” alternative to actually include in Panel.

1 Like

Hi, do you have any plan to relese a TreeWidget?
Thank you!

1 Like

I have not seen a request no Github. If you would like a Treewidget could you create a request there @davidpasquale ? Thanks.

@militante:
Awesome widget. I need something similar for a project I am involved with. I repeated exactly the same steps you posted Feb 21st. Unfortunately it did not work.
When trying to run your test (tree.py), I am getting the following error:
Exception has occurred: ImportError
cannot import name ‘bundled_files’ from ‘panel.util’ (/home/mtorre/.local/lib/python3.8/site-packages/panel/util.py)
File “/home/mtorre/python/bi-adapter/tree.py”, line 4, in
pn.extension(‘jstree’)

I wonder if you may help me out. Most likely I am making a rookie mistake.
Thank you,
Mario

@mtorre-iot I also have need of a Tree widget, and like Marc, I think a Tree Widget would be a nice addition to panel. I think @miliante has a good start and after doing some research as well, jsTree does seem like a good choice for a library to build tree widgets with. It is one of the more popular js tree libraries, it is has active development. It is very configurable, allowing you to customize the icons for all of the nodes and leaves with built in images, local images, or remote icon classes. It has configuration options for checkboxes, drag and drop the nodes around, a search box menu, and a lot more. It has a robust api allowing a lot of flexibility in how the tree behaves. Exposing a lot of events already on the JS side that can trigger all sorts of things, such as a before_node, open_node, and after_node events that are triggered before a node is opened, when a node is opened, and after it is opened and after the animation is complete. So I do think jsTree is a good choice.

I have plans to try and fully flesh out the jsTree that @miliante started last year and make a PR with a BaseTreeWidget class and at least a FileTree widget concrete implementation for server side file browsing. I have found that the FileSelector widget to be cumbersome and not very pretty. I start a couple days ago, and this is what I have so far. It takes a directory (defaults to cwd), and then lets you search through that directory downwards. It doesn’t do an exhaustive search, but as you open more nodes, it hands more data to jsTree.

import panel as pn

pn.extension("jstree")


ft = pn.widgets.FileTree(
    directory="~/Documents/panel_tree",
    checkbox=True
)

pn.Column(ft).servable()

file_tree

2 Likes

An updated for anyone who is interested. I have it so that you can turn off multiselect (demonstrated here) and you can on the FileTree directly assign to the value attribute to select a node, even if it isn’t populated in the tree yet. Since the nodes in the tree a populated lazily, if you pass a filepath that is a child of a child of a… a child of the bottommost node, it populates that new node and all of its intermediate parents too, and then select it.

Here it is with some other widgets for layouting

ft_text_box

Here is the repo if anyone wants to install it and try it out. It is still buggy, so be warned

You should be able to do a pip install git+https://github.com/madeline-scyphers/panel-jstree
to install it. You will also need nodejs >= 14, which you can do yourself or through conda: conda install -c conda-forge 'nodejs>=14'

Just wanted to give an update to anyone watching and wanting to use it before I try while it is a wip.

4 Likes

Hi madeline-scyphers:

Thanks for you tree widget that is a amazing work.

1 Like

I wanted to give an update on this.

with Philips help, I got it into panel 1. And I have made some major improvements on it over the summer with more time. It is also now on PyPI and Conda (with hopes of someday soonish of going into Panel). It has an abstract BaseTree class and two concrete implementations. a general Tree class that lets you use either static data (data you don’t change), or you can lazy load more data by passing in a callable that will load new node children as you open more nodes. It also has a number of parameters you can adjust from the GUI. Then there is also the FileTree that works as a server side file browser, similar to the FileSelector in Panel. It supports multiselect and single select. Lazy loads the nodes as you open them, and if you directly set the current value to something not loaded (a great-great-great grandchild of the loaded nodes), it will recursively load the parents until that node is loaded and selected. There are many more things to come before I think it would be ready for a PR to panel, but I would love for people to give me their thoughts! The docs right now are only what is in the parameters, so pretty still early.

This is the file tree
file-tree

This is a basic Tree that swaps out the data with a panel button hooked to a callback
simple_tree

This is a tree that produces random nodes based on a custom callable passed in at init
random-tree

All 3 are in the repo with instructions in the README on how to run

4 Likes

Hi madeline

Thanks for the update of the JS tree widget. it is amazing.

I get a issue when i use try to replace the _data of the tree widget.

please see example code:

import panel as pn
pn.extension()
from panel_jstree import FileTree
ft = FileTree(
    checkbox=False,
    select_multiple = True,
    width = 500,
    height = 1000
)
ft._data =[{'id': 'new_folder1',
              'text': 'new_folder1',
              'icon': 'jstree-folder'},
             {'id': 'new_folder2',
              'text': 'new_folder2',
              'icon': 'jstree-folder'}]
txt = pn.widgets.StaticText(name='Static Text', value='')
ft.link(txt, value='value')


pn.Column(txt,ft).show()

When i replace the _data of the tree widget, the it need click the check box twich to the select it visually

i am really greatful if you could give me sugget in this issue:

Kind regard
Victor