{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "#### **Title**: BoxEdit Stream\n", "\n", "**Description**: A linked streams example demonstrating how to use the BoxEdit stream.\n", "\n", "**Dependencies**: Bokeh\n", "\n", "**Backends**: [Bokeh](./BoxEdit.ipynb)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import holoviews as hv\n", "from holoviews import opts\n", "from holoviews import streams\n", "hv.extension('bokeh')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The ``BoxEdit`` stream adds a bokeh tool to the source plot that allows drawing, dragging, and deleting boxes and making the drawn data available to Python. The tool supports the following actions:\n", "\n", "**Add box**\n", "\n", " Double click to start one corner, then move the pointer to the other corner and double click again. (Or hold shift then click and drag anywhere on the plot.)\n", "\n", "**Move box**\n", "\n", " Click and drag an existing box, the box will be dropped once you let go of the mouse button.\n", "\n", "**Delete box**\n", "\n", " Tap a box to select it then press BACKSPACE or DELETE key while the mouse is within the plot area.\n", " \n", "### Properties\n", "\n", "* **``empty_value``**: Value to add to non-coordinate columns when adding new box\n", "* **``num_objects``** (int): Maximum number of boxes to draw before deleting the oldest object\n", "* **``styles``** (dict): Dictionary of style properties (e.g. line_color, line_width etc.) to apply to each box. If values are lists the values will cycle over the values." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As a very straightforward example we will create a `Rectangles` element containing multiple boxes, then attach it as a source to a ``BoxEdit`` stream instance. When we now plot the ``Rectangles`` instance it will add the tool, letting us draw, drag and delete the box polygons. To limit the number of boxes that can be drawn a fixed number of ``num_objects`` may be defined, causing the first box to be dropped when the limit is exceeded." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "boxes = hv.Rectangles([(0, 0, 1, 1), (2, 1, 3.5, 2.5), (0.5, 1.5, 1.5, 2.5)])\n", "box_stream = streams.BoxEdit(source=boxes, num_objects=3, styles={'fill_color': ['red', 'green', 'blue']})\n", "boxes.opts(\n", " opts.Rectangles(active_tools=['box_edit'], fill_alpha=0.5, height=400, width=400))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Whenever an action is executed the geometry data will be synced with Python, both in the notebook and when deployed on the bokeh server. We can access the data directly as columns of the corners of each box:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "box_stream.data" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Alternatively we can use the ``element`` property to get an Element containing the returned data:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "box_stream.element" ] } ], "metadata": { "language_info": { "name": "python", "pygments_lexer": "ipython3" } }, "nbformat": 4, "nbformat_minor": 4 }