Widgets

If you have read other parts of this document, you have learned that the display on the front of a tile is determined by html returned by the render_content method. The same is true for the return value of cells in a notebook. This can html elements that are interactive, such as buttons and text boxes. However, this makes it awkward to make tile displays that are truly interactive.

As an alternative, you can return widgets. Here’s what that can look like in a tile:

def render_content(self):
    my_text_widget = self.widget("text", {"value": "some text"})
    return [my_text_widget.render()]

The first line here creates a text widget.

The second line renders the widget and returns it as an element in a list. You can also return multiple widgets in a list, and they will be displayed one above the other.

The power comes from the fact that once a widget is created, you can easily change it’s value property from code in a way that will be reflected dynamically. For example:

def render_content(self):
    my_text_widget = self.widget("text", {"value": "some text"})
    ds([my_text_widget.render()]) # immediately renders and displays the widget
    # do some stuff here
    my_text_widget.value = "some new text" # this will update the widget display to this new text
    # do some more stuff here

The general syntax for creating a widget is self.widget(widget_kind, widget_data, **kwargs).

The widget_kind is a string that specifies the type of widget you want to create. The widget_data is a dictionary that contains parameters that define the widget. You can also specify parameters as keyword arguments. Under the hood, widget_data and **kwargs are merged together, so you can use either one to specify any parameters.

Actually, you can dynamically set properties other than value as well. So for example, you could change the options property of a select widget to change the options that are displayed in the dropdown menu. To do those other properties you have to do it using the more general set command, which takes a dict of properties to set. So for example, you could do my_select_widget.set({"options": new_options_list}) to change the options of a select widget.

Note

Where styles are specified, they can be in camel case or in kebab case. So for example, you could specify a background color like this: {"background-color": "red"} or like this: {"backgroundColor": "red"}. Both will work.

Creating widgets in the Tile Creator

If you define widgets in the Tile Creator, that creates a set of widget specs that are saved in your tile definition. Then, when the tile is loaded, widgets are created for each of those specs and attached to the tile instance. So if you define a widget in the Tile Creator with the namemy_widget, you can access that in your code with self.my_widget.

You can then render one of these widgets manually in your code as usual. Also, if you call self.render_all_widgets() in your code, all of the widgets defined in the Tile Creator that have to_render=True will be rendered.

Widget kinds

These are the currently available widgets, along with the parameters they accept. Note that the blueprintjs library is used to render the widgets in the browser. So you might learn more in some cases by referring to the documentation for that library for the corresponding widget: https://blueprintjs.com/docs/.

