From 214241bdfe308ec4f536761d23e21499e06c0ab8 Mon Sep 17 00:00:00 2001 From: Itay Dafna Date: Sat, 26 Jun 2021 20:39:29 -0700 Subject: [PATCH 1/8] Add ipydatagrid/other-libraries notebooks, move old notebooks to widget_libraries folder Signed-off-by: Itay Dafna --- notebooks/07.00-More_widget_libraries.ipynb | 6 +- notebooks/07.03-ipydatagrid.ipynb | 900 ++++++++++++++++++ notebooks/07.05-other-widget-libraries.ipynb | 33 + .../07.01-ipyleaflet.ipynb | 0 .../07.02-pythreejs.ipynb | 0 .../07.03-bqplot.ipynb | 6 +- .../07.xx-ipyvolume.ipynb} | 0 7 files changed, 939 insertions(+), 6 deletions(-) create mode 100644 notebooks/07.03-ipydatagrid.ipynb create mode 100644 notebooks/07.05-other-widget-libraries.ipynb rename notebooks/{ => widgets_libraries}/07.01-ipyleaflet.ipynb (100%) rename notebooks/{ => widgets_libraries}/07.02-pythreejs.ipynb (100%) rename notebooks/{ => widgets_libraries}/07.03-bqplot.ipynb (99%) rename notebooks/{07.04-ipyvolume.ipynb => widgets_libraries/07.xx-ipyvolume.ipynb} (100%) diff --git a/notebooks/07.00-More_widget_libraries.ipynb b/notebooks/07.00-More_widget_libraries.ipynb index 63a58546..a61ae1a3 100644 --- a/notebooks/07.00-More_widget_libraries.ipynb +++ b/notebooks/07.00-More_widget_libraries.ipynb @@ -52,9 +52,9 @@ ], "metadata": { "kernelspec": { - "display_name": "widgets-tutorial", + "display_name": "Python 3", "language": "python", - "name": "widgets-tutorial" + "name": "python3" }, "language_info": { "codemirror_mode": { @@ -66,7 +66,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.3" + "version": "3.8.10" } }, "nbformat": 4, diff --git a/notebooks/07.03-ipydatagrid.ipynb b/notebooks/07.03-ipydatagrid.ipynb new file mode 100644 index 00000000..1dea7501 --- /dev/null +++ b/notebooks/07.03-ipydatagrid.ipynb @@ -0,0 +1,900 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "4d5ce026", + "metadata": {}, + "source": [ + "# `ipydatagrid`: fast, performant data grid\n", + "\n", + "## https://github.com/bloomberg/ipydatagrid\n", + "\n", + "### Full canvas rendering\n", + "\n", + "`ipydatagrid` is a complete data grid solution providing full integration with pandas DataFrames without compromising on performance:\n", + "\n", + "- built-in sorting and filtering\n", + "- full integration with the jupyter-widgets ecosystem\n", + "- highly customisable renderers\n", + "- complete two-way data binding between Python and the front-end\n", + "- supports Vega expressions for conditional formatting and styling\n", + "\n", + "**Installation**:\n", + "```bash\n", + "conda install -c conda-forge ipydatagrid\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "30f4cc0e", + "metadata": {}, + "outputs": [], + "source": [ + "from ipydatagrid import DataGrid, TextRenderer, BarRenderer, Expr, VegaExpr\n", + "import pandas as pd\n", + "import numpy as np\n", + "import requests" + ] + }, + { + "cell_type": "markdown", + "id": "7b847f68", + "metadata": {}, + "source": [ + "#### Use any dataset" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b382fc75", + "metadata": {}, + "outputs": [], + "source": [ + "# Numpy/pandas\n", + "np.random.seed(0)\n", + "p_t, n = 100, 260\n", + "stock_df = pd.DataFrame(\n", + " {f'Stock {i}': p_t + np.round(np.random.standard_normal(n).cumsum(), 2) for i in range(10)}\n", + ")\n", + "\n", + "# Requests/JSON\n", + "req = requests.get(\"https://raw.githubusercontent.com/bloomberg/ipydatagrid/main/examples/cars.json\")\n", + "data = req.json()\n", + "cars_data = data['data']\n", + "\n", + "\n", + "# Random matrix\n", + "rand_df = pd.DataFrame(\n", + " {f'Column {col}': np.round(np.random.random(100), 2) for col in [chr(n) for n in range(65, 91)]}\n", + ")\n", + "\n", + "# Small grid\n", + "small_df = pd.DataFrame(\n", + " np.eye(10),\n", + " columns=[f'Col {i}' for i in range(10)],\n", + " index=[f'Row {i}' for i in range(10)]\n", + ")\n", + "\n", + "# Multi-index\n", + "top_level = ['Value Factors', 'Value Factors', 'Momentum Factors', 'Momentum Factors']\n", + "bottom_level = ['Factor A', 'Factor B', 'Factor C', 'Factor D']\n", + "\n", + "nested_df = pd.DataFrame(np.random.randn(4,4).round(2),\n", + " columns=pd.MultiIndex.from_arrays([top_level, bottom_level]),\n", + " index=pd.Index(['Security {}'.format(x) for x in ['A', 'B', 'C', 'D']], name='Ticker'))" + ] + }, + { + "cell_type": "markdown", + "id": "ab90aa2c", + "metadata": {}, + "source": [ + "#### Convert your pandas DataFrame to a datagrid - it 'just works'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "94b69044", + "metadata": {}, + "outputs": [], + "source": [ + "df = pd.DataFrame(cars_data).set_index('index')\n", + "df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c2ae788a", + "metadata": {}, + "outputs": [], + "source": [ + "grid = DataGrid(df)\n", + "grid" + ] + }, + { + "cell_type": "markdown", + "id": "691cac62", + "metadata": {}, + "source": [ + "Additional constructor options" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8b18b862", + "metadata": {}, + "outputs": [], + "source": [ + "grid = DataGrid(\n", + " dataframe=df,\n", + " base_row_size=30,\n", + " base_column_size=92,\n", + " base_row_header_size=128,\n", + " base_column_header_size=40\n", + ")\n", + "grid" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2fd41d80", + "metadata": {}, + "outputs": [], + "source": [ + "grid.header_visibility = 'row'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "80ad0ce1", + "metadata": {}, + "outputs": [], + "source": [ + "grid.header_visibility = 'column'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d02d97dd", + "metadata": {}, + "outputs": [], + "source": [ + "grid.header_visibility = 'none'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aab73a5d", + "metadata": {}, + "outputs": [], + "source": [ + "grid.header_visibility = 'all'" + ] + }, + { + "cell_type": "markdown", + "id": "63a965c8", + "metadata": {}, + "source": [ + "#### Style your data grid with custom renderers based on Vega expressions\n", + "\n", + "- Custom cell renderers can be defined for the entire grid or column-wise.\n", + "\n", + "- Two types of cell renderers are currently available: `TextRenderer` and `BarRenderer`.\n", + "\n", + "- Most of the TextRenderer/BarRenderer attributes (`background_color`, `text_color` etc.) can either be a `value`, a `bqplot` scale or a `VegaExpr` or `Expr` instance.\n", + "\n", + "The `VegaExpr` class allows you to define an attribute value as a result of a Vega-expression (see https://vega.github.io/vega/docs/expressions/):\n", + "```python\n", + "background_color = VegaExpr(\"value < 150 ? 'red' : 'green'\").\n", + "```\n", + "You can look at the vega-expression documentation for more information about available constants and functions. In the scope of the expression are also available: value: cell value, x and y: cell position in pixel, width and height of the cell, row and column: cell position." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ccf880c4", + "metadata": {}, + "outputs": [], + "source": [ + "from bqplot import LinearScale, ColorScale, OrdinalColorScale, OrdinalScale\n", + "from py2vega.functions.color import rgb\n", + "\n", + "def horsepower_coloring(cell):\n", + " if cell.value < 100:\n", + " return \"red\"\n", + " elif cell.value < 150:\n", + " return \"orange\"\n", + " else:\n", + " return \"green\"\n", + "\n", + "\n", + "def weight_coloring(cell):\n", + " scaled_value = 1 if cell.value > 4500 else cell.value / 4500\n", + " color_value = scaled_value * 255\n", + "\n", + " return rgb(color_value, 0, 0)\n", + "\n", + "\n", + "renderers = {\n", + " \"Acceleration\": BarRenderer(\n", + " horizontal_alignment=\"center\",\n", + " bar_color=ColorScale(min=0, max=20, scheme=\"viridis\"),\n", + " bar_value=LinearScale(min=0, max=20),\n", + " ),\n", + " \"Cylinders\": TextRenderer(\n", + " background_color=Expr('\"grey\" if cell.row % 2 else default_value')\n", + " ),\n", + " \"Displacement\": TextRenderer(\n", + " text_color=ColorScale(min=97, max=455),\n", + " font=Expr(\n", + " \"'16px sans-serif' if cell.value > 400 else '12px sans-serif'\"\n", + " ),\n", + " ),\n", + " \"Horsepower\": TextRenderer(\n", + " text_color=\"black\", background_color=Expr(horsepower_coloring)\n", + " ),\n", + " \"Miles_per_Gallon\": TextRenderer(\n", + " background_color=Expr('\"grey\" if cell.value is None else default_value')\n", + " ),\n", + " \"Name\": TextRenderer(\n", + " background_color=Expr(\n", + " 'rgb(0, 100, 255) if \"chevrolet\" in cell.value or \"ford\" in cell.value else default_value'\n", + " )\n", + " ),\n", + " \"Origin\": TextRenderer(\n", + " text_color=\"black\",\n", + " background_color=OrdinalColorScale(domain=[\"USA\", \"Japan\", \"Europe\"]),\n", + " horizontal_alignment=Expr(\n", + " \"'right' if cell.value in ['USA', 'Japan'] else 'left'\"\n", + " ),\n", + " ),\n", + " \"Weight_in_lbs\": TextRenderer(\n", + " text_color=\"black\", background_color=Expr(weight_coloring)\n", + " ),\n", + " \"Year\": TextRenderer(text_color=\"black\", background_color=\"green\"),\n", + "}\n", + "\n", + "grid.renderers = renderers" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "526f0c77", + "metadata": {}, + "outputs": [], + "source": [ + "renderers[\"Name\"] \\\n", + " .background_color.value = '\"green\" if \"pontiac\" in cell.value or \"citroen\" in cell.value else default_value'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8bee2999", + "metadata": {}, + "outputs": [], + "source": [ + "renderers[\"Year\"].background_color = \"yellow\"" + ] + }, + { + "cell_type": "markdown", + "id": "688d5b2c", + "metadata": {}, + "source": [ + "#### Apply styling to column and row headers" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f8c4b3ed", + "metadata": {}, + "outputs": [], + "source": [ + "grid.header_renderer = TextRenderer(\n", + " background_color=Expr('\"salmon\" if cell.value == \"Horsepower\" else \"skyblue\"'),\n", + " font='italic small-caps bold 12px/30px Georgia, serif'\n", + ")\n", + "\n", + "renderers['index'] = TextRenderer(background_color='slateblue')\n", + "grid.renderers = renderers" + ] + }, + { + "cell_type": "markdown", + "id": "e22665ef", + "metadata": {}, + "source": [ + "#### Built-in sorting and filtering functionality which you can trigger from both Python and directly via the GUI." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6c96d8dc", + "metadata": {}, + "outputs": [], + "source": [ + "# Filtering based on car origin and sorting based on displacement\n", + "grid.transform(\n", + " [\n", + " {\n", + " \"type\": \"filter\",\n", + " \"operator\": \"=\",\n", + " \"columnIndex\": 2,\n", + " \"value\": \"Europe\",\n", + " },\n", + " {\"type\": \"sort\", \"columnIndex\": 9, \"desc\": True},\n", + " ]\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "cd574769", + "metadata": {}, + "source": [ + "#### Conditional formatting based on another cell" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e9e3b45a", + "metadata": {}, + "outputs": [], + "source": [ + "def format_based_on_other_column(cell):\n", + " return (\"green\" if cell.column == 2 and cell.metadata.data[\"Return\"] > 0 else \"red\")\n", + "\n", + "signal_column_formatting = TextRenderer(\n", + " text_color=\"white\",\n", + " background_color=Expr(format_based_on_other_column),\n", + ")\n", + "\n", + "renderers = {\n", + " \"Signal\": signal_column_formatting,\n", + " \"Return\": TextRenderer(background_color='seashell',\n", + " text_color=VegaExpr('cell.value > 0 ? \"green\" : \"firebrick\"')\n", + " ),\n", + " \"Stock\": TextRenderer(background_color='seashell')\n", + "}\n", + "\n", + "conditional_grid = DataGrid(\n", + " pd.DataFrame(\n", + " {\"Stock\": \"A B C D\".split(), \n", + " \"Return\": [0.11, -0.05, 0.08, -0.20], \n", + " \"Signal\": [\"Buy\", \"Sell\", \"Buy\", \"Sell\"]}\n", + " ),\n", + " column_widths={\"Stock\": 64, \"Return\": 64, \"Signal\": 300},\n", + " base_row_size=30,\n", + " renderers=renderers,\n", + " layout={\"height\": \"150px\"},\n", + ")\n", + "\n", + "conditional_grid" + ] + }, + { + "cell_type": "markdown", + "id": "9cb0121c", + "metadata": {}, + "source": [ + "#### Multi-index and nested columns DataFrames are also supported" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "761d5d7c", + "metadata": {}, + "outputs": [], + "source": [ + "nested_df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3e5a896c", + "metadata": {}, + "outputs": [], + "source": [ + "columns_renderer = TextRenderer(\n", + " background_color='honeydew',\n", + " horizontal_alignment='center')\n", + "\n", + "renderers= {\n", + " \"('Ticker', '')\": TextRenderer(background_color='honeydew')\n", + "}\n", + "\n", + "default_renderer = TextRenderer(\n", + " background_color=VegaExpr('cell.value > 0 ? \"azure\" : \"lavenderblush\"')\n", + ")\n", + "\n", + "nested_grid = DataGrid(nested_df,\n", + " base_column_size=90,\n", + " column_widths={\"('Ticker', '')\": 80},\n", + " layout={'height':'140px'},\n", + " renderers=renderers,\n", + " default_renderer=default_renderer,\n", + " header_renderer=columns_renderer)\n", + "\n", + "nested_grid" + ] + }, + { + "cell_type": "markdown", + "id": "80c520dd", + "metadata": {}, + "source": [ + "#### Two-way selections model at your disposal\n", + "\n", + "DataGrid cells can be selected using mouse by simply clicking and dragging over the cells. Pressing Cmd / Ctrl key during selection will add to existing selections. Pressing Shift key allows selection of regions between two clicks.\n", + "\n", + "DataGrid supports three modes of selection `cell`, `row`, `column`. In order to disable selections, selection mode can be set to `none` which is the default setting.\n", + "\n", + "Selection Modes:\n", + "\n", + "- `cell`: Clicking on grid will select only the cell under mouse cursor\n", + "- `row`: Clicking on grid will select all the cells on the row under mouse cursor\n", + "- `column`: Clicking on grid will select all the cells on the column under mouse cursor\n", + "\n", + "You can clear all selections by hitting the `esc` key." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "19daff23", + "metadata": {}, + "outputs": [], + "source": [ + "sel_grid = DataGrid(stock_df, selection_mode='cell')\n", + "sel_grid" + ] + }, + { + "cell_type": "markdown", + "id": "31bae137", + "metadata": {}, + "source": [ + "Select from the UI and retrieve on the Python side" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "24bb14f0", + "metadata": {}, + "outputs": [], + "source": [ + "sel_grid.selections" + ] + }, + { + "cell_type": "markdown", + "id": "f63bfcdd", + "metadata": {}, + "source": [ + "We can also access the selected cell values" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f34ebe8c", + "metadata": {}, + "outputs": [], + "source": [ + "sel_grid.selected_cell_values" + ] + }, + { + "cell_type": "markdown", + "id": "5b79e117", + "metadata": {}, + "source": [ + "Select from the Python side and see selections highlighted on the UI.\n", + "\n", + "Parameters:\n", + "\n", + "- `row1`: start row (starts from 0).\n", + "- `row2`: end row (starts from 0).\n", + "- `column1`: start column.\n", + "- `column2`: end column.\n", + "\n", + "We can automatically clear any existing selections by passing a value for `clear_mode`:\n", + "\n", + "- `current`: clear last selection\n", + "- `all`: clear all existing selections\n", + "- `none`: do not clear selections (default)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cb14e58b", + "metadata": {}, + "outputs": [], + "source": [ + "# Select top left corner of grid\n", + "sel_grid.select(row1=0, column1=0, row2=1, column2=1, clear_mode='current')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "324850f9", + "metadata": {}, + "outputs": [], + "source": [ + "# Clear selection\n", + "sel_grid.clear_selection()" + ] + }, + { + "cell_type": "markdown", + "id": "1da0f04a", + "metadata": {}, + "source": [ + "We can select individual sells by omitting `row2` and `column2`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6852e273", + "metadata": {}, + "outputs": [], + "source": [ + "sel_grid.select(10, 5)" + ] + }, + { + "cell_type": "markdown", + "id": "702dc047", + "metadata": {}, + "source": [ + "When working with large grids, we can opt to use the `selected_cell_iterator`. It will yield values for each loop iteration, avoiding the need to store all selections in a list, in advance." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fe0634e8", + "metadata": {}, + "outputs": [], + "source": [ + "for cell in sel_grid.selected_cell_iterator:\n", + " print(f'Cell value: {cell}')" + ] + }, + { + "cell_type": "markdown", + "id": "1f299815", + "metadata": {}, + "source": [ + "We can modify selections in place by passing a list of selections" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "88bccc93", + "metadata": {}, + "outputs": [], + "source": [ + "sel_grid.selections = [\n", + " {\"r1\": 22, \"r2\": 20, \"c1\": 0, \"c2\": 2},\n", + " {\"r1\": 6, \"r2\": 6, \"c1\": 2, \"c2\": 2},\n", + " {\"r1\": 10, \"r2\": 10, \"c1\": 3, \"c2\": 3},\n", + " {\"r1\": 13, \"r2\": 13, \"c1\": 2, \"c2\": 2},\n", + "]" + ] + }, + { + "cell_type": "markdown", + "id": "e8d948c4", + "metadata": {}, + "source": [ + "Row selection mode" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b653da0e", + "metadata": {}, + "outputs": [], + "source": [ + "sel_grid.selection_mode='row'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "71cdf563", + "metadata": {}, + "outputs": [], + "source": [ + "for i in range(260):\n", + " sel_grid.select(i, i) if i % 2 == 0 else None" + ] + }, + { + "cell_type": "markdown", + "id": "85045e17", + "metadata": {}, + "source": [ + "#### Two-way cell editing is possible\n", + "\n", + "Just pass `editable=True` to the grid's constructorand you're good to go (grids are not editable by default)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e118e5d5", + "metadata": {}, + "outputs": [], + "source": [ + "small_grid = DataGrid(small_df, \n", + " editable=True, \n", + " default_renderer=TextRenderer(\n", + " background_color=VegaExpr(\"cell.value === 1 ? 'limegreen' : 'moccasin'\")\n", + " ),\n", + " layout={'height': '250px'})\n", + "small_grid" + ] + }, + { + "cell_type": "markdown", + "id": "5e0ccd9a", + "metadata": {}, + "source": [ + "You can change values directly in the UI by double clicking a cell and changing the value. You can navigate the grid using the keyboard. You can use the arrow keys or the grid's __cursor__:\n", + "\n", + "- __Down__: Enter\n", + "- __Up__: Shift + Enter\n", + "- __Right__: Tab\n", + "- __Left__: Shift + Tab" + ] + }, + { + "cell_type": "markdown", + "id": "806468bd", + "metadata": {}, + "source": [ + "..or you can change it directly from the Python side" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f0ac1126", + "metadata": {}, + "outputs": [], + "source": [ + "# Returns a boolean to indicate whether operations was successful\n", + "small_grid.set_cell_value('Col 0', 'Row 9', 1) # Sets value based on row name" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "af84ae1e", + "metadata": {}, + "outputs": [], + "source": [ + "small_grid.set_cell_value_by_index('Col 9', 0, 1) # Sets value based on row index" + ] + }, + { + "cell_type": "markdown", + "id": "9cb298fb", + "metadata": {}, + "source": [ + "#### Events and integration with `ipywidgets`" + ] + }, + { + "cell_type": "markdown", + "id": "2b00cab5", + "metadata": {}, + "source": [ + "Listen to cell change events" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b214bb25", + "metadata": {}, + "outputs": [], + "source": [ + "def cell_changed(e):\n", + " row, column, col_index, value = e['row'], e['column'], e['column_index'], e['value']\n", + " print(f'The cell at row {row}, column \"{column}\" (index {col_index}), changed to {value}')\n", + " \n", + "small_grid.on_cell_change(cell_changed)\n", + "small_grid" + ] + }, + { + "cell_type": "markdown", + "id": "8c454fb8", + "metadata": {}, + "source": [ + "#### An example with the BarRenderer" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d3dcd28e", + "metadata": {}, + "outputs": [], + "source": [ + "from bqplot import LinearScale, ColorScale\n", + "from ipydatagrid import DataGrid, BarRenderer\n", + "\n", + "linear_scale = LinearScale(min=0, max=1)\n", + "color_scale = ColorScale(min=0, max=1)\n", + "bar_renderer = BarRenderer(\n", + " bar_color=color_scale,\n", + " bar_value=linear_scale,\n", + " bar_horizontal_alignment=\"center\",\n", + ")\n", + "\n", + "\n", + "rand_grid = DataGrid(rand_df, default_renderer=bar_renderer, base_column_size=76)\n", + "rand_grid" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8296850a", + "metadata": {}, + "outputs": [], + "source": [ + "bar_renderer.show_text = False" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c920c322", + "metadata": {}, + "outputs": [], + "source": [ + "from ipywidgets import FloatSlider, link\n", + "\n", + "slider = FloatSlider(\n", + " description=\"Scale: \", value=linear_scale.max, min=0, max=0.99, step=0.01\n", + ")\n", + "link((color_scale, \"min\"), (slider, \"value\"))\n", + "link((linear_scale, \"min\"), (slider, \"value\"))\n", + "\n", + "slider" + ] + }, + { + "cell_type": "markdown", + "id": "b78005c8", + "metadata": {}, + "source": [ + "#### Integration with `bqplot`\n", + "\n", + "We have a DataGrid with time series of 10 different stock prices. Each time we click on a stock price column, we want to plot the time series of that stock price in a line chart." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e3ecc75d", + "metadata": {}, + "outputs": [], + "source": [ + "stock_df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dee03573", + "metadata": {}, + "outputs": [], + "source": [ + "from bqplot import LinearScale, Axis, Figure, Lines, CATEGORY10\n", + "from ipywidgets import HBox, Layout\n", + "\n", + "def plot_stock(e):\n", + " line.y = stock_grid.selected_cell_values\n", + " line.x = range(len(line.y))\n", + " line.labels = [e['column']]\n", + " line.colors = [CATEGORY10[np.random.randint(0, len(CATEGORY10)) % len(CATEGORY10)]]\n", + " \n", + "stock_grid = DataGrid(stock_df, selection_mode='column')\n", + "\n", + "# Event listener for cell click\n", + "stock_grid.on_cell_click(plot_stock)" + ] + }, + { + "cell_type": "markdown", + "id": "65ae20ea", + "metadata": {}, + "source": [ + "Setting up bqplot and ipywidgets objects" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6163f8dd", + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "# Creating the bqplot chart objects\n", + "sc_x = LinearScale()\n", + "sc_y = LinearScale()\n", + "line = Lines(x=[], y=[], labels=['Fake stock price'], display_legend=True,\n", + " scales={'x': sc_x, 'y': sc_y})\n", + "ax_x = Axis(scale=sc_x, label='Index')\n", + "ax_y = Axis(scale=sc_y, orientation='vertical', label='y-value')\n", + "fig = Figure(marks=[line], axes=[ax_x, ax_y], title='Line Chart', layout=Layout(flex='1 1 auto', width='100%'))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1413d459", + "metadata": {}, + "outputs": [], + "source": [ + "HBox(\n", + " [stock_grid, fig]\n", + ")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/07.05-other-widget-libraries.ipynb b/notebooks/07.05-other-widget-libraries.ipynb new file mode 100644 index 00000000..832e9a65 --- /dev/null +++ b/notebooks/07.05-other-widget-libraries.ipynb @@ -0,0 +1,33 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "7e3a1d9e-3a48-41ff-a2b7-2dbcdb82c520", + "metadata": {}, + "source": [ + "# To be added" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/07.01-ipyleaflet.ipynb b/notebooks/widgets_libraries/07.01-ipyleaflet.ipynb similarity index 100% rename from notebooks/07.01-ipyleaflet.ipynb rename to notebooks/widgets_libraries/07.01-ipyleaflet.ipynb diff --git a/notebooks/07.02-pythreejs.ipynb b/notebooks/widgets_libraries/07.02-pythreejs.ipynb similarity index 100% rename from notebooks/07.02-pythreejs.ipynb rename to notebooks/widgets_libraries/07.02-pythreejs.ipynb diff --git a/notebooks/07.03-bqplot.ipynb b/notebooks/widgets_libraries/07.03-bqplot.ipynb similarity index 99% rename from notebooks/07.03-bqplot.ipynb rename to notebooks/widgets_libraries/07.03-bqplot.ipynb index f17816a9..c33a2018 100644 --- a/notebooks/07.03-bqplot.ipynb +++ b/notebooks/widgets_libraries/07.03-bqplot.ipynb @@ -435,9 +435,9 @@ ], "metadata": { "kernelspec": { - "display_name": "widgets-tutorial", + "display_name": "Python 3", "language": "python", - "name": "widgets-tutorial" + "name": "python3" }, "language_info": { "codemirror_mode": { @@ -449,7 +449,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.3" + "version": "3.8.10" }, "widgets": { "state": { diff --git a/notebooks/07.04-ipyvolume.ipynb b/notebooks/widgets_libraries/07.xx-ipyvolume.ipynb similarity index 100% rename from notebooks/07.04-ipyvolume.ipynb rename to notebooks/widgets_libraries/07.xx-ipyvolume.ipynb From 63eb513250c1fb1c963ea34afc53cadc37c83cc7 Mon Sep 17 00:00:00 2001 From: Itay Dafna Date: Thu, 1 Jul 2021 22:59:46 -0700 Subject: [PATCH 2/8] Change kernelspecs, rename other-widgets notebook Signed-off-by: Itay Dafna --- notebooks/07.00-More_widget_libraries.ipynb | 4 ++-- notebooks/07.03-ipydatagrid.ipynb | 4 ++-- ...get-libraries.ipynb => 07.09-other-widget-libraries.ipynb} | 4 ++-- notebooks/widgets_libraries/07.01-ipyleaflet.ipynb | 2 +- notebooks/widgets_libraries/07.02-pythreejs.ipynb | 2 +- notebooks/widgets_libraries/07.03-bqplot.ipynb | 4 ++-- notebooks/widgets_libraries/07.xx-ipyvolume.ipynb | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) rename notebooks/{07.05-other-widget-libraries.ipynb => 07.09-other-widget-libraries.ipynb} (88%) diff --git a/notebooks/07.00-More_widget_libraries.ipynb b/notebooks/07.00-More_widget_libraries.ipynb index a61ae1a3..33e68cc4 100644 --- a/notebooks/07.00-More_widget_libraries.ipynb +++ b/notebooks/07.00-More_widget_libraries.ipynb @@ -52,9 +52,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "widgets-tutorial", "language": "python", - "name": "python3" + "name": "widgets-tutorial" }, "language_info": { "codemirror_mode": { diff --git a/notebooks/07.03-ipydatagrid.ipynb b/notebooks/07.03-ipydatagrid.ipynb index 1dea7501..f9777422 100644 --- a/notebooks/07.03-ipydatagrid.ipynb +++ b/notebooks/07.03-ipydatagrid.ipynb @@ -878,9 +878,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "widgets-tutorial", "language": "python", - "name": "python3" + "name": "widgets-tutorial" }, "language_info": { "codemirror_mode": { diff --git a/notebooks/07.05-other-widget-libraries.ipynb b/notebooks/07.09-other-widget-libraries.ipynb similarity index 88% rename from notebooks/07.05-other-widget-libraries.ipynb rename to notebooks/07.09-other-widget-libraries.ipynb index 832e9a65..b0d1fa4a 100644 --- a/notebooks/07.05-other-widget-libraries.ipynb +++ b/notebooks/07.09-other-widget-libraries.ipynb @@ -11,9 +11,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "widgets-tutorial", "language": "python", - "name": "python3" + "name": "widgets-tutorial" }, "language_info": { "codemirror_mode": { diff --git a/notebooks/widgets_libraries/07.01-ipyleaflet.ipynb b/notebooks/widgets_libraries/07.01-ipyleaflet.ipynb index 887382b7..35ac5e96 100644 --- a/notebooks/widgets_libraries/07.01-ipyleaflet.ipynb +++ b/notebooks/widgets_libraries/07.01-ipyleaflet.ipynb @@ -649,7 +649,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.3" + "version": "3.8.10" } }, "nbformat": 4, diff --git a/notebooks/widgets_libraries/07.02-pythreejs.ipynb b/notebooks/widgets_libraries/07.02-pythreejs.ipynb index 5fbcaa55..5e961d71 100644 --- a/notebooks/widgets_libraries/07.02-pythreejs.ipynb +++ b/notebooks/widgets_libraries/07.02-pythreejs.ipynb @@ -276,7 +276,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.3" + "version": "3.8.10" }, "widgets": { "state": { diff --git a/notebooks/widgets_libraries/07.03-bqplot.ipynb b/notebooks/widgets_libraries/07.03-bqplot.ipynb index c33a2018..86f844e8 100644 --- a/notebooks/widgets_libraries/07.03-bqplot.ipynb +++ b/notebooks/widgets_libraries/07.03-bqplot.ipynb @@ -435,9 +435,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "widgets-tutorial", "language": "python", - "name": "python3" + "name": "widgets-tutorial" }, "language_info": { "codemirror_mode": { diff --git a/notebooks/widgets_libraries/07.xx-ipyvolume.ipynb b/notebooks/widgets_libraries/07.xx-ipyvolume.ipynb index 53d3e9ef..c3f5e8a6 100644 --- a/notebooks/widgets_libraries/07.xx-ipyvolume.ipynb +++ b/notebooks/widgets_libraries/07.xx-ipyvolume.ipynb @@ -224,7 +224,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.3" + "version": "3.8.10" } }, "nbformat": 4, From ccee49c42f911fbf7929e4c402e11198380ce090 Mon Sep 17 00:00:00 2001 From: Itay Dafna Date: Fri, 2 Jul 2021 00:07:12 -0700 Subject: [PATCH 3/8] Update other widget libraries notebook Signed-off-by: Itay Dafna --- notebooks/07.09-other-widget-libraries.ipynb | 427 ++++++++++++++++++- 1 file changed, 426 insertions(+), 1 deletion(-) diff --git a/notebooks/07.09-other-widget-libraries.ipynb b/notebooks/07.09-other-widget-libraries.ipynb index b0d1fa4a..d0ea6a8c 100644 --- a/notebooks/07.09-other-widget-libraries.ipynb +++ b/notebooks/07.09-other-widget-libraries.ipynb @@ -5,7 +5,432 @@ "id": "7e3a1d9e-3a48-41ff-a2b7-2dbcdb82c520", "metadata": {}, "source": [ - "# To be added" + "# Other widget libraries\n", + "\n", + "We would have loved to show you everything the Jupyter Widgets ecosystem has to offer today, but we are blessed to have such an active community of widget creators and unfortunately can't fit all widgets in a single session, no matter how long. \n", + "\n", + "This notebook lists some of the widget libraries we wanted to demo but did not have enough time to include in the session. Enjoy!" + ] + }, + { + "cell_type": "markdown", + "id": "6bbc79d5-86b4-4b2b-b924-e458375e090a", + "metadata": {}, + "source": [ + "# ipyleaflet: Interactive maps\n", + "\n", + "## A Jupyter - LeafletJS bridge\n", + "\n", + "## https://github.com/jupyter-widgets/ipyleaflet\n", + "\n", + "\n", + "ipyleaflet is a jupyter interactive widget library which provides interactive maps to the Jupyter notebook.\n", + "\n", + "- MIT Licensed\n", + "\n", + "**Installation:**\n", + "\n", + "```bash\n", + "conda install -c conda-forge ipyleaflet\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c77c85c9-6d99-475c-a9a2-e2c190ba4122", + "metadata": {}, + "outputs": [], + "source": [ + "from ipywidgets import Text, HTML, HBox\n", + "from ipyleaflet import GeoJSON, WidgetControl, Map \n", + "import json" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "54c3506c-2ac0-4319-bfcc-e017f0885295", + "metadata": {}, + "outputs": [], + "source": [ + "m = Map(center = (43,-100), zoom = 4)\n", + "\n", + "geo_json_data = json.load(open('us-states-density-colored.json'))\n", + "geojson = GeoJSON(data=geo_json_data, hover_style={'color': 'black', 'dashArray': '5, 5', 'weight': 2})\n", + "m.add_layer(geojson)\n", + "\n", + "html = HTML('''\n", + "

US population density

\n", + " Hover over a state\n", + "''')\n", + "html.layout.margin = '0px 20px 20px 20px'\n", + "control = WidgetControl(widget=html, position='topright')\n", + "m.add_control(control)\n", + "\n", + "def update_html(properties, **kwargs):\n", + " html.value = '''\n", + "

US population density

\n", + "

{}

\n", + " {} people / mi^2\n", + " '''.format(properties['name'], properties['density'])\n", + "\n", + "geojson.on_hover(update_html)\n", + "\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "9bfcd179-0463-4b07-9bce-f7ba298ed3de", + "metadata": {}, + "source": [ + "# pythreejs: 3D rendering in the browser \n", + "\n", + "## A Jupyter - threejs bridge\n", + "\n", + "## https://github.com/jupyter-widgets/pythreejs\n", + "\n", + "\n", + "Pythreejs is a jupyter interactive widget bringing fast WebGL 3d visualization to the Jupyter notebook.\n", + "\n", + "- Originally authored by Jason Grout, currently maintained by Vidar Tonaas Fauske\n", + "- BSD Licensed\n", + "\n", + "Pythreejs is *not* a 3d plotting library, it only exposes the threejs scene objects to the Jupyter kernel.\n", + "\n", + "**Installation:**\n", + "\n", + "```bash\n", + "conda install -c conda-forge pythreejs\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "989097a4-302f-4092-a784-814282b5c366", + "metadata": {}, + "outputs": [], + "source": [ + "from pythreejs import *\n", + "import numpy as np\n", + "from IPython.display import display\n", + "from ipywidgets import HTML, Text, Output, VBox\n", + "from traitlets import link, dlink" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "07bb1212-d30f-4b22-a1e9-75ba63c449cc", + "metadata": {}, + "outputs": [], + "source": [ + "# Generate surface data:\n", + "view_width = 600\n", + "view_height = 400\n", + "nx, ny = (20, 20)\n", + "xmax=1\n", + "x = np.linspace(-xmax, xmax, nx)\n", + "y = np.linspace(-xmax, xmax, ny)\n", + "xx, yy = np.meshgrid(x, y)\n", + "z = xx ** 2 - yy ** 2\n", + "#z[6,1] = float('nan')\n", + "\n", + "\n", + "# Generate scene objects from data:\n", + "surf_g = SurfaceGeometry(z=list(z[::-1].flat), \n", + " width=2 * xmax,\n", + " height=2 * xmax,\n", + " width_segments=nx - 1,\n", + " height_segments=ny - 1)\n", + "\n", + "surf = Mesh(geometry=surf_g,\n", + " material=MeshLambertMaterial(map=height_texture(z[::-1], 'YlGnBu_r')))\n", + "\n", + "surfgrid = SurfaceGrid(geometry=surf_g, material=LineBasicMaterial(color='black'),\n", + " position=[0, 0, 1e-2]) # Avoid overlap by lifting grid slightly\n", + "\n", + "# Set up picking bojects:\n", + "hover_point = Mesh(geometry=SphereGeometry(radius=0.05),\n", + " material=MeshLambertMaterial(color='green'))\n", + "\n", + "click_picker = Picker(controlling=surf, event='dblclick')\n", + "hover_picker = Picker(controlling=surf, event='mousemove')\n", + "\n", + "# Set up scene:\n", + "key_light = DirectionalLight(color='white', position=[3, 5, 1], intensity=0.4)\n", + "c = PerspectiveCamera(position=[0, 3, 3], up=[0, 0, 1], aspect=view_width / view_height,\n", + " children=[key_light])\n", + "\n", + "scene = Scene(children=[surf, c, surfgrid, hover_point, AmbientLight(intensity=0.8)])\n", + "\n", + "renderer = Renderer(camera=c, scene=scene,\n", + " width=view_width, height=view_height,\n", + " controls=[OrbitControls(controlling=c), click_picker, hover_picker])\n", + "\n", + "\n", + "# Set up picking responses:\n", + "# Add a new marker when double-clicking:\n", + "out = Output()\n", + "def f(change):\n", + " value = change['new']\n", + " with out:\n", + " print('Clicked on %s' % (value,))\n", + " point = Mesh(geometry=SphereGeometry(radius=0.05), \n", + " material=MeshLambertMaterial(color='hotpink'),\n", + " position=value)\n", + " scene.add(point)\n", + "\n", + "click_picker.observe(f, names=['point'])\n", + "\n", + "# Have marker follow picker point:\n", + "link((hover_point, 'position'), (hover_picker, 'point'))\n", + "\n", + "# Show picker point coordinates as a label:\n", + "h = HTML()\n", + "def g(change):\n", + " h.value = 'Green point at (%.3f, %.3f, %.3f)' % tuple(change['new'])\n", + " h.value += ' Double-click to add marker'\n", + "g({'new': hover_point.position})\n", + "hover_picker.observe(g, names=['point'])\n", + "\n", + "display(VBox([h, renderer, out]))" + ] + }, + { + "cell_type": "markdown", + "id": "228aa568-3b3b-4901-9700-b6a865e474a1", + "metadata": {}, + "source": [ + "# bqplot: complex interactive visualizations\n", + "\n", + "## https://github.com/bloomberg/bqplot\n", + "\n", + "## A Jupyter - d3.js bridge\n", + "\n", + "bqplot is a jupyter interactive widget library bringing d3.js visualization to the Jupyter notebook.\n", + "\n", + "- Apache Licensed\n", + "\n", + "bqplot implements the abstractions of Wilkinson’s “The Grammar of Graphics” as interactive Jupyter widgets.\n", + "\n", + "bqplot provides both\n", + "-\thigh-level plotting procedures with relevant defaults for common chart types,\n", + "-\tlower-level descriptions of data visualizations meant for complex interactive visualization dashboards and applications involving mouse interactions and user-provided Python callbacks.\n", + "\n", + "**Installation:**\n", + "\n", + "```bash\n", + "conda install -c conda-forge bqplot\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e406ea84-67fe-4137-9b26-cf4cbdb4e751", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import bqplot as bq" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "625bd9df-8661-4267-aa34-3c758e04be21", + "metadata": {}, + "outputs": [], + "source": [ + "xs = bq.LinearScale()\n", + "ys = bq.LinearScale()\n", + "x = np.arange(100)\n", + "y = np.cumsum(np.random.randn(2, 100), axis=1) #two random walks\n", + "\n", + "line = bq.Lines(x=x, y=y, scales={'x': xs, 'y': ys}, colors=['red', 'green'])\n", + "xax = bq.Axis(scale=xs, label='x', grid_lines='solid')\n", + "yax = bq.Axis(scale=ys, orientation='vertical', tick_format='0.2f', label='y', grid_lines='solid')\n", + "\n", + "fig = bq.Figure(marks=[line], axes=[xax, yax], animation_duration=1000)\n", + "display(fig)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "94ac959d-76d1-4712-914c-bcb931d04e93", + "metadata": {}, + "outputs": [], + "source": [ + "# update data of the line mark\n", + "line.y = np.cumsum(np.random.randn(2, 100), axis=1)" + ] + }, + { + "cell_type": "markdown", + "id": "4ce97fcb-e621-4b0e-b826-d49c04146f51", + "metadata": {}, + "source": [ + "# ipympl: The Matplotlib Jupyter Widget Backend\n", + "\n", + "## https://github.com/matplotlib/ipympl\n", + "\n", + "\n", + "Enabling interaction with matplotlib charts in the Jupyter notebook and JupyterLab\n", + "\n", + "- BSD-3-Clause\n", + "\n", + "**Installation:**\n", + "\n", + "```bash\n", + "conda install -c conda-forge ipympl\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "91a33e30-803d-4945-8129-2c37f30a1d09", + "metadata": {}, + "source": [ + "Enabling the `widget` backend. This requires ipympl. ipympl can be install via pip or conda." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6b157ee7-4008-492d-8045-f93b747af703", + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib widget" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "152cba47-06f1-4896-b15a-b3ed960cafd3", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "from ipywidgets import VBox, FloatSlider" + ] + }, + { + "cell_type": "markdown", + "id": "fc9dca28-883c-4286-af3d-a17081b089d6", + "metadata": {}, + "source": [ + "When using the `widget` backend from ipympl, fig.canvas is a proper Jupyter interactive widget, which can be embedded in Layout classes like HBox and Vbox.\n", + "\n", + "One can bound figure attributes to other widget values." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9db5b3e0-317c-4b79-bb5c-36786d02895a", + "metadata": {}, + "outputs": [], + "source": [ + "plt.ioff()\n", + "plt.clf()\n", + "\n", + "slider = FloatSlider(\n", + " value=1.0,\n", + " min=0.02,\n", + " max=2.0\n", + ")\n", + "\n", + "fig1 = plt.figure(1)\n", + "\n", + "x1 = np.linspace(0, 20, 500)\n", + "\n", + "lines = plt.plot(x1, np.sin(slider.value * x1))\n", + "\n", + "def update_lines(change):\n", + " lines[0].set_data(x1, np.sin(change.new * x1))\n", + " fig1.canvas.draw()\n", + " fig1.canvas.flush_events()\n", + "\n", + "slider.observe(update_lines, names='value')\n", + "\n", + "VBox([slider, fig1.canvas])" + ] + }, + { + "cell_type": "markdown", + "id": "24389d91-db96-4591-a279-9dde81b9c8ef", + "metadata": {}, + "source": [ + "# ipytree: Interactive tree view based on ipywidgets\n", + "\n", + "## https://github.com/QuantStack/ipytree/\n", + "\n", + "\n", + "ipytree is a jupyter interactive widget library which provides a tree widget to the Jupyter notebook.\n", + "\n", + "- MIT Licensed\n", + "\n", + "**Installation:**\n", + "\n", + "```bash\n", + "conda install -c conda-forge ipytree\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "fa20469b-b9b6-46bc-99f0-e85c313db971", + "metadata": {}, + "source": [ + "## Create a tree" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c3b13d81-455d-438c-a843-f31421db0fc1", + "metadata": {}, + "outputs": [], + "source": [ + "from ipywidgets import Text, link\n", + "from ipytree import Tree, Node" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5461f21f-e96e-4877-8f4c-bc1bc5f572e2", + "metadata": {}, + "outputs": [], + "source": [ + "tree = Tree()\n", + "tree.add_node(Node('node1'))\n", + "\n", + "node2 = Node('node2')\n", + "tree.add_node(node2)\n", + "\n", + "tree" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6059b01a-8c08-492a-834b-450905e5c3dd", + "metadata": {}, + "outputs": [], + "source": [ + "node3 = Node('node3', disabled=True)\n", + "node4 = Node('node4')\n", + "node5 = Node('node5', [Node('1'), Node('2')])\n", + "node2.add_node(node3)\n", + "node2.add_node(node4)\n", + "node2.add_node(node5)" ] } ], From ebe064c2a1d4c552fe58dff014b7378640c45186 Mon Sep 17 00:00:00 2001 From: Itay Dafna Date: Wed, 7 Jul 2021 06:18:04 -0700 Subject: [PATCH 4/8] Update ipydatagrid notebook Signed-off-by: Itay Dafna --- notebooks/07.03-ipydatagrid.ipynb | 75 ++++++++++++++++++------------- 1 file changed, 43 insertions(+), 32 deletions(-) diff --git a/notebooks/07.03-ipydatagrid.ipynb b/notebooks/07.03-ipydatagrid.ipynb index f9777422..871beca8 100644 --- a/notebooks/07.03-ipydatagrid.ipynb +++ b/notebooks/07.03-ipydatagrid.ipynb @@ -371,8 +371,7 @@ " \"Signal\": signal_column_formatting,\n", " \"Return\": TextRenderer(background_color='seashell',\n", " text_color=VegaExpr('cell.value > 0 ? \"green\" : \"firebrick\"')\n", - " ),\n", - " \"Stock\": TextRenderer(background_color='seashell')\n", + " )\n", "}\n", "\n", "conditional_grid = DataGrid(\n", @@ -416,15 +415,15 @@ "outputs": [], "source": [ "columns_renderer = TextRenderer(\n", - " background_color='honeydew',\n", + " background_color='dimgray',\n", " horizontal_alignment='center')\n", "\n", "renderers= {\n", - " \"('Ticker', '')\": TextRenderer(background_color='honeydew')\n", + " \"('Ticker', '')\": TextRenderer(background_color='dimgray')\n", "}\n", "\n", "default_renderer = TextRenderer(\n", - " background_color=VegaExpr('cell.value > 0 ? \"azure\" : \"lavenderblush\"')\n", + " background_color=VegaExpr('cell.value > 0 ? \"steelblue\" : \"seagreen\"')\n", ")\n", "\n", "nested_grid = DataGrid(nested_df,\n", @@ -657,7 +656,7 @@ "small_grid = DataGrid(small_df, \n", " editable=True, \n", " default_renderer=TextRenderer(\n", - " background_color=VegaExpr(\"cell.value === 1 ? 'limegreen' : 'moccasin'\")\n", + " background_color=VegaExpr(\"cell.value === 1 ? 'limegreen' : 'hotpink'\")\n", " ),\n", " layout={'height': '250px'})\n", "small_grid" @@ -741,7 +740,9 @@ "id": "8c454fb8", "metadata": {}, "source": [ - "#### An example with the BarRenderer" + "#### An example with the BarRenderer\n", + "\n", + "Renders cell values as horizontal bars based on a scale. `ipydatagrid` has two renderers - `TextRenderer`, which is the default one we've seen, and `BarRenderer`, which we will use now." ] }, { @@ -795,6 +796,16 @@ "slider" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "6ab2857d-60be-46e2-8402-6f6b8edb7c33", + "metadata": {}, + "outputs": [], + "source": [ + "color_scale.min" + ] + }, { "cell_type": "markdown", "id": "b78005c8", @@ -824,25 +835,18 @@ "source": [ "from bqplot import LinearScale, Axis, Figure, Lines, CATEGORY10\n", "from ipywidgets import HBox, Layout\n", - "\n", - "def plot_stock(e):\n", - " line.y = stock_grid.selected_cell_values\n", - " line.x = range(len(line.y))\n", - " line.labels = [e['column']]\n", - " line.colors = [CATEGORY10[np.random.randint(0, len(CATEGORY10)) % len(CATEGORY10)]]\n", " \n", + "# Setting up the data grid\n", "stock_grid = DataGrid(stock_df, selection_mode='column')\n", "\n", - "# Event listener for cell click\n", - "stock_grid.on_cell_click(plot_stock)" - ] - }, - { - "cell_type": "markdown", - "id": "65ae20ea", - "metadata": {}, - "source": [ - "Setting up bqplot and ipywidgets objects" + "# Creating the bqplot chart objects\n", + "sc_x = LinearScale()\n", + "sc_y = LinearScale()\n", + "line = Lines(x=[], y=[], labels=['Fake stock price'], display_legend=True,\n", + " scales={'x': sc_x, 'y': sc_y})\n", + "ax_x = Axis(scale=sc_x, label='Index')\n", + "ax_y = Axis(scale=sc_y, orientation='vertical', label='y-value')\n", + "fig = Figure(marks=[line], axes=[ax_x, ax_y], title='Line Chart', layout=Layout(flex='1 1 auto', width='100%'))" ] }, { @@ -852,15 +856,14 @@ "metadata": {}, "outputs": [], "source": [ - "\n", - "# Creating the bqplot chart objects\n", - "sc_x = LinearScale()\n", - "sc_y = LinearScale()\n", - "line = Lines(x=[], y=[], labels=['Fake stock price'], display_legend=True,\n", - " scales={'x': sc_x, 'y': sc_y})\n", - "ax_x = Axis(scale=sc_x, label='Index')\n", - "ax_y = Axis(scale=sc_y, orientation='vertical', label='y-value')\n", - "fig = Figure(marks=[line], axes=[ax_x, ax_y], title='Line Chart', layout=Layout(flex='1 1 auto', width='100%'))" + "def plot_stock(e=None):\n", + " line.y = stock_grid.selected_cell_values\n", + " line.x = range(len(line.y))\n", + " line.labels = [e['column']]\n", + " line.colors = [CATEGORY10[np.random.randint(0, len(CATEGORY10)) % len(CATEGORY10)]]\n", + " \n", + "# Event listener for cell click\n", + "stock_grid.on_cell_click(plot_stock)" ] }, { @@ -874,6 +877,14 @@ " [stock_grid, fig]\n", ")" ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "100aec93-89b1-48d8-9077-0cc0d5fc48ac", + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { From 706d0d8ad7b6b154c10c609a5adecd3703000395 Mon Sep 17 00:00:00 2001 From: Itay Dafna Date: Sat, 26 Jun 2021 20:39:29 -0700 Subject: [PATCH 5/8] Add ipydatagrid/other-libraries notebooks, move old notebooks to widget_libraries folder Signed-off-by: Itay Dafna --- notebooks/07.02-pythreejs.ipynb | 1 + notebooks/07.03-bqplot.ipynb | 1 + notebooks/07.03-ipydatagrid.ipynb | 900 ++++++++++++++++++ notebooks/07.04-ipyvolume.ipynb | 1 + notebooks/07.05-other-widget-libraries.ipynb | 33 + .../07.00-More_widget_libraries.ipynb | 4 +- .../widgets_libraries/07.01-ipyleaflet.ipynb | 657 +++++++++++++ .../widgets_libraries/07.02-pythreejs.ipynb | 317 ++++++ .../widgets_libraries/07.03-bqplot.ipynb | 525 ++++++++++ .../widgets_libraries/07.xx-ipyvolume.ipynb | 232 +++++ 10 files changed, 2669 insertions(+), 2 deletions(-) create mode 100644 notebooks/07.02-pythreejs.ipynb create mode 100644 notebooks/07.03-bqplot.ipynb create mode 100644 notebooks/07.03-ipydatagrid.ipynb create mode 100644 notebooks/07.04-ipyvolume.ipynb create mode 100644 notebooks/07.05-other-widget-libraries.ipynb create mode 100644 notebooks/widgets_libraries/07.01-ipyleaflet.ipynb create mode 100644 notebooks/widgets_libraries/07.02-pythreejs.ipynb create mode 100644 notebooks/widgets_libraries/07.03-bqplot.ipynb create mode 100644 notebooks/widgets_libraries/07.xx-ipyvolume.ipynb diff --git a/notebooks/07.02-pythreejs.ipynb b/notebooks/07.02-pythreejs.ipynb new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/notebooks/07.02-pythreejs.ipynb @@ -0,0 +1 @@ + diff --git a/notebooks/07.03-bqplot.ipynb b/notebooks/07.03-bqplot.ipynb new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/notebooks/07.03-bqplot.ipynb @@ -0,0 +1 @@ + diff --git a/notebooks/07.03-ipydatagrid.ipynb b/notebooks/07.03-ipydatagrid.ipynb new file mode 100644 index 00000000..1dea7501 --- /dev/null +++ b/notebooks/07.03-ipydatagrid.ipynb @@ -0,0 +1,900 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "4d5ce026", + "metadata": {}, + "source": [ + "# `ipydatagrid`: fast, performant data grid\n", + "\n", + "## https://github.com/bloomberg/ipydatagrid\n", + "\n", + "### Full canvas rendering\n", + "\n", + "`ipydatagrid` is a complete data grid solution providing full integration with pandas DataFrames without compromising on performance:\n", + "\n", + "- built-in sorting and filtering\n", + "- full integration with the jupyter-widgets ecosystem\n", + "- highly customisable renderers\n", + "- complete two-way data binding between Python and the front-end\n", + "- supports Vega expressions for conditional formatting and styling\n", + "\n", + "**Installation**:\n", + "```bash\n", + "conda install -c conda-forge ipydatagrid\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "30f4cc0e", + "metadata": {}, + "outputs": [], + "source": [ + "from ipydatagrid import DataGrid, TextRenderer, BarRenderer, Expr, VegaExpr\n", + "import pandas as pd\n", + "import numpy as np\n", + "import requests" + ] + }, + { + "cell_type": "markdown", + "id": "7b847f68", + "metadata": {}, + "source": [ + "#### Use any dataset" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b382fc75", + "metadata": {}, + "outputs": [], + "source": [ + "# Numpy/pandas\n", + "np.random.seed(0)\n", + "p_t, n = 100, 260\n", + "stock_df = pd.DataFrame(\n", + " {f'Stock {i}': p_t + np.round(np.random.standard_normal(n).cumsum(), 2) for i in range(10)}\n", + ")\n", + "\n", + "# Requests/JSON\n", + "req = requests.get(\"https://raw.githubusercontent.com/bloomberg/ipydatagrid/main/examples/cars.json\")\n", + "data = req.json()\n", + "cars_data = data['data']\n", + "\n", + "\n", + "# Random matrix\n", + "rand_df = pd.DataFrame(\n", + " {f'Column {col}': np.round(np.random.random(100), 2) for col in [chr(n) for n in range(65, 91)]}\n", + ")\n", + "\n", + "# Small grid\n", + "small_df = pd.DataFrame(\n", + " np.eye(10),\n", + " columns=[f'Col {i}' for i in range(10)],\n", + " index=[f'Row {i}' for i in range(10)]\n", + ")\n", + "\n", + "# Multi-index\n", + "top_level = ['Value Factors', 'Value Factors', 'Momentum Factors', 'Momentum Factors']\n", + "bottom_level = ['Factor A', 'Factor B', 'Factor C', 'Factor D']\n", + "\n", + "nested_df = pd.DataFrame(np.random.randn(4,4).round(2),\n", + " columns=pd.MultiIndex.from_arrays([top_level, bottom_level]),\n", + " index=pd.Index(['Security {}'.format(x) for x in ['A', 'B', 'C', 'D']], name='Ticker'))" + ] + }, + { + "cell_type": "markdown", + "id": "ab90aa2c", + "metadata": {}, + "source": [ + "#### Convert your pandas DataFrame to a datagrid - it 'just works'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "94b69044", + "metadata": {}, + "outputs": [], + "source": [ + "df = pd.DataFrame(cars_data).set_index('index')\n", + "df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c2ae788a", + "metadata": {}, + "outputs": [], + "source": [ + "grid = DataGrid(df)\n", + "grid" + ] + }, + { + "cell_type": "markdown", + "id": "691cac62", + "metadata": {}, + "source": [ + "Additional constructor options" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8b18b862", + "metadata": {}, + "outputs": [], + "source": [ + "grid = DataGrid(\n", + " dataframe=df,\n", + " base_row_size=30,\n", + " base_column_size=92,\n", + " base_row_header_size=128,\n", + " base_column_header_size=40\n", + ")\n", + "grid" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2fd41d80", + "metadata": {}, + "outputs": [], + "source": [ + "grid.header_visibility = 'row'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "80ad0ce1", + "metadata": {}, + "outputs": [], + "source": [ + "grid.header_visibility = 'column'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d02d97dd", + "metadata": {}, + "outputs": [], + "source": [ + "grid.header_visibility = 'none'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aab73a5d", + "metadata": {}, + "outputs": [], + "source": [ + "grid.header_visibility = 'all'" + ] + }, + { + "cell_type": "markdown", + "id": "63a965c8", + "metadata": {}, + "source": [ + "#### Style your data grid with custom renderers based on Vega expressions\n", + "\n", + "- Custom cell renderers can be defined for the entire grid or column-wise.\n", + "\n", + "- Two types of cell renderers are currently available: `TextRenderer` and `BarRenderer`.\n", + "\n", + "- Most of the TextRenderer/BarRenderer attributes (`background_color`, `text_color` etc.) can either be a `value`, a `bqplot` scale or a `VegaExpr` or `Expr` instance.\n", + "\n", + "The `VegaExpr` class allows you to define an attribute value as a result of a Vega-expression (see https://vega.github.io/vega/docs/expressions/):\n", + "```python\n", + "background_color = VegaExpr(\"value < 150 ? 'red' : 'green'\").\n", + "```\n", + "You can look at the vega-expression documentation for more information about available constants and functions. In the scope of the expression are also available: value: cell value, x and y: cell position in pixel, width and height of the cell, row and column: cell position." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ccf880c4", + "metadata": {}, + "outputs": [], + "source": [ + "from bqplot import LinearScale, ColorScale, OrdinalColorScale, OrdinalScale\n", + "from py2vega.functions.color import rgb\n", + "\n", + "def horsepower_coloring(cell):\n", + " if cell.value < 100:\n", + " return \"red\"\n", + " elif cell.value < 150:\n", + " return \"orange\"\n", + " else:\n", + " return \"green\"\n", + "\n", + "\n", + "def weight_coloring(cell):\n", + " scaled_value = 1 if cell.value > 4500 else cell.value / 4500\n", + " color_value = scaled_value * 255\n", + "\n", + " return rgb(color_value, 0, 0)\n", + "\n", + "\n", + "renderers = {\n", + " \"Acceleration\": BarRenderer(\n", + " horizontal_alignment=\"center\",\n", + " bar_color=ColorScale(min=0, max=20, scheme=\"viridis\"),\n", + " bar_value=LinearScale(min=0, max=20),\n", + " ),\n", + " \"Cylinders\": TextRenderer(\n", + " background_color=Expr('\"grey\" if cell.row % 2 else default_value')\n", + " ),\n", + " \"Displacement\": TextRenderer(\n", + " text_color=ColorScale(min=97, max=455),\n", + " font=Expr(\n", + " \"'16px sans-serif' if cell.value > 400 else '12px sans-serif'\"\n", + " ),\n", + " ),\n", + " \"Horsepower\": TextRenderer(\n", + " text_color=\"black\", background_color=Expr(horsepower_coloring)\n", + " ),\n", + " \"Miles_per_Gallon\": TextRenderer(\n", + " background_color=Expr('\"grey\" if cell.value is None else default_value')\n", + " ),\n", + " \"Name\": TextRenderer(\n", + " background_color=Expr(\n", + " 'rgb(0, 100, 255) if \"chevrolet\" in cell.value or \"ford\" in cell.value else default_value'\n", + " )\n", + " ),\n", + " \"Origin\": TextRenderer(\n", + " text_color=\"black\",\n", + " background_color=OrdinalColorScale(domain=[\"USA\", \"Japan\", \"Europe\"]),\n", + " horizontal_alignment=Expr(\n", + " \"'right' if cell.value in ['USA', 'Japan'] else 'left'\"\n", + " ),\n", + " ),\n", + " \"Weight_in_lbs\": TextRenderer(\n", + " text_color=\"black\", background_color=Expr(weight_coloring)\n", + " ),\n", + " \"Year\": TextRenderer(text_color=\"black\", background_color=\"green\"),\n", + "}\n", + "\n", + "grid.renderers = renderers" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "526f0c77", + "metadata": {}, + "outputs": [], + "source": [ + "renderers[\"Name\"] \\\n", + " .background_color.value = '\"green\" if \"pontiac\" in cell.value or \"citroen\" in cell.value else default_value'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8bee2999", + "metadata": {}, + "outputs": [], + "source": [ + "renderers[\"Year\"].background_color = \"yellow\"" + ] + }, + { + "cell_type": "markdown", + "id": "688d5b2c", + "metadata": {}, + "source": [ + "#### Apply styling to column and row headers" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f8c4b3ed", + "metadata": {}, + "outputs": [], + "source": [ + "grid.header_renderer = TextRenderer(\n", + " background_color=Expr('\"salmon\" if cell.value == \"Horsepower\" else \"skyblue\"'),\n", + " font='italic small-caps bold 12px/30px Georgia, serif'\n", + ")\n", + "\n", + "renderers['index'] = TextRenderer(background_color='slateblue')\n", + "grid.renderers = renderers" + ] + }, + { + "cell_type": "markdown", + "id": "e22665ef", + "metadata": {}, + "source": [ + "#### Built-in sorting and filtering functionality which you can trigger from both Python and directly via the GUI." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6c96d8dc", + "metadata": {}, + "outputs": [], + "source": [ + "# Filtering based on car origin and sorting based on displacement\n", + "grid.transform(\n", + " [\n", + " {\n", + " \"type\": \"filter\",\n", + " \"operator\": \"=\",\n", + " \"columnIndex\": 2,\n", + " \"value\": \"Europe\",\n", + " },\n", + " {\"type\": \"sort\", \"columnIndex\": 9, \"desc\": True},\n", + " ]\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "cd574769", + "metadata": {}, + "source": [ + "#### Conditional formatting based on another cell" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e9e3b45a", + "metadata": {}, + "outputs": [], + "source": [ + "def format_based_on_other_column(cell):\n", + " return (\"green\" if cell.column == 2 and cell.metadata.data[\"Return\"] > 0 else \"red\")\n", + "\n", + "signal_column_formatting = TextRenderer(\n", + " text_color=\"white\",\n", + " background_color=Expr(format_based_on_other_column),\n", + ")\n", + "\n", + "renderers = {\n", + " \"Signal\": signal_column_formatting,\n", + " \"Return\": TextRenderer(background_color='seashell',\n", + " text_color=VegaExpr('cell.value > 0 ? \"green\" : \"firebrick\"')\n", + " ),\n", + " \"Stock\": TextRenderer(background_color='seashell')\n", + "}\n", + "\n", + "conditional_grid = DataGrid(\n", + " pd.DataFrame(\n", + " {\"Stock\": \"A B C D\".split(), \n", + " \"Return\": [0.11, -0.05, 0.08, -0.20], \n", + " \"Signal\": [\"Buy\", \"Sell\", \"Buy\", \"Sell\"]}\n", + " ),\n", + " column_widths={\"Stock\": 64, \"Return\": 64, \"Signal\": 300},\n", + " base_row_size=30,\n", + " renderers=renderers,\n", + " layout={\"height\": \"150px\"},\n", + ")\n", + "\n", + "conditional_grid" + ] + }, + { + "cell_type": "markdown", + "id": "9cb0121c", + "metadata": {}, + "source": [ + "#### Multi-index and nested columns DataFrames are also supported" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "761d5d7c", + "metadata": {}, + "outputs": [], + "source": [ + "nested_df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3e5a896c", + "metadata": {}, + "outputs": [], + "source": [ + "columns_renderer = TextRenderer(\n", + " background_color='honeydew',\n", + " horizontal_alignment='center')\n", + "\n", + "renderers= {\n", + " \"('Ticker', '')\": TextRenderer(background_color='honeydew')\n", + "}\n", + "\n", + "default_renderer = TextRenderer(\n", + " background_color=VegaExpr('cell.value > 0 ? \"azure\" : \"lavenderblush\"')\n", + ")\n", + "\n", + "nested_grid = DataGrid(nested_df,\n", + " base_column_size=90,\n", + " column_widths={\"('Ticker', '')\": 80},\n", + " layout={'height':'140px'},\n", + " renderers=renderers,\n", + " default_renderer=default_renderer,\n", + " header_renderer=columns_renderer)\n", + "\n", + "nested_grid" + ] + }, + { + "cell_type": "markdown", + "id": "80c520dd", + "metadata": {}, + "source": [ + "#### Two-way selections model at your disposal\n", + "\n", + "DataGrid cells can be selected using mouse by simply clicking and dragging over the cells. Pressing Cmd / Ctrl key during selection will add to existing selections. Pressing Shift key allows selection of regions between two clicks.\n", + "\n", + "DataGrid supports three modes of selection `cell`, `row`, `column`. In order to disable selections, selection mode can be set to `none` which is the default setting.\n", + "\n", + "Selection Modes:\n", + "\n", + "- `cell`: Clicking on grid will select only the cell under mouse cursor\n", + "- `row`: Clicking on grid will select all the cells on the row under mouse cursor\n", + "- `column`: Clicking on grid will select all the cells on the column under mouse cursor\n", + "\n", + "You can clear all selections by hitting the `esc` key." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "19daff23", + "metadata": {}, + "outputs": [], + "source": [ + "sel_grid = DataGrid(stock_df, selection_mode='cell')\n", + "sel_grid" + ] + }, + { + "cell_type": "markdown", + "id": "31bae137", + "metadata": {}, + "source": [ + "Select from the UI and retrieve on the Python side" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "24bb14f0", + "metadata": {}, + "outputs": [], + "source": [ + "sel_grid.selections" + ] + }, + { + "cell_type": "markdown", + "id": "f63bfcdd", + "metadata": {}, + "source": [ + "We can also access the selected cell values" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f34ebe8c", + "metadata": {}, + "outputs": [], + "source": [ + "sel_grid.selected_cell_values" + ] + }, + { + "cell_type": "markdown", + "id": "5b79e117", + "metadata": {}, + "source": [ + "Select from the Python side and see selections highlighted on the UI.\n", + "\n", + "Parameters:\n", + "\n", + "- `row1`: start row (starts from 0).\n", + "- `row2`: end row (starts from 0).\n", + "- `column1`: start column.\n", + "- `column2`: end column.\n", + "\n", + "We can automatically clear any existing selections by passing a value for `clear_mode`:\n", + "\n", + "- `current`: clear last selection\n", + "- `all`: clear all existing selections\n", + "- `none`: do not clear selections (default)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cb14e58b", + "metadata": {}, + "outputs": [], + "source": [ + "# Select top left corner of grid\n", + "sel_grid.select(row1=0, column1=0, row2=1, column2=1, clear_mode='current')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "324850f9", + "metadata": {}, + "outputs": [], + "source": [ + "# Clear selection\n", + "sel_grid.clear_selection()" + ] + }, + { + "cell_type": "markdown", + "id": "1da0f04a", + "metadata": {}, + "source": [ + "We can select individual sells by omitting `row2` and `column2`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6852e273", + "metadata": {}, + "outputs": [], + "source": [ + "sel_grid.select(10, 5)" + ] + }, + { + "cell_type": "markdown", + "id": "702dc047", + "metadata": {}, + "source": [ + "When working with large grids, we can opt to use the `selected_cell_iterator`. It will yield values for each loop iteration, avoiding the need to store all selections in a list, in advance." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fe0634e8", + "metadata": {}, + "outputs": [], + "source": [ + "for cell in sel_grid.selected_cell_iterator:\n", + " print(f'Cell value: {cell}')" + ] + }, + { + "cell_type": "markdown", + "id": "1f299815", + "metadata": {}, + "source": [ + "We can modify selections in place by passing a list of selections" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "88bccc93", + "metadata": {}, + "outputs": [], + "source": [ + "sel_grid.selections = [\n", + " {\"r1\": 22, \"r2\": 20, \"c1\": 0, \"c2\": 2},\n", + " {\"r1\": 6, \"r2\": 6, \"c1\": 2, \"c2\": 2},\n", + " {\"r1\": 10, \"r2\": 10, \"c1\": 3, \"c2\": 3},\n", + " {\"r1\": 13, \"r2\": 13, \"c1\": 2, \"c2\": 2},\n", + "]" + ] + }, + { + "cell_type": "markdown", + "id": "e8d948c4", + "metadata": {}, + "source": [ + "Row selection mode" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b653da0e", + "metadata": {}, + "outputs": [], + "source": [ + "sel_grid.selection_mode='row'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "71cdf563", + "metadata": {}, + "outputs": [], + "source": [ + "for i in range(260):\n", + " sel_grid.select(i, i) if i % 2 == 0 else None" + ] + }, + { + "cell_type": "markdown", + "id": "85045e17", + "metadata": {}, + "source": [ + "#### Two-way cell editing is possible\n", + "\n", + "Just pass `editable=True` to the grid's constructorand you're good to go (grids are not editable by default)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e118e5d5", + "metadata": {}, + "outputs": [], + "source": [ + "small_grid = DataGrid(small_df, \n", + " editable=True, \n", + " default_renderer=TextRenderer(\n", + " background_color=VegaExpr(\"cell.value === 1 ? 'limegreen' : 'moccasin'\")\n", + " ),\n", + " layout={'height': '250px'})\n", + "small_grid" + ] + }, + { + "cell_type": "markdown", + "id": "5e0ccd9a", + "metadata": {}, + "source": [ + "You can change values directly in the UI by double clicking a cell and changing the value. You can navigate the grid using the keyboard. You can use the arrow keys or the grid's __cursor__:\n", + "\n", + "- __Down__: Enter\n", + "- __Up__: Shift + Enter\n", + "- __Right__: Tab\n", + "- __Left__: Shift + Tab" + ] + }, + { + "cell_type": "markdown", + "id": "806468bd", + "metadata": {}, + "source": [ + "..or you can change it directly from the Python side" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f0ac1126", + "metadata": {}, + "outputs": [], + "source": [ + "# Returns a boolean to indicate whether operations was successful\n", + "small_grid.set_cell_value('Col 0', 'Row 9', 1) # Sets value based on row name" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "af84ae1e", + "metadata": {}, + "outputs": [], + "source": [ + "small_grid.set_cell_value_by_index('Col 9', 0, 1) # Sets value based on row index" + ] + }, + { + "cell_type": "markdown", + "id": "9cb298fb", + "metadata": {}, + "source": [ + "#### Events and integration with `ipywidgets`" + ] + }, + { + "cell_type": "markdown", + "id": "2b00cab5", + "metadata": {}, + "source": [ + "Listen to cell change events" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b214bb25", + "metadata": {}, + "outputs": [], + "source": [ + "def cell_changed(e):\n", + " row, column, col_index, value = e['row'], e['column'], e['column_index'], e['value']\n", + " print(f'The cell at row {row}, column \"{column}\" (index {col_index}), changed to {value}')\n", + " \n", + "small_grid.on_cell_change(cell_changed)\n", + "small_grid" + ] + }, + { + "cell_type": "markdown", + "id": "8c454fb8", + "metadata": {}, + "source": [ + "#### An example with the BarRenderer" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d3dcd28e", + "metadata": {}, + "outputs": [], + "source": [ + "from bqplot import LinearScale, ColorScale\n", + "from ipydatagrid import DataGrid, BarRenderer\n", + "\n", + "linear_scale = LinearScale(min=0, max=1)\n", + "color_scale = ColorScale(min=0, max=1)\n", + "bar_renderer = BarRenderer(\n", + " bar_color=color_scale,\n", + " bar_value=linear_scale,\n", + " bar_horizontal_alignment=\"center\",\n", + ")\n", + "\n", + "\n", + "rand_grid = DataGrid(rand_df, default_renderer=bar_renderer, base_column_size=76)\n", + "rand_grid" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8296850a", + "metadata": {}, + "outputs": [], + "source": [ + "bar_renderer.show_text = False" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c920c322", + "metadata": {}, + "outputs": [], + "source": [ + "from ipywidgets import FloatSlider, link\n", + "\n", + "slider = FloatSlider(\n", + " description=\"Scale: \", value=linear_scale.max, min=0, max=0.99, step=0.01\n", + ")\n", + "link((color_scale, \"min\"), (slider, \"value\"))\n", + "link((linear_scale, \"min\"), (slider, \"value\"))\n", + "\n", + "slider" + ] + }, + { + "cell_type": "markdown", + "id": "b78005c8", + "metadata": {}, + "source": [ + "#### Integration with `bqplot`\n", + "\n", + "We have a DataGrid with time series of 10 different stock prices. Each time we click on a stock price column, we want to plot the time series of that stock price in a line chart." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e3ecc75d", + "metadata": {}, + "outputs": [], + "source": [ + "stock_df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dee03573", + "metadata": {}, + "outputs": [], + "source": [ + "from bqplot import LinearScale, Axis, Figure, Lines, CATEGORY10\n", + "from ipywidgets import HBox, Layout\n", + "\n", + "def plot_stock(e):\n", + " line.y = stock_grid.selected_cell_values\n", + " line.x = range(len(line.y))\n", + " line.labels = [e['column']]\n", + " line.colors = [CATEGORY10[np.random.randint(0, len(CATEGORY10)) % len(CATEGORY10)]]\n", + " \n", + "stock_grid = DataGrid(stock_df, selection_mode='column')\n", + "\n", + "# Event listener for cell click\n", + "stock_grid.on_cell_click(plot_stock)" + ] + }, + { + "cell_type": "markdown", + "id": "65ae20ea", + "metadata": {}, + "source": [ + "Setting up bqplot and ipywidgets objects" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6163f8dd", + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "# Creating the bqplot chart objects\n", + "sc_x = LinearScale()\n", + "sc_y = LinearScale()\n", + "line = Lines(x=[], y=[], labels=['Fake stock price'], display_legend=True,\n", + " scales={'x': sc_x, 'y': sc_y})\n", + "ax_x = Axis(scale=sc_x, label='Index')\n", + "ax_y = Axis(scale=sc_y, orientation='vertical', label='y-value')\n", + "fig = Figure(marks=[line], axes=[ax_x, ax_y], title='Line Chart', layout=Layout(flex='1 1 auto', width='100%'))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1413d459", + "metadata": {}, + "outputs": [], + "source": [ + "HBox(\n", + " [stock_grid, fig]\n", + ")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/07.04-ipyvolume.ipynb b/notebooks/07.04-ipyvolume.ipynb new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/notebooks/07.04-ipyvolume.ipynb @@ -0,0 +1 @@ + diff --git a/notebooks/07.05-other-widget-libraries.ipynb b/notebooks/07.05-other-widget-libraries.ipynb new file mode 100644 index 00000000..832e9a65 --- /dev/null +++ b/notebooks/07.05-other-widget-libraries.ipynb @@ -0,0 +1,33 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "7e3a1d9e-3a48-41ff-a2b7-2dbcdb82c520", + "metadata": {}, + "source": [ + "# To be added" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/07.More-libraries/07.00-More_widget_libraries.ipynb b/notebooks/07.More-libraries/07.00-More_widget_libraries.ipynb index 5c4721d9..e0fa3ff9 100644 --- a/notebooks/07.More-libraries/07.00-More_widget_libraries.ipynb +++ b/notebooks/07.More-libraries/07.00-More_widget_libraries.ipynb @@ -52,9 +52,9 @@ ], "metadata": { "kernelspec": { - "display_name": "widgets-tutorial", + "display_name": "Python 3", "language": "python", - "name": "widgets-tutorial" + "name": "python3" }, "language_info": { "codemirror_mode": { diff --git a/notebooks/widgets_libraries/07.01-ipyleaflet.ipynb b/notebooks/widgets_libraries/07.01-ipyleaflet.ipynb new file mode 100644 index 00000000..887382b7 --- /dev/null +++ b/notebooks/widgets_libraries/07.01-ipyleaflet.ipynb @@ -0,0 +1,657 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "< [More widget libraries](07.00-More_widget_libraries.ipynb) | [Contents](00.00-index.ipynb) | [pythreejs: 3D rendering in the browser](07.02-pythreejs.ipynb) >" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# ipyleaflet: Interactive maps\n", + "\n", + "## A Jupyter - LeafletJS bridge\n", + "\n", + "## https://github.com/jupyter-widgets/ipyleaflet\n", + "\n", + "\n", + "ipyleaflet is a jupyter interactive widget library which provides interactive maps to the Jupyter notebook.\n", + "\n", + "- MIT Licensed\n", + "\n", + "**Installation:**\n", + "\n", + "```bash\n", + "conda install -c conda-forge ipyleaflet\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from __future__ import print_function\n", + "\n", + "from ipyleaflet import (\n", + " Map,\n", + " Marker, MarkerCluster, TileLayer, ImageOverlay, GeoJSON,\n", + " Polyline, Polygon, Rectangle, Circle, CircleMarker, Popup,\n", + " SplitMapControl, WidgetControl,\n", + " basemaps, basemap_to_tiles\n", + ")\n", + "\n", + "from ipywidgets import HTML" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "center = [34.6252978589571, -77.34580993652344]\n", + "zoom = 10" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Map Widget" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "m = Map(center=center, zoom=zoom)\n", + "m" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "m.layout.height = '700px'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Every Layer in ipyleaflet is a Widget: TileLayers, Markers, Heatmaps, Videos..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can dynamically change the layers you apply on top of the Map, for example you can dynamically change the base TileLayer and control it through a SelectionSlider widget:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from datetime import date, timedelta\n", + "from ipywidgets import SelectionSlider\n", + "\n", + "n_days = 30\n", + "days = []\n", + "\n", + "# Previous 30 days, starting from today\n", + "for n in range(n_days):\n", + " delta = (n_days - n) * timedelta(days=1)\n", + " days.append((date.today() - delta).isoformat())\n", + "\n", + "days_slider = SelectionSlider(options=days, value=days[-1], description='Day: ')\n", + "\n", + "base_layer = basemap_to_tiles(basemaps.NASAGIBS.ModisTerraTrueColorCR, days_slider.value)\n", + "\n", + "m.layers = [base_layer]\n", + "m.zoom = 6" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def handle_day_change(change, **kwargs):\n", + " base_layer.url = basemaps.NASAGIBS.ModisTerraTrueColorCR.get('url') % change['new']\n", + "\n", + "days_slider.observe(handle_day_change, 'value')\n", + "\n", + "days_slider" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# jupyterlab-sidecar: A sidecar output widget for JupyterLab\n", + "\n", + "## https://github.com/jupyter-widgets/jupyterlab-sidecar" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from sidecar import Sidecar\n", + "\n", + "sc = Sidecar(title='Map Output')\n", + "with sc:\n", + " m.layout.height = ''\n", + " display(m)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Marker" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mark = Marker(location=m.center)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "m += mark" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mark.visible" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mark.visible = False" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mark.visible = True" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mark.interact(opacity=(0.0, 1.0, 0.01))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Popup\n", + "\n", + "The popup is displayed when you click on the marker. You can add ANY widget as a popup for the marker, from simple HTMLWidget to plots using bqplot." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from ipywidgets import FloatSlider, link\n", + "\n", + "slider = FloatSlider(value=1.0, min=0.0, max=1.0)\n", + "link((mark, 'opacity'), (slider, 'value'))\n", + "\n", + "mark.popup = slider" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Marker Cluster\n", + "\n", + "Markers can be clustered depending on the zoom level." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "xscale = 5\n", + "yscale = 10\n", + "\n", + "x = [m.center[0] + i * xscale * .05 for i in (-1,0,1)]\n", + "y = [m.center[1] + i * yscale * .05 for i in (-1,0,1)]\n", + "\n", + "from itertools import product\n", + "locations = product(x, y)\n", + "markers = [Marker(location=loc) for loc in locations]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `MarkerCluster` will automatically handle clustering and the zoom level changes." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "marker_cluster = MarkerCluster(markers=markers)\n", + "m += marker_cluster" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Heatmap" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from ipywidgets import Button, IntSlider, link\n", + "from ipyleaflet import Heatmap\n", + "from random import gauss\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "center = (37.09, -103.66)\n", + "zoom = 5" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def create_random_data(length):\n", + " \"Return a list of some random lat/lon/value triples.\"\n", + " return [[gauss(center[0], 2), \n", + " gauss(center[1], 4),\n", + " gauss(700, 300)] for i in range(length)]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "m.center = center\n", + "m.zoom = zoom" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "heat = Heatmap(locations=create_random_data(1000), radius=20, blur=10)\n", + "m.add_layer(heat)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def generate(_):\n", + " heat.locations = create_random_data(1000)\n", + "\n", + "button = Button(description='Generate data', button_style='success')\n", + "button.on_click(generate)\n", + "button" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "slider = IntSlider(min=10, max=30, value=heat.radius)\n", + "link((slider, 'value'), (heat, 'radius'))\n", + "slider" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Controls" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# The following NASA images need a zoom level <= 9\n", + "if m.zoom > 9:\n", + " m.zoom = 9\n", + "\n", + "control = SplitMapControl(\n", + " left_layer=basemap_to_tiles(basemaps.NASAGIBS.ModisTerraTrueColorCR, \"2017-11-11\") , \n", + " right_layer=basemap_to_tiles(basemaps.NASAGIBS.ModisAquaBands721CR, \"2017-11-11\")\n", + ")\n", + "m.add_control(control)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "m.remove_control(control)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from ipywidgets import IntSlider, Button, link\n", + "\n", + "button = Button(description='Goto NYC')\n", + "\n", + "def goto_nyc(*args, **kwargs):\n", + " # NYC: 40.7128° N, 74.0060° W\n", + " m.center = (40.7128, -74.0060)\n", + " m.zoom = 9\n", + "\n", + "button.on_click(goto_nyc)\n", + "\n", + "wid_control = WidgetControl(widget=button, position='bottomright')\n", + "m.add_control(wid_control)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## JupyterLab Themes Support\n", + "\n", + "Controls in ipyleaflet have support for JupyterLab themes, try changing the current theme" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "m.remove_control(wid_control)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Advanced example 1: Velocity\n", + "\n", + "*It is ok to skip this for now -- running it requires downloading a ~1MB data file.*\n", + "\n", + "This example needs an extra dependency that is not in the installation instructions and a dataset.\n", + "\n", + "You can install it with this:\n", + "\n", + "```bash\n", + "pip install netcdf4\n", + "```\n", + "\n", + "To download the data, copy and paste the code below into a new cell and run it.\n", + "\n", + "```python\n", + "import requests\n", + "\n", + "wind_data = requests.get('https://github.com/benbovy/xvelmap/raw/master/notebooks/wind-global.nc') \n", + "\n", + "with open('wind-global.nc', 'wb') as f: \n", + " f.write(wind_data.content)\n", + "```\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from ipyleaflet.velocity import Velocity\n", + "import xarray as xr" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "center = (0, 0)\n", + "zoom = 4\n", + "\n", + "m2 = Map(center=center, zoom=zoom, interpolation='nearest', basemap=basemaps.CartoDB.DarkMatter)\n", + "\n", + "sc2 = Sidecar(title='Map Velocity')\n", + "\n", + "with sc2:\n", + " display(m2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ds = xr.open_dataset('wind-global.nc')\n", + "display_options = {\n", + " 'velocityType': 'Global Wind',\n", + " 'displayPosition': 'bottomleft',\n", + " 'displayEmptyString': 'No wind data'\n", + "}\n", + "wind = Velocity(data=ds,\n", + " zonal_speed='u_wind',\n", + " meridional_speed='v_wind',\n", + " latitude_dimension='lat',\n", + " longitude_dimension='lon',\n", + " velocity_scale=0.01,\n", + " max_velocity=20,\n", + " display_options=display_options)\n", + "m2.add_layer(wind)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Advanced example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from ipywidgets import Text, HTML, HBox\n", + "from ipyleaflet import GeoJSON, WidgetControl, Map \n", + "import json" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "m = Map(center = (43,-100), zoom = 4)\n", + "\n", + "geo_json_data = json.load(open('us-states-density-colored.json'))\n", + "geojson = GeoJSON(data=geo_json_data, hover_style={'color': 'black', 'dashArray': '5, 5', 'weight': 2})\n", + "m.add_layer(geojson)\n", + "\n", + "html = HTML('''\n", + "

US population density

\n", + " Hover over a state\n", + "''')\n", + "html.layout.margin = '0px 20px 20px 20px'\n", + "control = WidgetControl(widget=html, position='topright')\n", + "m.add_control(control)\n", + "\n", + "def update_html(properties, **kwargs):\n", + " html.value = '''\n", + "

US population density

\n", + "

{}

\n", + " {} people / mi^2\n", + " '''.format(properties['name'], properties['density'])\n", + "\n", + "geojson.on_hover(update_html)\n", + "\n", + "m" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Exercise" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1) Create a Map" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2) Create a slider controlling the zoom level of the Map (manually, not using interact)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3) Embed the slider in a WidgetControl on the bottom left of the map" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "< [More widget libraries](07.00-More_widget_libraries.ipynb) | [Contents](00.00-index.ipynb) | [pythreejs: 3D rendering in the browser](07.02-pythreejs.ipynb) >" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "widgets-tutorial", + "language": "python", + "name": "widgets-tutorial" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.3" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/notebooks/widgets_libraries/07.02-pythreejs.ipynb b/notebooks/widgets_libraries/07.02-pythreejs.ipynb new file mode 100644 index 00000000..af770033 --- /dev/null +++ b/notebooks/widgets_libraries/07.02-pythreejs.ipynb @@ -0,0 +1,317 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "< [ipycanvas](07.01-ipycanvas.ipynb) | [Contents](00.00-index.ipynb) | [bqplot: complex interactive visualizations](07.03-bqplot.ipynb) >" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# pythreejs: 3D rendering in the browser \n", + "\n", + "## A Jupyter - threejs bridge\n", + "\n", + "## https://github.com/jupyter-widgets/pythreejs\n", + "\n", + "\n", + "Pythreejs is a jupyter interactive widget bringing fast WebGL 3d visualization to the Jupyter notebook.\n", + "\n", + "- Originally authored by Jason Grout, currently maintained by Vidar Tonaas Fauske\n", + "- BSD Licensed\n", + "\n", + "Pythreejs is *not* a 3d plotting library, it only exposes the threejs scene objects to the Jupyter kernel.\n", + "\n", + "**Installation:**\n", + "\n", + "```bash\n", + "conda install -c conda-forge pythreejs\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## This notebook based on [Examples.ipynb](https://github.com/jupyter-widgets/pythreejs/blob/master/examples/Examples.ipynb) \n", + "\n", + "One of the many example notebooks at https://github.com/jupyter-widgets/pythreejs/tree/master/examples" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from pythreejs import *\n", + "import numpy as np\n", + "from IPython.display import display\n", + "from ipywidgets import HTML, Text, Output, VBox\n", + "from traitlets import link, dlink" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Simple sphere" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ball = Mesh(geometry=SphereGeometry(radius=1), \n", + " material=MeshLambertMaterial(color='red'),\n", + " position=[2, 1, 0])\n", + "\n", + "c = PerspectiveCamera(position=[0, 5, 5], up=[0, 1, 0],\n", + " children=[DirectionalLight(color='white', position=[3, 5, 1], intensity=0.5)])\n", + "\n", + "scene = Scene(children=[ball, c, AmbientLight(color='#777777')])\n", + "\n", + "renderer = Renderer(camera=c, \n", + " scene=scene, \n", + " controls=[OrbitControls(controlling=c)])\n", + "display(renderer)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Properties of the ball can be updated, with changes reflected immediately in the visualization." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ball.scale = (0.5,) * 3" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import time, math\n", + "ball.material.color = '#4400dd'\n", + "for i in range(1, 150, 2):\n", + " ball.scale = (i / 100.,) * 3\n", + " ball.position = [math.cos(i / 10.), math.sin(i / 50.), i / 100.]\n", + " time.sleep(.05)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Clickable Surface" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Generate surface data:\n", + "view_width = 600\n", + "view_height = 400\n", + "nx, ny = (20, 20)\n", + "xmax=1\n", + "x = np.linspace(-xmax, xmax, nx)\n", + "y = np.linspace(-xmax, xmax, ny)\n", + "xx, yy = np.meshgrid(x, y)\n", + "z = xx ** 2 - yy ** 2\n", + "#z[6,1] = float('nan')\n", + "\n", + "\n", + "# Generate scene objects from data:\n", + "surf_g = SurfaceGeometry(z=list(z[::-1].flat), \n", + " width=2 * xmax,\n", + " height=2 * xmax,\n", + " width_segments=nx - 1,\n", + " height_segments=ny - 1)\n", + "\n", + "surf = Mesh(geometry=surf_g,\n", + " material=MeshLambertMaterial(map=height_texture(z[::-1], 'YlGnBu_r')))\n", + "\n", + "surfgrid = SurfaceGrid(geometry=surf_g, material=LineBasicMaterial(color='black'),\n", + " position=[0, 0, 1e-2]) # Avoid overlap by lifting grid slightly\n", + "\n", + "# Set up picking bojects:\n", + "hover_point = Mesh(geometry=SphereGeometry(radius=0.05),\n", + " material=MeshLambertMaterial(color='green'))\n", + "\n", + "click_picker = Picker(controlling=surf, event='dblclick')\n", + "hover_picker = Picker(controlling=surf, event='mousemove')\n", + "\n", + "# Set up scene:\n", + "key_light = DirectionalLight(color='white', position=[3, 5, 1], intensity=0.4)\n", + "c = PerspectiveCamera(position=[0, 3, 3], up=[0, 0, 1], aspect=view_width / view_height,\n", + " children=[key_light])\n", + "\n", + "scene = Scene(children=[surf, c, surfgrid, hover_point, AmbientLight(intensity=0.8)])\n", + "\n", + "renderer = Renderer(camera=c, scene=scene,\n", + " width=view_width, height=view_height,\n", + " controls=[OrbitControls(controlling=c), click_picker, hover_picker])\n", + "\n", + "\n", + "# Set up picking responses:\n", + "# Add a new marker when double-clicking:\n", + "out = Output()\n", + "def f(change):\n", + " value = change['new']\n", + " with out:\n", + " print('Clicked on %s' % (value,))\n", + " point = Mesh(geometry=SphereGeometry(radius=0.05), \n", + " material=MeshLambertMaterial(color='hotpink'),\n", + " position=value)\n", + " scene.add(point)\n", + "\n", + "click_picker.observe(f, names=['point'])\n", + "\n", + "# Have marker follow picker point:\n", + "link((hover_point, 'position'), (hover_picker, 'point'))\n", + "\n", + "# Show picker point coordinates as a label:\n", + "h = HTML()\n", + "def g(change):\n", + " h.value = 'Green point at (%.3f, %.3f, %.3f)' % tuple(change['new'])\n", + " h.value += ' Double-click to add marker'\n", + "g({'new': hover_point.position})\n", + "hover_picker.observe(g, names=['point'])\n", + "\n", + "display(VBox([h, renderer, out]))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# when we change the z values of the geometry, we need to also change the height map\n", + "surf_g.z = list((-z[::-1]).flat)\n", + "surf.material.map = height_texture(-z[::-1])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Parametric Functions\n", + "\n", + "\n", + "To use the ParametricGeometry class, you need to specify a javascript function as a string. The function should take two parameters that vary between 0 and 1, and return a `new THREE.Vector3(x,y,z)`.\n", + "\n", + "If you want to build the surface in Python, you'll need to explicitly construct the vertices and faces and build a basic geometry from the vertices and faces." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "f = \"\"\"\n", + "function f(origu, origv, vec) {\n", + " // scale u and v to the ranges I want: [0, 2*pi]\n", + " var u = 2*Math.PI*origu;\n", + " var v = 2*Math.PI*origv;\n", + "\n", + " vec.x = Math.sin(u);\n", + " vec.y = Math.cos(v);\n", + " vec.z = Math.cos(u+v);\n", + "}\n", + "\"\"\"\n", + "surf_g = ParametricGeometry(func=f, slices=16, stacks=16);\n", + "\n", + "surf = Mesh(geometry=surf_g, material=MeshLambertMaterial(color='green', side='FrontSide'))\n", + "surf2 = Mesh(geometry=surf_g, material=MeshLambertMaterial(color='yellow', side='BackSide'))\n", + "c = PerspectiveCamera(position=[5, 5, 3], up=[0, 0, 1],\n", + " children=[DirectionalLight(color='white',\n", + " position=[3, 5, 1],\n", + " intensity=0.6)])\n", + "scene = Scene(children=[surf, surf2, c, AmbientLight(intensity=0.5)])\n", + "renderer = Renderer(camera=c, scene=scene, controls=[OrbitControls(controlling=c)], width=400, height=400)\n", + "display(renderer)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "< [ipycanvas](07.01-ipycanvas.ipynb) | [Contents](00.00-index.ipynb) | [bqplot: complex interactive visualizations](07.03-bqplot.ipynb) >" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "widgets-tutorial", + "language": "python", + "name": "widgets-tutorial" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.5" + }, + "widgets": { + "state": { + "01b59842f123469f8518ef01a0a3dc2b": { + "views": [ + { + "cell_index": 6 + } + ] + }, + "9ad3421bc8374489a73f356fa90eb605": { + "views": [ + { + "cell_index": 3 + } + ] + }, + "ddb9e9caabe04004a81c108b889973e7": { + "views": [ + { + "cell_index": 10 + } + ] + }, + "e372695c70254a63af0d6f485dd1f3a3": { + "views": [ + { + "cell_index": 3 + } + ] + } + }, + "version": "2.0.0-dev" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/notebooks/widgets_libraries/07.03-bqplot.ipynb b/notebooks/widgets_libraries/07.03-bqplot.ipynb new file mode 100644 index 00000000..c33a2018 --- /dev/null +++ b/notebooks/widgets_libraries/07.03-bqplot.ipynb @@ -0,0 +1,525 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "< [pythreejs: 3D rendering in the browser](07.02-pythreejs.ipynb) | [Contents](00.00-index.ipynb) | [ipyvolume: 3D plotting in the notebook](07.04-ipyvolume.ipynb) >" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# bqplot: complex interactive visualizations\n", + "\n", + "## https://github.com/bloomberg/bqplot\n", + "\n", + "## A Jupyter - d3.js bridge\n", + "\n", + "bqplot is a jupyter interactive widget library bringing d3.js visualization to the Jupyter notebook.\n", + "\n", + "- Apache Licensed\n", + "\n", + "bqplot implements the abstractions of Wilkinson’s “The Grammar of Graphics” as interactive Jupyter widgets.\n", + "\n", + "bqplot provides both\n", + "-\thigh-level plotting procedures with relevant defaults for common chart types,\n", + "-\tlower-level descriptions of data visualizations meant for complex interactive visualization dashboards and applications involving mouse interactions and user-provided Python callbacks.\n", + "\n", + "**Installation:**\n", + "\n", + "```bash\n", + "conda install -c conda-forge bqplot\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from __future__ import print_function\n", + "from IPython.display import display\n", + "from ipywidgets import *\n", + "from traitlets import *\n", + "\n", + "import numpy as np\n", + "import pandas as pd\n", + "import bqplot as bq\n", + "import datetime as dt" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "np.random.seed(0)\n", + "size = 100\n", + "y_data = np.cumsum(np.random.randn(size) * 100.0)\n", + "y_data_2 = np.cumsum(np.random.randn(size))\n", + "y_data_3 = np.cumsum(np.random.randn(size) * 100.)\n", + "\n", + "x = np.linspace(0.0, 10.0, size)\n", + "\n", + "price_data = pd.DataFrame(np.cumsum(np.random.randn(150, 2).dot([[0.5, 0.8], [0.8, 1.0]]), axis=0) + 100,\n", + " columns=['Security 1', 'Security 2'],\n", + " index=pd.date_range(start='01-01-2007', periods=150))\n", + "\n", + "symbol = 'Security 1'\n", + "dates_all = price_data.index.values\n", + "final_prices = price_data[symbol].values.flatten()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# A simple plot with the pyplot API" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from bqplot import pyplot as plt" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "plt.figure(1)\n", + "n = 100\n", + "plt.plot(np.linspace(0.0, 10.0, n), np.cumsum(np.random.randn(n)), \n", + " axes_options={'y': {'grid_lines': 'dashed'}})\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Scatter Plot" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "plt.figure(title='Scatter Plot with colors')\n", + "plt.scatter(y_data_2, y_data_3, color=y_data)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Histogram" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "plt.figure()\n", + "plt.hist(y_data, colors=['OrangeRed'])\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Every component of the figure is an independent widget" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "xs = bq.LinearScale()\n", + "ys = bq.LinearScale()\n", + "x = np.arange(100)\n", + "y = np.cumsum(np.random.randn(2, 100), axis=1) #two random walks\n", + "\n", + "line = bq.Lines(x=x, y=y, scales={'x': xs, 'y': ys}, colors=['red', 'green'])\n", + "xax = bq.Axis(scale=xs, label='x', grid_lines='solid')\n", + "yax = bq.Axis(scale=ys, orientation='vertical', tick_format='0.2f', label='y', grid_lines='solid')\n", + "\n", + "fig = bq.Figure(marks=[line], axes=[xax, yax], animation_duration=1000)\n", + "display(fig)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# update data of the line mark\n", + "line.y = np.cumsum(np.random.randn(2, 100), axis=1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "xs = bq.LinearScale()\n", + "ys = bq.LinearScale()\n", + "x, y = np.random.rand(2, 20)\n", + "scatt = bq.Scatter(x=x, y=y, scales={'x': xs, 'y': ys}, default_colors=['blue'])\n", + "xax = bq.Axis(scale=xs, label='x', grid_lines='solid')\n", + "yax = bq.Axis(scale=ys, orientation='vertical', tick_format='0.2f', label='y', grid_lines='solid')\n", + "\n", + "fig = bq.Figure(marks=[scatt], axes=[xax, yax], animation_duration=1000)\n", + "display(fig)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#data updates\n", + "scatt.x = np.random.rand(20) * 10\n", + "scatt.y = np.random.rand(20)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## The same holds for the attributes of scales, axes" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "xs.min = 4" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "xs.min = None" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "xax.label = 'Some label for the x axis'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Use bqplot figures as input widgets" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "xs = bq.LinearScale()\n", + "ys = bq.LinearScale()\n", + "x = np.arange(100)\n", + "y = np.cumsum(np.random.randn(2, 100), axis=1) #two random walks\n", + "\n", + "line = bq.Lines(x=x, y=y, scales={'x': xs, 'y': ys}, colors=['red', 'green'])\n", + "xax = bq.Axis(scale=xs, label='x', grid_lines='solid')\n", + "yax = bq.Axis(scale=ys, orientation='vertical', tick_format='0.2f', label='y', grid_lines='solid')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Selections" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def interval_change_callback(change):\n", + " db.value = str(change['new'])\n", + "\n", + "intsel = bq.interacts.FastIntervalSelector(scale=xs, marks=[line])\n", + "intsel.observe(interval_change_callback, names=['selected'] )\n", + "\n", + "db = widgets.Label()\n", + "db.value = str(intsel.selected)\n", + "display(db)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fig = bq.Figure(marks=[line], axes=[xax, yax], animation_duration=1000, interaction=intsel)\n", + "display(fig)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "line.selected" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Handdraw" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "handdraw = bq.interacts.HandDraw(lines=line)\n", + "fig.interaction = handdraw" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "line.y[0]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Moving points around" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from bqplot import (LinearScale, Scatter, Label, Axis, Figure, Lines)\n", + "import numpy as np\n", + "\n", + "size = 100\n", + "np.random.seed(0)\n", + "x_data = range(size)\n", + "y_data = np.cumsum(np.random.randn(size) * 100.0)\n", + "\n", + "## Enabling moving of points in scatter. Try to click and drag any of the points in the scatter and \n", + "## notice the line representing the mean of the data update\n", + "\n", + "sc_x = LinearScale()\n", + "sc_y = LinearScale()\n", + "\n", + "scat = Scatter(x=x_data[:10], y=y_data[:10], scales={'x': sc_x, 'y': sc_y}, default_colors=['blue'],\n", + " enable_move=True)\n", + "lin = Lines(scales={'x': sc_x, 'y': sc_y}, stroke_width=4, line_style='dashed', colors=['orange'])\n", + "m = Label(x=[0.05], y=[0.9], text=[\"\"], colors=[\"black\"])\n", + "\n", + "def update_line(change):\n", + " with lin.hold_sync():\n", + " lin.x = [np.min(scat.x), np.max(scat.x)]\n", + " lin.y = [np.mean(scat.y), np.mean(scat.y)]\n", + " m.text=['Mean is %s'%np.mean(scat.y)]\n", + " \n", + "\n", + "update_line(None)\n", + "\n", + "# update line on change of x or y of scatter\n", + "scat.observe(update_line, names='x')\n", + "scat.observe(update_line, names='y')\n", + "\n", + "ax_x = Axis(scale=sc_x)\n", + "ax_y = Axis(scale=sc_y, tick_format='0.2f', orientation='vertical')\n", + "\n", + "fig = Figure(marks=[scat, lin, m], axes=[ax_x, ax_y])\n", + "\n", + "## In this case on drag, the line updates as you move the points.\n", + "with scat.hold_sync():\n", + " scat.enable_move = True\n", + " scat.update_on_move = True\n", + " scat.enable_add = False\n", + "\n", + "display(fig)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Exercises" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1) Create a line chart using the object model (use x_data and y_data as your data attributes)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2) Update the data of the Line mark, and change its color to 'darkorange'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "< [pythreejs: 3D rendering in the browser](07.02-pythreejs.ipynb) | [Contents](00.00-index.ipynb) | [ipyvolume: 3D plotting in the notebook](07.04-ipyvolume.ipynb) >" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.10" + }, + "widgets": { + "state": { + "0ba98b0561564e5987dba19d1b574c04": { + "views": [ + { + "cell_index": 29 + } + ] + }, + "1ffa1ac6658e4eef89e45cf62daae339": { + "views": [ + { + "cell_index": 30 + } + ] + }, + "42735872becb4c43b817ccff90973d63": { + "views": [ + { + "cell_index": 15 + } + ] + }, + "4b9a5b18593545faba761a719b2e6039": { + "views": [ + { + "cell_index": 17 + } + ] + }, + "7fb14b25d15240ec820c565619fe4f11": { + "views": [ + { + "cell_index": 7 + } + ] + }, + "99604f1b70c54e19a508c95d705ce488": { + "views": [ + { + "cell_index": 9 + } + ] + }, + "bf805af773d94496888afbe9e2bd3d37": { + "views": [ + { + "cell_index": 13 + } + ] + }, + "dc1b84a0e5fa4ed5a42454cfc52c44f5": { + "views": [ + { + "cell_index": 25 + } + ] + }, + "f30275bcf69e426c9d45a525833198d0": { + "views": [ + { + "cell_index": 5 + } + ] + } + }, + "version": "2.0.0-dev" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/notebooks/widgets_libraries/07.xx-ipyvolume.ipynb b/notebooks/widgets_libraries/07.xx-ipyvolume.ipynb new file mode 100644 index 00000000..53d3e9ef --- /dev/null +++ b/notebooks/widgets_libraries/07.xx-ipyvolume.ipynb @@ -0,0 +1,232 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "< [bqplot: complex interactive visualizations](07.03-bqplot.ipynb) | [Contents](00.00-index.ipynb) | [Dashboarding with widgets](08.00-voila.ipynb) >" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# ipyvolume: 3D plotting in the notebook\n", + "\n", + "## https://github.com/maartenbreddels/ipyvolume\n", + "\n", + "IPyvolume is a Python library to visualize 3d volumes and glyphs (e.g. 3d scatter plots), in the Jupyter notebook, with minimal configuration and effort. It is currently pre-1.0, so use at own risk. IPyvolume’s volshow is to 3d arrays what matplotlib’s imshow is to 2d arrays.\n", + "\n", + "- MIT Licensed\n", + "\n", + "By Maarten Breddels\n", + "\n", + "**Installation:**\n", + "\n", + "```bash\n", + "conda install -c conda-forge ipyvolume\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 3-D Scatter Plots" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import ipyvolume as ipv\n", + "import numpy as np\n", + "import ipywidgets as widgets" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x, y, z = np.random.random((3, 10000))\n", + "ipv.figure()\n", + "scatter = ipv.scatter(x, y, z, size=1, marker=\"sphere\")\n", + "ipv.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ipv.save('standalone.html')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Open the HTML file from the file browser" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x, y, z, u, v, w = np.random.random((6, 1000))*2-1\n", + "selected = np.random.randint(0, 1000, 100)\n", + "fig = ipv.figure()\n", + "quiver = ipv.quiver(x, y, z, u, v, w, size=5, size_selected=8, selected=selected)\n", + "ipv.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "size = widgets.FloatSlider(min=0, max=30, step=0.1)\n", + "size_selected = widgets.FloatSlider(min=0, max=30, step=0.1)\n", + "color = widgets.ColorPicker()\n", + "color_selected = widgets.ColorPicker()\n", + "widgets.jslink((quiver, 'size'), (size, 'value'))\n", + "widgets.jslink((quiver, 'size_selected'), (size_selected, 'value'))\n", + "widgets.jslink((quiver, 'color'), (color, 'value'))\n", + "widgets.jslink((quiver, 'color_selected'), (color_selected, 'value'))\n", + "widgets.VBox([size, size_selected, color, color_selected])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Animations" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# create 2d grids: x, y, and r\n", + "u = np.linspace(-10, 10, 25)\n", + "x, y = np.meshgrid(u, u)\n", + "r = np.sqrt(x**2+y**2)\n", + "print(\"x,y and z are of shape\", x.shape)\n", + "# and turn them into 1d\n", + "x = x.flatten()\n", + "y = y.flatten()\n", + "r = r.flatten()\n", + "print(\"and flattened of shape\", x.shape)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# create a sequence of 15 time elements\n", + "time = np.linspace(0, np.pi*2, 15)\n", + "z = np.array([(np.cos(r + t) * np.exp(-r/5)) for t in time])\n", + "print(\"z is of shape\", z.shape)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# draw the scatter plot, and add controls with animate_glyphs\n", + "ipv.figure()\n", + "s = ipv.scatter(x, z, y, marker=\"sphere\")\n", + "ipv.animation_control(s, interval=200)\n", + "ipv.ylim(-3,3)\n", + "ipv.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Now also include, color, which containts rgb values\n", + "color = np.array([[np.cos(r + t), 1-np.abs(z[i]), 0.1+z[i]*0] for i, t in enumerate(time)])\n", + "size = (z+1)\n", + "print(\"color is of shape\", color.shape)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "color = np.transpose(color, (0, 2, 1)) # flip the last axes" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ipv.figure()\n", + "s = ipv.scatter(x, z, y, color=color, size=size, marker=\"sphere\")\n", + "ipv.animation_control(s, interval=200)\n", + "ipv.ylim(-3, 3)\n", + "ipv.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "< [bqplot: complex interactive visualizations](07.03-bqplot.ipynb) | [Contents](00.00-index.ipynb) | [Dashboarding with widgets](08.00-voila.ipynb) >" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "widgets-tutorial", + "language": "python", + "name": "widgets-tutorial" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.3" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} From 54989cd212a0fc4627743f0e0bd77d7096d18198 Mon Sep 17 00:00:00 2001 From: Itay Dafna Date: Thu, 1 Jul 2021 22:59:46 -0700 Subject: [PATCH 6/8] Change kernelspecs, rename other-widgets notebook Signed-off-by: Itay Dafna --- notebooks/07.03-ipydatagrid.ipynb | 4 ++-- ...get-libraries.ipynb => 07.09-other-widget-libraries.ipynb} | 4 ++-- notebooks/07.More-libraries/07.00-More_widget_libraries.ipynb | 4 ++-- notebooks/widgets_libraries/07.01-ipyleaflet.ipynb | 2 +- notebooks/widgets_libraries/07.03-bqplot.ipynb | 4 ++-- notebooks/widgets_libraries/07.xx-ipyvolume.ipynb | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) rename notebooks/{07.05-other-widget-libraries.ipynb => 07.09-other-widget-libraries.ipynb} (88%) diff --git a/notebooks/07.03-ipydatagrid.ipynb b/notebooks/07.03-ipydatagrid.ipynb index 1dea7501..f9777422 100644 --- a/notebooks/07.03-ipydatagrid.ipynb +++ b/notebooks/07.03-ipydatagrid.ipynb @@ -878,9 +878,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "widgets-tutorial", "language": "python", - "name": "python3" + "name": "widgets-tutorial" }, "language_info": { "codemirror_mode": { diff --git a/notebooks/07.05-other-widget-libraries.ipynb b/notebooks/07.09-other-widget-libraries.ipynb similarity index 88% rename from notebooks/07.05-other-widget-libraries.ipynb rename to notebooks/07.09-other-widget-libraries.ipynb index 832e9a65..b0d1fa4a 100644 --- a/notebooks/07.05-other-widget-libraries.ipynb +++ b/notebooks/07.09-other-widget-libraries.ipynb @@ -11,9 +11,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "widgets-tutorial", "language": "python", - "name": "python3" + "name": "widgets-tutorial" }, "language_info": { "codemirror_mode": { diff --git a/notebooks/07.More-libraries/07.00-More_widget_libraries.ipynb b/notebooks/07.More-libraries/07.00-More_widget_libraries.ipynb index e0fa3ff9..5c4721d9 100644 --- a/notebooks/07.More-libraries/07.00-More_widget_libraries.ipynb +++ b/notebooks/07.More-libraries/07.00-More_widget_libraries.ipynb @@ -52,9 +52,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "widgets-tutorial", "language": "python", - "name": "python3" + "name": "widgets-tutorial" }, "language_info": { "codemirror_mode": { diff --git a/notebooks/widgets_libraries/07.01-ipyleaflet.ipynb b/notebooks/widgets_libraries/07.01-ipyleaflet.ipynb index 887382b7..35ac5e96 100644 --- a/notebooks/widgets_libraries/07.01-ipyleaflet.ipynb +++ b/notebooks/widgets_libraries/07.01-ipyleaflet.ipynb @@ -649,7 +649,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.3" + "version": "3.8.10" } }, "nbformat": 4, diff --git a/notebooks/widgets_libraries/07.03-bqplot.ipynb b/notebooks/widgets_libraries/07.03-bqplot.ipynb index c33a2018..86f844e8 100644 --- a/notebooks/widgets_libraries/07.03-bqplot.ipynb +++ b/notebooks/widgets_libraries/07.03-bqplot.ipynb @@ -435,9 +435,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "widgets-tutorial", "language": "python", - "name": "python3" + "name": "widgets-tutorial" }, "language_info": { "codemirror_mode": { diff --git a/notebooks/widgets_libraries/07.xx-ipyvolume.ipynb b/notebooks/widgets_libraries/07.xx-ipyvolume.ipynb index 53d3e9ef..c3f5e8a6 100644 --- a/notebooks/widgets_libraries/07.xx-ipyvolume.ipynb +++ b/notebooks/widgets_libraries/07.xx-ipyvolume.ipynb @@ -224,7 +224,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.3" + "version": "3.8.10" } }, "nbformat": 4, From f6b24e4a6f65ba02b0661b66f941f38d8859bba5 Mon Sep 17 00:00:00 2001 From: Itay Dafna Date: Fri, 2 Jul 2021 00:07:12 -0700 Subject: [PATCH 7/8] Update other widget libraries notebook Signed-off-by: Itay Dafna --- notebooks/07.09-other-widget-libraries.ipynb | 427 ++++++++++++++++++- 1 file changed, 426 insertions(+), 1 deletion(-) diff --git a/notebooks/07.09-other-widget-libraries.ipynb b/notebooks/07.09-other-widget-libraries.ipynb index b0d1fa4a..d0ea6a8c 100644 --- a/notebooks/07.09-other-widget-libraries.ipynb +++ b/notebooks/07.09-other-widget-libraries.ipynb @@ -5,7 +5,432 @@ "id": "7e3a1d9e-3a48-41ff-a2b7-2dbcdb82c520", "metadata": {}, "source": [ - "# To be added" + "# Other widget libraries\n", + "\n", + "We would have loved to show you everything the Jupyter Widgets ecosystem has to offer today, but we are blessed to have such an active community of widget creators and unfortunately can't fit all widgets in a single session, no matter how long. \n", + "\n", + "This notebook lists some of the widget libraries we wanted to demo but did not have enough time to include in the session. Enjoy!" + ] + }, + { + "cell_type": "markdown", + "id": "6bbc79d5-86b4-4b2b-b924-e458375e090a", + "metadata": {}, + "source": [ + "# ipyleaflet: Interactive maps\n", + "\n", + "## A Jupyter - LeafletJS bridge\n", + "\n", + "## https://github.com/jupyter-widgets/ipyleaflet\n", + "\n", + "\n", + "ipyleaflet is a jupyter interactive widget library which provides interactive maps to the Jupyter notebook.\n", + "\n", + "- MIT Licensed\n", + "\n", + "**Installation:**\n", + "\n", + "```bash\n", + "conda install -c conda-forge ipyleaflet\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c77c85c9-6d99-475c-a9a2-e2c190ba4122", + "metadata": {}, + "outputs": [], + "source": [ + "from ipywidgets import Text, HTML, HBox\n", + "from ipyleaflet import GeoJSON, WidgetControl, Map \n", + "import json" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "54c3506c-2ac0-4319-bfcc-e017f0885295", + "metadata": {}, + "outputs": [], + "source": [ + "m = Map(center = (43,-100), zoom = 4)\n", + "\n", + "geo_json_data = json.load(open('us-states-density-colored.json'))\n", + "geojson = GeoJSON(data=geo_json_data, hover_style={'color': 'black', 'dashArray': '5, 5', 'weight': 2})\n", + "m.add_layer(geojson)\n", + "\n", + "html = HTML('''\n", + "

US population density

\n", + " Hover over a state\n", + "''')\n", + "html.layout.margin = '0px 20px 20px 20px'\n", + "control = WidgetControl(widget=html, position='topright')\n", + "m.add_control(control)\n", + "\n", + "def update_html(properties, **kwargs):\n", + " html.value = '''\n", + "

US population density

\n", + "

{}

\n", + " {} people / mi^2\n", + " '''.format(properties['name'], properties['density'])\n", + "\n", + "geojson.on_hover(update_html)\n", + "\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "9bfcd179-0463-4b07-9bce-f7ba298ed3de", + "metadata": {}, + "source": [ + "# pythreejs: 3D rendering in the browser \n", + "\n", + "## A Jupyter - threejs bridge\n", + "\n", + "## https://github.com/jupyter-widgets/pythreejs\n", + "\n", + "\n", + "Pythreejs is a jupyter interactive widget bringing fast WebGL 3d visualization to the Jupyter notebook.\n", + "\n", + "- Originally authored by Jason Grout, currently maintained by Vidar Tonaas Fauske\n", + "- BSD Licensed\n", + "\n", + "Pythreejs is *not* a 3d plotting library, it only exposes the threejs scene objects to the Jupyter kernel.\n", + "\n", + "**Installation:**\n", + "\n", + "```bash\n", + "conda install -c conda-forge pythreejs\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "989097a4-302f-4092-a784-814282b5c366", + "metadata": {}, + "outputs": [], + "source": [ + "from pythreejs import *\n", + "import numpy as np\n", + "from IPython.display import display\n", + "from ipywidgets import HTML, Text, Output, VBox\n", + "from traitlets import link, dlink" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "07bb1212-d30f-4b22-a1e9-75ba63c449cc", + "metadata": {}, + "outputs": [], + "source": [ + "# Generate surface data:\n", + "view_width = 600\n", + "view_height = 400\n", + "nx, ny = (20, 20)\n", + "xmax=1\n", + "x = np.linspace(-xmax, xmax, nx)\n", + "y = np.linspace(-xmax, xmax, ny)\n", + "xx, yy = np.meshgrid(x, y)\n", + "z = xx ** 2 - yy ** 2\n", + "#z[6,1] = float('nan')\n", + "\n", + "\n", + "# Generate scene objects from data:\n", + "surf_g = SurfaceGeometry(z=list(z[::-1].flat), \n", + " width=2 * xmax,\n", + " height=2 * xmax,\n", + " width_segments=nx - 1,\n", + " height_segments=ny - 1)\n", + "\n", + "surf = Mesh(geometry=surf_g,\n", + " material=MeshLambertMaterial(map=height_texture(z[::-1], 'YlGnBu_r')))\n", + "\n", + "surfgrid = SurfaceGrid(geometry=surf_g, material=LineBasicMaterial(color='black'),\n", + " position=[0, 0, 1e-2]) # Avoid overlap by lifting grid slightly\n", + "\n", + "# Set up picking bojects:\n", + "hover_point = Mesh(geometry=SphereGeometry(radius=0.05),\n", + " material=MeshLambertMaterial(color='green'))\n", + "\n", + "click_picker = Picker(controlling=surf, event='dblclick')\n", + "hover_picker = Picker(controlling=surf, event='mousemove')\n", + "\n", + "# Set up scene:\n", + "key_light = DirectionalLight(color='white', position=[3, 5, 1], intensity=0.4)\n", + "c = PerspectiveCamera(position=[0, 3, 3], up=[0, 0, 1], aspect=view_width / view_height,\n", + " children=[key_light])\n", + "\n", + "scene = Scene(children=[surf, c, surfgrid, hover_point, AmbientLight(intensity=0.8)])\n", + "\n", + "renderer = Renderer(camera=c, scene=scene,\n", + " width=view_width, height=view_height,\n", + " controls=[OrbitControls(controlling=c), click_picker, hover_picker])\n", + "\n", + "\n", + "# Set up picking responses:\n", + "# Add a new marker when double-clicking:\n", + "out = Output()\n", + "def f(change):\n", + " value = change['new']\n", + " with out:\n", + " print('Clicked on %s' % (value,))\n", + " point = Mesh(geometry=SphereGeometry(radius=0.05), \n", + " material=MeshLambertMaterial(color='hotpink'),\n", + " position=value)\n", + " scene.add(point)\n", + "\n", + "click_picker.observe(f, names=['point'])\n", + "\n", + "# Have marker follow picker point:\n", + "link((hover_point, 'position'), (hover_picker, 'point'))\n", + "\n", + "# Show picker point coordinates as a label:\n", + "h = HTML()\n", + "def g(change):\n", + " h.value = 'Green point at (%.3f, %.3f, %.3f)' % tuple(change['new'])\n", + " h.value += ' Double-click to add marker'\n", + "g({'new': hover_point.position})\n", + "hover_picker.observe(g, names=['point'])\n", + "\n", + "display(VBox([h, renderer, out]))" + ] + }, + { + "cell_type": "markdown", + "id": "228aa568-3b3b-4901-9700-b6a865e474a1", + "metadata": {}, + "source": [ + "# bqplot: complex interactive visualizations\n", + "\n", + "## https://github.com/bloomberg/bqplot\n", + "\n", + "## A Jupyter - d3.js bridge\n", + "\n", + "bqplot is a jupyter interactive widget library bringing d3.js visualization to the Jupyter notebook.\n", + "\n", + "- Apache Licensed\n", + "\n", + "bqplot implements the abstractions of Wilkinson’s “The Grammar of Graphics” as interactive Jupyter widgets.\n", + "\n", + "bqplot provides both\n", + "-\thigh-level plotting procedures with relevant defaults for common chart types,\n", + "-\tlower-level descriptions of data visualizations meant for complex interactive visualization dashboards and applications involving mouse interactions and user-provided Python callbacks.\n", + "\n", + "**Installation:**\n", + "\n", + "```bash\n", + "conda install -c conda-forge bqplot\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e406ea84-67fe-4137-9b26-cf4cbdb4e751", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import bqplot as bq" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "625bd9df-8661-4267-aa34-3c758e04be21", + "metadata": {}, + "outputs": [], + "source": [ + "xs = bq.LinearScale()\n", + "ys = bq.LinearScale()\n", + "x = np.arange(100)\n", + "y = np.cumsum(np.random.randn(2, 100), axis=1) #two random walks\n", + "\n", + "line = bq.Lines(x=x, y=y, scales={'x': xs, 'y': ys}, colors=['red', 'green'])\n", + "xax = bq.Axis(scale=xs, label='x', grid_lines='solid')\n", + "yax = bq.Axis(scale=ys, orientation='vertical', tick_format='0.2f', label='y', grid_lines='solid')\n", + "\n", + "fig = bq.Figure(marks=[line], axes=[xax, yax], animation_duration=1000)\n", + "display(fig)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "94ac959d-76d1-4712-914c-bcb931d04e93", + "metadata": {}, + "outputs": [], + "source": [ + "# update data of the line mark\n", + "line.y = np.cumsum(np.random.randn(2, 100), axis=1)" + ] + }, + { + "cell_type": "markdown", + "id": "4ce97fcb-e621-4b0e-b826-d49c04146f51", + "metadata": {}, + "source": [ + "# ipympl: The Matplotlib Jupyter Widget Backend\n", + "\n", + "## https://github.com/matplotlib/ipympl\n", + "\n", + "\n", + "Enabling interaction with matplotlib charts in the Jupyter notebook and JupyterLab\n", + "\n", + "- BSD-3-Clause\n", + "\n", + "**Installation:**\n", + "\n", + "```bash\n", + "conda install -c conda-forge ipympl\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "91a33e30-803d-4945-8129-2c37f30a1d09", + "metadata": {}, + "source": [ + "Enabling the `widget` backend. This requires ipympl. ipympl can be install via pip or conda." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6b157ee7-4008-492d-8045-f93b747af703", + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib widget" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "152cba47-06f1-4896-b15a-b3ed960cafd3", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "from ipywidgets import VBox, FloatSlider" + ] + }, + { + "cell_type": "markdown", + "id": "fc9dca28-883c-4286-af3d-a17081b089d6", + "metadata": {}, + "source": [ + "When using the `widget` backend from ipympl, fig.canvas is a proper Jupyter interactive widget, which can be embedded in Layout classes like HBox and Vbox.\n", + "\n", + "One can bound figure attributes to other widget values." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9db5b3e0-317c-4b79-bb5c-36786d02895a", + "metadata": {}, + "outputs": [], + "source": [ + "plt.ioff()\n", + "plt.clf()\n", + "\n", + "slider = FloatSlider(\n", + " value=1.0,\n", + " min=0.02,\n", + " max=2.0\n", + ")\n", + "\n", + "fig1 = plt.figure(1)\n", + "\n", + "x1 = np.linspace(0, 20, 500)\n", + "\n", + "lines = plt.plot(x1, np.sin(slider.value * x1))\n", + "\n", + "def update_lines(change):\n", + " lines[0].set_data(x1, np.sin(change.new * x1))\n", + " fig1.canvas.draw()\n", + " fig1.canvas.flush_events()\n", + "\n", + "slider.observe(update_lines, names='value')\n", + "\n", + "VBox([slider, fig1.canvas])" + ] + }, + { + "cell_type": "markdown", + "id": "24389d91-db96-4591-a279-9dde81b9c8ef", + "metadata": {}, + "source": [ + "# ipytree: Interactive tree view based on ipywidgets\n", + "\n", + "## https://github.com/QuantStack/ipytree/\n", + "\n", + "\n", + "ipytree is a jupyter interactive widget library which provides a tree widget to the Jupyter notebook.\n", + "\n", + "- MIT Licensed\n", + "\n", + "**Installation:**\n", + "\n", + "```bash\n", + "conda install -c conda-forge ipytree\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "fa20469b-b9b6-46bc-99f0-e85c313db971", + "metadata": {}, + "source": [ + "## Create a tree" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c3b13d81-455d-438c-a843-f31421db0fc1", + "metadata": {}, + "outputs": [], + "source": [ + "from ipywidgets import Text, link\n", + "from ipytree import Tree, Node" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5461f21f-e96e-4877-8f4c-bc1bc5f572e2", + "metadata": {}, + "outputs": [], + "source": [ + "tree = Tree()\n", + "tree.add_node(Node('node1'))\n", + "\n", + "node2 = Node('node2')\n", + "tree.add_node(node2)\n", + "\n", + "tree" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6059b01a-8c08-492a-834b-450905e5c3dd", + "metadata": {}, + "outputs": [], + "source": [ + "node3 = Node('node3', disabled=True)\n", + "node4 = Node('node4')\n", + "node5 = Node('node5', [Node('1'), Node('2')])\n", + "node2.add_node(node3)\n", + "node2.add_node(node4)\n", + "node2.add_node(node5)" ] } ], From c79281e5791ea586bf91e0a4b6fa7740e30f803f Mon Sep 17 00:00:00 2001 From: Itay Dafna Date: Fri, 9 Jul 2021 10:53:22 -0700 Subject: [PATCH 8/8] Refactor more widget libraries folder structure Signed-off-by: Itay Dafna --- ...toscape.ipynb => 07.02-ipycytoscape.ipynb} | 0 .../07.More-libraries/07.03-bqplot.ipynb | 525 ------------------ .../07.03-ipydatagrid.ipynb | 0 ...7.06-ipygany.ipynb => 07.04-ipygany.ipynb} | 0 .../07.More-libraries/07.04-ipyvolume.ipynb | 232 -------- .../07.05-other-widget-libraries.ipynb} | 0 .../{widgets_libraries => extras}/PyWWT.ipynb | 0 .../bqplot.ipynb} | 0 .../bqplot_A_Penalized_regression.ipynb | 0 ...plot_A_plot_as_a_control_in_a_widget.ipynb | 0 .../extra_examples/flight_sim.ipynb | 0 .../{ => extras}/extra_examples/vaex.ipynb | 0 .../ipyleaflet.ipynb} | 0 .../ipympl.ipynb | 0 .../ipytree.ipynb | 0 .../ipyvolume.ipynb} | 0 .../ipyvuetify.ipynb | 0 .../ipywebrtc.ipynb | 0 .../pythreejs.ipynb} | 0 .../widgets_libraries/07.02-pythreejs.ipynb | 0 20 files changed, 757 deletions(-) rename notebooks/07.More-libraries/{07.05-ipycytoscape.ipynb => 07.02-ipycytoscape.ipynb} (100%) delete mode 100644 notebooks/07.More-libraries/07.03-bqplot.ipynb rename notebooks/{ => 07.More-libraries}/07.03-ipydatagrid.ipynb (100%) rename notebooks/07.More-libraries/{07.06-ipygany.ipynb => 07.04-ipygany.ipynb} (100%) delete mode 100644 notebooks/07.More-libraries/07.04-ipyvolume.ipynb rename notebooks/{07.09-other-widget-libraries.ipynb => 07.More-libraries/07.05-other-widget-libraries.ipynb} (100%) rename notebooks/{widgets_libraries => extras}/PyWWT.ipynb (100%) rename notebooks/{widgets_libraries/07.03-bqplot.ipynb => extras/bqplot.ipynb} (100%) rename notebooks/{ => extras}/extra_examples/bqplot_A_Penalized_regression.ipynb (100%) rename notebooks/{ => extras}/extra_examples/bqplot_A_plot_as_a_control_in_a_widget.ipynb (100%) rename notebooks/{ => extras}/extra_examples/flight_sim.ipynb (100%) rename notebooks/{ => extras}/extra_examples/vaex.ipynb (100%) rename notebooks/{widgets_libraries/07.01-ipyleaflet.ipynb => extras/ipyleaflet.ipynb} (100%) rename notebooks/{widgets_libraries => extras}/ipympl.ipynb (100%) rename notebooks/{widgets_libraries => extras}/ipytree.ipynb (100%) rename notebooks/{widgets_libraries/07.xx-ipyvolume.ipynb => extras/ipyvolume.ipynb} (100%) rename notebooks/{widgets_libraries => extras}/ipyvuetify.ipynb (100%) rename notebooks/{widgets_libraries => extras}/ipywebrtc.ipynb (100%) rename notebooks/{07.More-libraries/07.02-pythreejs.ipynb => extras/pythreejs.ipynb} (100%) delete mode 100644 notebooks/widgets_libraries/07.02-pythreejs.ipynb diff --git a/notebooks/07.More-libraries/07.05-ipycytoscape.ipynb b/notebooks/07.More-libraries/07.02-ipycytoscape.ipynb similarity index 100% rename from notebooks/07.More-libraries/07.05-ipycytoscape.ipynb rename to notebooks/07.More-libraries/07.02-ipycytoscape.ipynb diff --git a/notebooks/07.More-libraries/07.03-bqplot.ipynb b/notebooks/07.More-libraries/07.03-bqplot.ipynb deleted file mode 100644 index f17816a9..00000000 --- a/notebooks/07.More-libraries/07.03-bqplot.ipynb +++ /dev/null @@ -1,525 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "< [pythreejs: 3D rendering in the browser](07.02-pythreejs.ipynb) | [Contents](00.00-index.ipynb) | [ipyvolume: 3D plotting in the notebook](07.04-ipyvolume.ipynb) >" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# bqplot: complex interactive visualizations\n", - "\n", - "## https://github.com/bloomberg/bqplot\n", - "\n", - "## A Jupyter - d3.js bridge\n", - "\n", - "bqplot is a jupyter interactive widget library bringing d3.js visualization to the Jupyter notebook.\n", - "\n", - "- Apache Licensed\n", - "\n", - "bqplot implements the abstractions of Wilkinson’s “The Grammar of Graphics” as interactive Jupyter widgets.\n", - "\n", - "bqplot provides both\n", - "-\thigh-level plotting procedures with relevant defaults for common chart types,\n", - "-\tlower-level descriptions of data visualizations meant for complex interactive visualization dashboards and applications involving mouse interactions and user-provided Python callbacks.\n", - "\n", - "**Installation:**\n", - "\n", - "```bash\n", - "conda install -c conda-forge bqplot\n", - "```" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from __future__ import print_function\n", - "from IPython.display import display\n", - "from ipywidgets import *\n", - "from traitlets import *\n", - "\n", - "import numpy as np\n", - "import pandas as pd\n", - "import bqplot as bq\n", - "import datetime as dt" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "np.random.seed(0)\n", - "size = 100\n", - "y_data = np.cumsum(np.random.randn(size) * 100.0)\n", - "y_data_2 = np.cumsum(np.random.randn(size))\n", - "y_data_3 = np.cumsum(np.random.randn(size) * 100.)\n", - "\n", - "x = np.linspace(0.0, 10.0, size)\n", - "\n", - "price_data = pd.DataFrame(np.cumsum(np.random.randn(150, 2).dot([[0.5, 0.8], [0.8, 1.0]]), axis=0) + 100,\n", - " columns=['Security 1', 'Security 2'],\n", - " index=pd.date_range(start='01-01-2007', periods=150))\n", - "\n", - "symbol = 'Security 1'\n", - "dates_all = price_data.index.values\n", - "final_prices = price_data[symbol].values.flatten()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# A simple plot with the pyplot API" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from bqplot import pyplot as plt" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "plt.figure(1)\n", - "n = 100\n", - "plt.plot(np.linspace(0.0, 10.0, n), np.cumsum(np.random.randn(n)), \n", - " axes_options={'y': {'grid_lines': 'dashed'}})\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Scatter Plot" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "plt.figure(title='Scatter Plot with colors')\n", - "plt.scatter(y_data_2, y_data_3, color=y_data)\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Histogram" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "plt.figure()\n", - "plt.hist(y_data, colors=['OrangeRed'])\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Every component of the figure is an independent widget" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "xs = bq.LinearScale()\n", - "ys = bq.LinearScale()\n", - "x = np.arange(100)\n", - "y = np.cumsum(np.random.randn(2, 100), axis=1) #two random walks\n", - "\n", - "line = bq.Lines(x=x, y=y, scales={'x': xs, 'y': ys}, colors=['red', 'green'])\n", - "xax = bq.Axis(scale=xs, label='x', grid_lines='solid')\n", - "yax = bq.Axis(scale=ys, orientation='vertical', tick_format='0.2f', label='y', grid_lines='solid')\n", - "\n", - "fig = bq.Figure(marks=[line], axes=[xax, yax], animation_duration=1000)\n", - "display(fig)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# update data of the line mark\n", - "line.y = np.cumsum(np.random.randn(2, 100), axis=1)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "xs = bq.LinearScale()\n", - "ys = bq.LinearScale()\n", - "x, y = np.random.rand(2, 20)\n", - "scatt = bq.Scatter(x=x, y=y, scales={'x': xs, 'y': ys}, default_colors=['blue'])\n", - "xax = bq.Axis(scale=xs, label='x', grid_lines='solid')\n", - "yax = bq.Axis(scale=ys, orientation='vertical', tick_format='0.2f', label='y', grid_lines='solid')\n", - "\n", - "fig = bq.Figure(marks=[scatt], axes=[xax, yax], animation_duration=1000)\n", - "display(fig)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#data updates\n", - "scatt.x = np.random.rand(20) * 10\n", - "scatt.y = np.random.rand(20)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## The same holds for the attributes of scales, axes" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "xs.min = 4" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "xs.min = None" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "xax.label = 'Some label for the x axis'" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Use bqplot figures as input widgets" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "xs = bq.LinearScale()\n", - "ys = bq.LinearScale()\n", - "x = np.arange(100)\n", - "y = np.cumsum(np.random.randn(2, 100), axis=1) #two random walks\n", - "\n", - "line = bq.Lines(x=x, y=y, scales={'x': xs, 'y': ys}, colors=['red', 'green'])\n", - "xax = bq.Axis(scale=xs, label='x', grid_lines='solid')\n", - "yax = bq.Axis(scale=ys, orientation='vertical', tick_format='0.2f', label='y', grid_lines='solid')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Selections" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def interval_change_callback(change):\n", - " db.value = str(change['new'])\n", - "\n", - "intsel = bq.interacts.FastIntervalSelector(scale=xs, marks=[line])\n", - "intsel.observe(interval_change_callback, names=['selected'] )\n", - "\n", - "db = widgets.Label()\n", - "db.value = str(intsel.selected)\n", - "display(db)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fig = bq.Figure(marks=[line], axes=[xax, yax], animation_duration=1000, interaction=intsel)\n", - "display(fig)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "line.selected" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Handdraw" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "handdraw = bq.interacts.HandDraw(lines=line)\n", - "fig.interaction = handdraw" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "line.y[0]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Moving points around" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from bqplot import (LinearScale, Scatter, Label, Axis, Figure, Lines)\n", - "import numpy as np\n", - "\n", - "size = 100\n", - "np.random.seed(0)\n", - "x_data = range(size)\n", - "y_data = np.cumsum(np.random.randn(size) * 100.0)\n", - "\n", - "## Enabling moving of points in scatter. Try to click and drag any of the points in the scatter and \n", - "## notice the line representing the mean of the data update\n", - "\n", - "sc_x = LinearScale()\n", - "sc_y = LinearScale()\n", - "\n", - "scat = Scatter(x=x_data[:10], y=y_data[:10], scales={'x': sc_x, 'y': sc_y}, default_colors=['blue'],\n", - " enable_move=True)\n", - "lin = Lines(scales={'x': sc_x, 'y': sc_y}, stroke_width=4, line_style='dashed', colors=['orange'])\n", - "m = Label(x=[0.05], y=[0.9], text=[\"\"], colors=[\"black\"])\n", - "\n", - "def update_line(change):\n", - " with lin.hold_sync():\n", - " lin.x = [np.min(scat.x), np.max(scat.x)]\n", - " lin.y = [np.mean(scat.y), np.mean(scat.y)]\n", - " m.text=['Mean is %s'%np.mean(scat.y)]\n", - " \n", - "\n", - "update_line(None)\n", - "\n", - "# update line on change of x or y of scatter\n", - "scat.observe(update_line, names='x')\n", - "scat.observe(update_line, names='y')\n", - "\n", - "ax_x = Axis(scale=sc_x)\n", - "ax_y = Axis(scale=sc_y, tick_format='0.2f', orientation='vertical')\n", - "\n", - "fig = Figure(marks=[scat, lin, m], axes=[ax_x, ax_y])\n", - "\n", - "## In this case on drag, the line updates as you move the points.\n", - "with scat.hold_sync():\n", - " scat.enable_move = True\n", - " scat.update_on_move = True\n", - " scat.enable_add = False\n", - "\n", - "display(fig)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Exercises" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 1) Create a line chart using the object model (use x_data and y_data as your data attributes)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 2) Update the data of the Line mark, and change its color to 'darkorange'" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "< [pythreejs: 3D rendering in the browser](07.02-pythreejs.ipynb) | [Contents](00.00-index.ipynb) | [ipyvolume: 3D plotting in the notebook](07.04-ipyvolume.ipynb) >" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "widgets-tutorial", - "language": "python", - "name": "widgets-tutorial" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.3" - }, - "widgets": { - "state": { - "0ba98b0561564e5987dba19d1b574c04": { - "views": [ - { - "cell_index": 29 - } - ] - }, - "1ffa1ac6658e4eef89e45cf62daae339": { - "views": [ - { - "cell_index": 30 - } - ] - }, - "42735872becb4c43b817ccff90973d63": { - "views": [ - { - "cell_index": 15 - } - ] - }, - "4b9a5b18593545faba761a719b2e6039": { - "views": [ - { - "cell_index": 17 - } - ] - }, - "7fb14b25d15240ec820c565619fe4f11": { - "views": [ - { - "cell_index": 7 - } - ] - }, - "99604f1b70c54e19a508c95d705ce488": { - "views": [ - { - "cell_index": 9 - } - ] - }, - "bf805af773d94496888afbe9e2bd3d37": { - "views": [ - { - "cell_index": 13 - } - ] - }, - "dc1b84a0e5fa4ed5a42454cfc52c44f5": { - "views": [ - { - "cell_index": 25 - } - ] - }, - "f30275bcf69e426c9d45a525833198d0": { - "views": [ - { - "cell_index": 5 - } - ] - } - }, - "version": "2.0.0-dev" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/notebooks/07.03-ipydatagrid.ipynb b/notebooks/07.More-libraries/07.03-ipydatagrid.ipynb similarity index 100% rename from notebooks/07.03-ipydatagrid.ipynb rename to notebooks/07.More-libraries/07.03-ipydatagrid.ipynb diff --git a/notebooks/07.More-libraries/07.06-ipygany.ipynb b/notebooks/07.More-libraries/07.04-ipygany.ipynb similarity index 100% rename from notebooks/07.More-libraries/07.06-ipygany.ipynb rename to notebooks/07.More-libraries/07.04-ipygany.ipynb diff --git a/notebooks/07.More-libraries/07.04-ipyvolume.ipynb b/notebooks/07.More-libraries/07.04-ipyvolume.ipynb deleted file mode 100644 index 53d3e9ef..00000000 --- a/notebooks/07.More-libraries/07.04-ipyvolume.ipynb +++ /dev/null @@ -1,232 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "< [bqplot: complex interactive visualizations](07.03-bqplot.ipynb) | [Contents](00.00-index.ipynb) | [Dashboarding with widgets](08.00-voila.ipynb) >" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# ipyvolume: 3D plotting in the notebook\n", - "\n", - "## https://github.com/maartenbreddels/ipyvolume\n", - "\n", - "IPyvolume is a Python library to visualize 3d volumes and glyphs (e.g. 3d scatter plots), in the Jupyter notebook, with minimal configuration and effort. It is currently pre-1.0, so use at own risk. IPyvolume’s volshow is to 3d arrays what matplotlib’s imshow is to 2d arrays.\n", - "\n", - "- MIT Licensed\n", - "\n", - "By Maarten Breddels\n", - "\n", - "**Installation:**\n", - "\n", - "```bash\n", - "conda install -c conda-forge ipyvolume\n", - "```" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 3-D Scatter Plots" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import ipyvolume as ipv\n", - "import numpy as np\n", - "import ipywidgets as widgets" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "x, y, z = np.random.random((3, 10000))\n", - "ipv.figure()\n", - "scatter = ipv.scatter(x, y, z, size=1, marker=\"sphere\")\n", - "ipv.show()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "ipv.save('standalone.html')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Open the HTML file from the file browser" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "x, y, z, u, v, w = np.random.random((6, 1000))*2-1\n", - "selected = np.random.randint(0, 1000, 100)\n", - "fig = ipv.figure()\n", - "quiver = ipv.quiver(x, y, z, u, v, w, size=5, size_selected=8, selected=selected)\n", - "ipv.show()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "size = widgets.FloatSlider(min=0, max=30, step=0.1)\n", - "size_selected = widgets.FloatSlider(min=0, max=30, step=0.1)\n", - "color = widgets.ColorPicker()\n", - "color_selected = widgets.ColorPicker()\n", - "widgets.jslink((quiver, 'size'), (size, 'value'))\n", - "widgets.jslink((quiver, 'size_selected'), (size_selected, 'value'))\n", - "widgets.jslink((quiver, 'color'), (color, 'value'))\n", - "widgets.jslink((quiver, 'color_selected'), (color_selected, 'value'))\n", - "widgets.VBox([size, size_selected, color, color_selected])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Animations" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# create 2d grids: x, y, and r\n", - "u = np.linspace(-10, 10, 25)\n", - "x, y = np.meshgrid(u, u)\n", - "r = np.sqrt(x**2+y**2)\n", - "print(\"x,y and z are of shape\", x.shape)\n", - "# and turn them into 1d\n", - "x = x.flatten()\n", - "y = y.flatten()\n", - "r = r.flatten()\n", - "print(\"and flattened of shape\", x.shape)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# create a sequence of 15 time elements\n", - "time = np.linspace(0, np.pi*2, 15)\n", - "z = np.array([(np.cos(r + t) * np.exp(-r/5)) for t in time])\n", - "print(\"z is of shape\", z.shape)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# draw the scatter plot, and add controls with animate_glyphs\n", - "ipv.figure()\n", - "s = ipv.scatter(x, z, y, marker=\"sphere\")\n", - "ipv.animation_control(s, interval=200)\n", - "ipv.ylim(-3,3)\n", - "ipv.show()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Now also include, color, which containts rgb values\n", - "color = np.array([[np.cos(r + t), 1-np.abs(z[i]), 0.1+z[i]*0] for i, t in enumerate(time)])\n", - "size = (z+1)\n", - "print(\"color is of shape\", color.shape)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "color = np.transpose(color, (0, 2, 1)) # flip the last axes" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "ipv.figure()\n", - "s = ipv.scatter(x, z, y, color=color, size=size, marker=\"sphere\")\n", - "ipv.animation_control(s, interval=200)\n", - "ipv.ylim(-3, 3)\n", - "ipv.show()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "< [bqplot: complex interactive visualizations](07.03-bqplot.ipynb) | [Contents](00.00-index.ipynb) | [Dashboarding with widgets](08.00-voila.ipynb) >" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "widgets-tutorial", - "language": "python", - "name": "widgets-tutorial" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.3" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/notebooks/07.09-other-widget-libraries.ipynb b/notebooks/07.More-libraries/07.05-other-widget-libraries.ipynb similarity index 100% rename from notebooks/07.09-other-widget-libraries.ipynb rename to notebooks/07.More-libraries/07.05-other-widget-libraries.ipynb diff --git a/notebooks/widgets_libraries/PyWWT.ipynb b/notebooks/extras/PyWWT.ipynb similarity index 100% rename from notebooks/widgets_libraries/PyWWT.ipynb rename to notebooks/extras/PyWWT.ipynb diff --git a/notebooks/widgets_libraries/07.03-bqplot.ipynb b/notebooks/extras/bqplot.ipynb similarity index 100% rename from notebooks/widgets_libraries/07.03-bqplot.ipynb rename to notebooks/extras/bqplot.ipynb diff --git a/notebooks/extra_examples/bqplot_A_Penalized_regression.ipynb b/notebooks/extras/extra_examples/bqplot_A_Penalized_regression.ipynb similarity index 100% rename from notebooks/extra_examples/bqplot_A_Penalized_regression.ipynb rename to notebooks/extras/extra_examples/bqplot_A_Penalized_regression.ipynb diff --git a/notebooks/extra_examples/bqplot_A_plot_as_a_control_in_a_widget.ipynb b/notebooks/extras/extra_examples/bqplot_A_plot_as_a_control_in_a_widget.ipynb similarity index 100% rename from notebooks/extra_examples/bqplot_A_plot_as_a_control_in_a_widget.ipynb rename to notebooks/extras/extra_examples/bqplot_A_plot_as_a_control_in_a_widget.ipynb diff --git a/notebooks/extra_examples/flight_sim.ipynb b/notebooks/extras/extra_examples/flight_sim.ipynb similarity index 100% rename from notebooks/extra_examples/flight_sim.ipynb rename to notebooks/extras/extra_examples/flight_sim.ipynb diff --git a/notebooks/extra_examples/vaex.ipynb b/notebooks/extras/extra_examples/vaex.ipynb similarity index 100% rename from notebooks/extra_examples/vaex.ipynb rename to notebooks/extras/extra_examples/vaex.ipynb diff --git a/notebooks/widgets_libraries/07.01-ipyleaflet.ipynb b/notebooks/extras/ipyleaflet.ipynb similarity index 100% rename from notebooks/widgets_libraries/07.01-ipyleaflet.ipynb rename to notebooks/extras/ipyleaflet.ipynb diff --git a/notebooks/widgets_libraries/ipympl.ipynb b/notebooks/extras/ipympl.ipynb similarity index 100% rename from notebooks/widgets_libraries/ipympl.ipynb rename to notebooks/extras/ipympl.ipynb diff --git a/notebooks/widgets_libraries/ipytree.ipynb b/notebooks/extras/ipytree.ipynb similarity index 100% rename from notebooks/widgets_libraries/ipytree.ipynb rename to notebooks/extras/ipytree.ipynb diff --git a/notebooks/widgets_libraries/07.xx-ipyvolume.ipynb b/notebooks/extras/ipyvolume.ipynb similarity index 100% rename from notebooks/widgets_libraries/07.xx-ipyvolume.ipynb rename to notebooks/extras/ipyvolume.ipynb diff --git a/notebooks/widgets_libraries/ipyvuetify.ipynb b/notebooks/extras/ipyvuetify.ipynb similarity index 100% rename from notebooks/widgets_libraries/ipyvuetify.ipynb rename to notebooks/extras/ipyvuetify.ipynb diff --git a/notebooks/widgets_libraries/ipywebrtc.ipynb b/notebooks/extras/ipywebrtc.ipynb similarity index 100% rename from notebooks/widgets_libraries/ipywebrtc.ipynb rename to notebooks/extras/ipywebrtc.ipynb diff --git a/notebooks/07.More-libraries/07.02-pythreejs.ipynb b/notebooks/extras/pythreejs.ipynb similarity index 100% rename from notebooks/07.More-libraries/07.02-pythreejs.ipynb rename to notebooks/extras/pythreejs.ipynb diff --git a/notebooks/widgets_libraries/07.02-pythreejs.ipynb b/notebooks/widgets_libraries/07.02-pythreejs.ipynb deleted file mode 100644 index e69de29b..00000000