{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Interactive Tables and their API\n", "\n", "The table UI allows column drag/drop, hide, sorting, formatting, searching, selecting/export as CSV. This makes it easy to paste into a spreadsheet like Excel.\n", "\n", "There is a menu in the top-left for the whole table, and each column has a menu that appears on hover.\n", "\n", "There are also keyboard commands: digits change the precision of all columns, shift-digit changes the precision of the current column. Arrow keys navigate. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "new TableDisplay( new CSV().read(\"../resources/data/interest-rates.csv\"))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import com.twosigma.beakerx.table.*\n", "import com.twosigma.beakerx.table.format.TableDisplayStringFormat\n", "\n", "display = new TableDisplay(new CSV().read(\"../resources/data/interest-rates.csv\"))\n", "//show all time columns in days\n", "display.setStringFormatForTimes(TimeUnit.DAYS)\n", "//min 4, max 6 decimal places for all doubles\n", "display.setStringFormatForType(ColumnType.Double, TableDisplayStringFormat.getDecimalFormat(4,6))\n", "//setting for a column takes precidence over the type\n", "display.setStringFormatForColumn(\"m3\", TableDisplayStringFormat.getDecimalFormat(0, 0))\n", "//set the alignment\n", "display.setAlignmentProviderForType(ColumnType.Double, TableDisplayAlignmentProvider.RIGHT_ALIGNMENT)\n", "display.setAlignmentProviderForColumn('m3', TableDisplayAlignmentProvider.CENTER_ALIGNMENT)\n", "\n", "//using a closure\n", "display.setStringFormatForColumn(\"y3\") { value, row, col, tableDisplay ->\n", " if(value < 8) {\n", " \":(\"\n", " } else {\n", " \":)\"\n", " } \n", "}\n", "\n", "display" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This changes the format of the table above in the previous output cell. It's updated because the object is synchronized between the kernel and the client." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "display.setStringFormatForTimes(TimeUnit.HOURS)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import com.twosigma.beakerx.table.*\n", "import com.twosigma.beakerx.table.renderer.TableDisplayCellRenderer\n", "\n", "def display2 = new TableDisplay(new CSV().read(\"../resources/data/interest-rates.csv\"))\n", "//right now, the only renderer option is for data bars\n", "display2.setRendererForType(ColumnType.Double, TableDisplayCellRenderer.getDataBarsRenderer())\n", "//use the false parameter to hide the String value\n", "display2.setRendererForColumn(\"y10\", TableDisplayCellRenderer.getDataBarsRenderer(false))\n", "display2" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import com.twosigma.beakerx.table.*\n", "import com.twosigma.beakerx.fileloader.CSV\n", "import com.twosigma.beakerx.table.format.TableDisplayStringFormat\n", "\n", "def display3 = new TableDisplay(new CSV().read(\"../resources/data/interest-rates.csv\"))\n", "display3.setStringFormatForType(ColumnType.Double, TableDisplayStringFormat.getDecimalFormat(9,9))\n", "//freeze a column\n", "display3.setColumnFrozen(\"y1\", true)\n", "//freeze a column to the right\n", "display3.setColumnFrozenRight(\"y10\", true)\n", "//hide a column\n", "display3.setColumnVisible(\"y30\", false)\n", "\n", "//explicitly set column order/visiblity\n", "display3.setColumnOrder([\"m3\", \"y1\", \"y5\", \"time\", \"y2\"]) //Columns in the list will be shown in the provided order. Columns not in the list will be hidden.\n", "display3" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import com.twosigma.beakerx.table.*\n", "import com.twosigma.beakerx.table.highlight.TableDisplayCellHighlighter\n", "\n", "def display4 = new TableDisplay(new CSV().read(\"../resources/data/interest-rates.csv\"))\n", "display4.addCellHighlighter(TableDisplayCellHighlighter.getHeatmapHighlighter(\"m3\", TableDisplayCellHighlighter.FULL_ROW))\n", "\n", "//the following two overloads should also be supported\n", "//set the min and max used for calculating the color\n", "//display4.addCellHighlighter(TableDisplayCellHighlighter.getHeatmapHighlighter(\"y1\", TableDisplayCellHighlighter.FULL_ROW, 0, 5))\n", "//set the colors used for the min and max\n", "//display4.addCellHighlighter(TableDisplayCellHighlighter.getHeatmapHighlighter(\"m6\", TableDisplayCellHighlighter.SINGLE_COLUMN, null, null, Color.YELLOW, Color.BLUE))\n", "\n", "display4" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def map = [\n", " [a:1, b:2, c:3],\n", " [a:4, b:5, c:6],\n", " [a:7, b:8, c:5]\n", "]\n", "def display5 = new TableDisplay(map)\n", "display5.addCellHighlighter { row, column, tableDisplay ->\n", " if (column == 2) {\n", " display5.values[row][column] < 5 ? Color.RED : Color.GREEN\n", " }\n", "}\n", "display5" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import com.twosigma.beakerx.table.*\n", "import com.twosigma.beakerx.table.highlight.*\n", "\n", "display6 = new TableDisplay(new CSV().read(\"../resources/data/interest-rates.csv\"))\n", "display6.addCellHighlighter(TableDisplayCellHighlighter.getHeatmapHighlighter(\"m3\", 0, 8, Color.ORANGE, Color.PINK))\n", "display6.addCellHighlighter(TableDisplayCellHighlighter.getHeatmapHighlighter(\"m6\", TableDisplayCellHighlighter.SINGLE_COLUMN, 6, 8, Color.BLACK, Color.PINK))\n", "\n", "display6.addCellHighlighter(new ThreeColorHeatmapHighlighter(\"y1\", TableDisplayCellHighlighter.SINGLE_COLUMN, 4, 6, 8, new Color(247,106,106), new Color(239,218,82), new Color(100,189,122)))\n", "\n", "display6" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "display6.removeAllCellHighlighters()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import com.twosigma.beakerx.table.highlight.*\n", "\n", "def table = new TableDisplay([[1,2,3], \n", " [3,4,5], \n", " [6,2,8], \n", " [6,2,8], \n", " [6,2,8], \n", " [6,4,8], \n", " [6,2,8], \n", " [6,2,8], \n", " [6,5,8]], \n", " ['a', 'b', 'c'], \n", " ['double', 'double', 'double'])\n", "table.addCellHighlighter(TableDisplayCellHighlighter.getUniqueEntriesHighlighter(\"b\", TableDisplayCellHighlighter.FULL_ROW))\n", "table" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def mapList4 = [\n", " [a:1, b:2, c:3],\n", " [a:4, b:5, c:6],\n", " [a:7, b:8, c:5]\n", "]\n", "def display7 = new TableDisplay(mapList4)\n", "\n", "//set what happens on a double click\n", "display7.setDoubleClickAction { row, col, tableDisplay ->\n", " tableDisplay.values[row][col] = tableDisplay.values[row].sum()\n", "}\n", "//run tagged cell on action\n", "//display7.setDoubleClickAction(\"misc_formatting\");\n", "\n", "\n", "//add a context menu item\n", "display7.addContextMenuItem(\"negate\") { row, col, tableDisplay ->\n", " tableDisplay.values[row][col] = -tableDisplay.values[row][col]\n", "}\n", "\n", "//run tagged cell on action\n", "//display7.addContextMenuItem(\"negate\", \"misc_formatting\");\n", "\n", "display7" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "misc_formatting" ] }, "outputs": [], "source": [ "Math.random()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def mapList5 = [\n", " [firstCol:1, secondCol:2, thirdCol:3],\n", " [firstCol:4, secondCol:5, thirdCol:6],\n", " [firstCol:9, secondCol:8, thirdCol:9]\n", "]\n", "def td4 = new TableDisplay(mapList5)\n", "\n", "//tool tip can be set with a closure\n", "td4.setToolTip { row, col, display ->\n", " \"The value is: \" + display.values[row][col]\n", "}\n", "td4\n", "\n", "//set the font size and color\n", "td4.dataFontSize = 15\n", "td4.headerFontSize = 30\n", "\n", "def colors = [[Color.LIGHT_GRAY, Color.GRAY, Color.RED],\n", " [Color.YELLOW, Color.ORANGE, Color.RED],\n", " [Color.MAGENTA, Color.BLUE, Color.BLACK]]\n", "\n", "td4.setFontColorProvider { row, col, td ->\n", " colors[row][col]\n", "}\n", "\n", "//try different filter options\n", "td4.setRowFilter { row, model ->\n", " //model[row][1] == 8\n", " true\n", " //false\n", " //model[row][0] == model[row][2]\n", "}\n", "\n", "//set vertical headers\n", "//you can also do this in the right-click menu\n", "td4.setHeadersVertical(true)\n", "\n", "td4" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "abc = 0; // test variable\n", "mapList = [\n", " [a:1, b:2, c:3],\n", " [a:4, b:5, c:6],\n", " [a:7, b:8, c:5]\n", "]\n", "OutputCell.HIDDEN" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def display1 = new TableDisplay(mapList)\n", "//set what happens on a double click\n", "display1.setDoubleClickAction { row, col, tableDisplay ->\n", " tableDisplay.values[row][col] = tableDisplay.values[row].sum()\n", "}\n", "\n", "//add a context menu item\n", "display1.addContextMenuItem(\"negate\") { row, col, tableDisplay ->\n", " tableDisplay.values[row][col] = -tableDisplay.values[row][col]\n", "}\n", "\n", "display1" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def display2 = new TableDisplay(mapList)\n", "\n", "//run tagged cell on action\n", "display2.addContextMenuItem(\"run print cell\", \"print_cell\");\n", "display2.setDoubleClickAction(\"print_cell\");\n", "\n", "display2" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "print_cell" ] }, "outputs": [], "source": [ "abc++\n", "println abc" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## API to run cells by tag" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "beakerx.runByTag(\"print_cell\") " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def display3 = new TableDisplay(mapList)\n", "display3.setDoubleClickAction {beakerx.runByTag(\"print_cell2\")}\n", "display3.addContextMenuItem(\"print_cell2\") { beakerx.runByTag(\"print_cell2\") }\n", "display3" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "print_cell2" ] }, "outputs": [], "source": [ "abc++\n", "println abc" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Action API\n", "\n", "Bind running a cell to the context menu or double click action on the table." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "display4 = new TableDisplay(mapList)\n", "\n", "//run tagged cell on action\n", "display4.addContextMenuItem(\"run tagged_cell cell\", \"tagged_cell\");\n", "display4.setDoubleClickAction(\"tagged_cell\");\n", "\n", "display4" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "tagged_cell" ] }, "outputs": [], "source": [ "def details = display4.details\n", "\n", "if(details != null){\n", " switch(details.actionType){\n", " case 'DOUBLE_CLICK':\n", " print (\"You clicked on the cell [\" + details.row + \", \" + details.col + \"]\")\n", " break;\n", " case 'CONTEXT_MENU_CLICK':\n", " print (\"You selected context menu '\" + details.contextMenuItem + \"' on the cell [\" + details.row + \", \" + details.col + \"]\")\n", " break;\n", " }\n", "}else{\n", " println \"no table tag action performed.\"\n", "}" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "displayHtml = new TableDisplay([[col1: \"This & that\", col2: \"This / that\", col3: \"This > that\"]]);\n", "displayHtml" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Update cell" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def mapListToUpdate = [\n", " [a:1, b:2, c:3],\n", " [a:4, b:5, c:6],\n", " [a:7, b:8, c:9]\n", "]\n", "tableToUpdate = new TableDisplay(mapListToUpdate)\n", "\n", "tableToUpdate" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "tableToUpdate.values[0][0] = 99\n", "tableToUpdate.sendModel()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "tableToUpdate.updateCell(2,\"c\",121)\n", "tableToUpdate.sendModel()" ] } ], "metadata": { "anaconda-cloud": {}, "beakerx_kernel_parameters": {}, "celltoolbar": "Tags", "kernelspec": { "display_name": "Groovy", "language": "groovy", "name": "groovy" }, "language_info": { "codemirror_mode": "groovy", "file_extension": ".groovy", "mimetype": "", "name": "Groovy", "nbconverter_exporter": "", "version": "2.4.3" }, "widgets": { "state": { "f7d30807-6d2d-414d-b604-fcb0ed748612": { "views": [ { "cell_index": 0 }, { "cell_index": 1 } ] } }, "version": "1.2.0" } }, "nbformat": 4, "nbformat_minor": 2 }