All widgets also accept a to_render parameter that is a boolean that determines whether the widget will be rendered when self.render_all_widgets() is called.

  • text. Display a string of text.

    • value: The text to display.

    • ellipsize: Whether to truncate the text with an ellipsis if it gets too long.

    • style: A dictionary of styles to be applied.

  • table. Display an interactive table of data

    • value: The table of data. This can be in the form of pandas Datframe, a list of dicts, a TacticDocument, an nltk FreqDist, a dict, a list, or a pandas Series.

    • maxColumnWidth (default=None):

    • expandRows (default=False): Whether rows begin expanded.

    • maxRows (default=50):

    • className (default=””):

    • style (default={}): A dictionary of styles to be applied.

  • slider. Displays an interactive slider.

    • value The current value of the slider.

    • on_change A function that will be called when the slider value changes. This function should take a single argument, which will be the new value of the slider.

    • min (default=0):

    • max (default=10):

    • stepSize (default=1):

    • labelStepSize (default=1)

    • style (default={}): A dictionary of styles to be applied.

  • progressBar. Display a progress bar.

    • value: The current value of the progress bar. This should be a number between 0 and 1.

    • style (default={}): A dictionary of styles to be applied.

    • stripes (default=False): Whether the progress bar should have stripes.

    • intent (default=”primary”): The intent of the progress bar. This can be one of None, “primary”, “success”, “warning”, or “danger”.

    • style (default={}): A dictionary of styles to be applied.

  • html. Displays raw htmls.

    • style (default={}): A dictionary of styles to be applied.

  • iframe. Creates an iframe with data.

    • value: A inline string containing html that will be the srcDoc for the iframe.

    • style (default={}): A dictionary of styles to be applied.

  • divider. Creates a horizontal divider. compact: Passes the compact parameter to blueprintjs. But doesn’t seem to do anything.

    • style (default={}):

  • button. Crates a button.

    • value: The value that will be provided when the button is pressed.

    • text (default=”Button”): The text to display on the button.

    • on_click: A function that will be called when the button is clicked. This function should take a single argument, which will be the value of the button.

    • icon (default=None): The name of a blueprint icon to display on the button. For example, “add” or “delete”.

    • fill (default=False): Whether the button should expand to fill its container.

    • variant (default=”solid”): The variant of the button. This can be one of “solid”, “minimal”, or “outlines”.

    • style (default={}): A dictionary of styles to be applied.

  • switch. Displays a switch that can be toggled on and off.

    • value: The current value of the switch. This should be a boolean.

    • on_change: A function that will be called when the switch value changes. This function should take a single argument, which will be the new value of the switch.

    • label (default=”switch”): The label to display next to the switch.

    • style (default={}): A dictionary of styles to be applied.

  • select. Displays a dropdown select menu.

    • value: The current value of the select menu. This should be a string that matches one of the values in the options list.

    • on_change: A function that will be called when the select value changes. This function should take a single argument, which will be the new value of the select menu.

    • options: A list of options to display in the select menu. Each option can be a string or a dict with “label” and “value” keys.

    • label (default=”select”): The label to display next to the select menu.

    • style (default={}): A dictionary of styles to be applied.

  • input. Displays an input box where users can type text.

    • value: The current value of the input box. This should be a string.

    • fill: (default=False): Whether the input box should expand to fill its container.

    • inline: (default=False): Whether the input box should be displayed inline with its label.

    • on_change: A function that will be called when the input value changes. This function should take a single argument, which will be the new value of the input box.

    • label (default=”input”): The label to display next to the input box.

    • style (default={}): A dictionary of styles to be applied.

  • box. A widget that organizes other widgets. It takes a list of widgets and displays them in a div element to which th the given style is applied.

    • widgets: A list of widgets to display.

    • style (default={}): A dictionary of styles to be applied.

  • collapse. A widget that organizes other widgets into a collapsible section.

    • widgets: A list of widgets to display.

    • label: The label that will appear on the button that expands the section.

    • startOpen (default=True): Whether the section should be expanded by default.

    • intent (default=”primary”): The intent of the button that expands the section.

    • style (default={}): A dictionary of styles to be applied.

  • matplotlib. Displays a matplotlib figure. See below for a full discussion.

    • style (default={}): A dictionary of styles to be applied.

    • use_svg (default=False): Whether to render the figure as an svg.

    • dpi (default=96): The dpi to use when rendering the figure, is use_svg is False.

  • javascript. Displays a widget with executing javascript code. See below for a full discussion.

    • value: A value, typically a dict, that will be passed to the javascript code.

    • code: A string of javascript code to execute. This code should define a function.

Matplotlib widgets

Using the matplotlib widget is just a little more complicated. First you create it. The created wdiget will have a matplotlib Figure object as its fig property. You can then use that figure object to create an axis and plot on it. Finally, before rendering the widget, you have to call the set_html method of the widget.

Here’s how that looks:

w = self.widget("matplotlib")
ax = w.fig.add_subplot(111)
ax.plot([1, 2, 3], [16, 25, 36])
w.set_html()

Javascript widgets

The javascript widget is the most complicated and also the most untested.

You have to create a javascript function with the signature function myFunction(selector, w, h, value, setValue, resizing). Then you pass this code as a string to the code parameter of the widget. The value parameter this javascript function receives will be the value you pass to the widget when you create it.

So your javascript function can look like this:

function showMessage(selector, w, h, value, setValue, resizing) {
    document.querySelector(selector).innerHTML = value;
}

Then your render_content method can look like:

javascript_code_string = ...
w = self.widget("javascript", value="Hello, world!", code=javascript_code_string)
return [w.render()]

Getting javascript code in the form of a string can be a little tricky, but the Tile Creator has a feature for making this a somewhat easier.

The Tile Creator as a section on the left where you can create javascript functions. You can create and name them. Then, when the tile is executed, your extract them from an attribute of the tile called jscript, which is a list of dicts, each with keys “name” and “code”. So you can extract the code for a function named “showMessage” like this:

the_code = None
for fdict in self.jscript:
    if fdict["name"] == "showMessage":
        the_code = fdict["code"]
        break

That’s still a bit clunky, but it’s better than trying to write a big chunk of javascript code as a string in python code. I’ll make it less clunky eventually.

Widgets in the notebook

You can use widgets in a notebook pretty much just like in a tile. There is one critical different however. Rather than returning [my_widget.render()] you instead execute my_widget.show() from anywhere in a cell as it runs, and the widget will be displayed immediately.