{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Interactive Time Series Plotting" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "BeakerX comes with its own charting library for creating interactive plots that you can click on, drag, zoom, and annotate. Right-click brings up a menu allowing export to SVG and PNG.\n", "\n", "You can access it from any language, but the most complete documentation is in Groovy.\n", "\n", "This tutorial shows you how to use and how to interact with it, with [step-by-step examples](plotDemo.ipynb)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Custom Plot Example" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Normally one expects long-term interest rates to be higher than short-term rates.\n", "But there are times when the *spread* between the rates goes negative.\n", "Two such incidents are visible in the below chart of\n", "[freely available historical data](http://catalog.data.gov/dataset/interest-rate-statistics-daily-treasury-bill-rates)\n", "on US Treasury interest rates.\n", "\n", "Wikipedia says:\n", "> Strongly inverted [Yield Curves](https://en.wikipedia.org/wiki/Yield_curve) have historically preceded economic depressions.\n", "\n", "### First Prepare the Data" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "rates = new CSV().read(\"../resources/data/interest-rates.csv\")\n", "def f = new java.text.SimpleDateFormat(\"yyyy MM dd\")\n", "lehmanDate = f.parse(\"2008 09 15\")\n", "bubbleBottomDate = f.parse(\"2002 10 09\")\n", "inversion1 = [f.parse(\"2000 07 22\"), f.parse(\"2001 02 16\")]\n", "inversion2 = [f.parse(\"2006 08 01\"), f.parse(\"2007 06 07\")]\n", "def size = rates.size()\n", "(0 ..< size).each{row = rates[it]; row.spread = row.y10 - row.m3}\n", "\n", "OutputCell.HIDDEN" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Then Build the Top and Bottom Plots" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def ch = new Crosshair(color: Color.gray, width: 2, style: StrokeType.DOT)\n", "\n", "// The top plot has 2 lines.\n", "p1 = new TimePlot(yLabel: \"Interest Rate\", crosshair: ch)\n", "p1 << new Line(x: rates.time, y: rates.m3, displayName: \"3 month\")\n", "p1 << new Line(x: rates.time, y: rates.y10, displayName: \"10 year\")\n", "\n", "// The bottom plot has an area filled in.\n", "p2 = new TimePlot(yLabel: \"Spread\", crosshair: ch)\n", "p2 << new Area(x: rates.time, y: rates.spread, color: new Color(120, 60, 0))\n", "\n", "// Highlight the inversion intervals\n", "def b1 = new ConstantBand(x: inversion1, color: new Color(240, 100, 100, 55))\n", "def b2 = new ConstantBand(x: inversion2, color: new Color(240, 100, 100, 55))\n", "\n", "// Add notation and line for Lehman Bankruptcy.\n", "p1 << new Text(x: lehmanDate, y: 7.5, text: \"Lehman Brothers Bankruptcy\")\n", "def l1 = new ConstantLine(x: lehmanDate, style: StrokeType.DOT, color: Color.gray)\n", "\n", "// Add notation and line for Stocks Nadir.\n", "p1 << new Text(x: bubbleBottomDate, y: 5.75, text: \"Stocks Hit Bottom\")\n", "def l2 = new ConstantLine(x: bubbleBottomDate, style: StrokeType.DOT, color: Color.gray)\n", "\n", "// add the notations and highlight bands to both plots\n", "p1 << l1 << l2 << b1 << b2\n", "p2 << l1 << l2 << b1 << b2\n", "\n", "OutputCell.HIDDEN" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Then Link and Display Together" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "// Then use a CombinedPlot to get stacked plots with linked X axis.\n", "def c = new CombinedPlot(title: \"US Treasuries\", initWidth: 1000)\n", "\n", "// add both plots to the combined plot, and including their relative heights.\n", "c.add(p1, 3)\n", "c.add(p2, 1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Simple Automatic Plot" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "// The simplest chart function with all defaults:\n", "new SimpleTimePlot(rates, [\"y1\", \"y10\"])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Scatter Plot" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def c = new Color(120, 120, 120, 100)\n", "new Plot() << new Points(x: rates.y1, y: rates.y30, displayName: \"y1 vs y30\") \\\n", " << new Points(x: rates.m3, y: rates.y5, displayName: \"m3 vs y5\") \\\n", " << new Line(x: rates.m3, y: rates.y5, color: c) \\\n", " << new Line(x: rates.y1, y: rates.y30, color: c)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Navigation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "First, let’s see how to navigate in a plot. The following navigation methods are supported\n", "\n", "## Dragging\n", "\n", "Click at some empty place of the plot, then drag the view around.\n", "\n", "## Zooming ##\n", " \n", "Click to start interacting with the chart.  Then Scroll your mouse-wheel to\n", "zoom in / out. Zoom will be centered at your mouse cursor, and scaled\n", "proportionally at each side.On a Mac laptop, drag two fingers vertically up and down to zoom.\n", "\n", "You may choose to zoom\n", "along a single (x / y), To zoom along the x-axis, move the mouse cursor below\n", "the x-axis, and then zoom. To zoom along the y-axis, move the mouse cursor left\n", "to the y-axis, and then zoom. \n", "\n", "If you'd like the y-axis to automatically scale to fit the data points, set the `autoZoom` parameter of the plot to `true`.\n", "\n", "## Box Zoom ##\n", "\n", "You can zoom to a\n", "selected rectangle region. Right click the mouse and drag out the box you’d\n", "like to zoom into. You do NOT necessarily need to drag the box from the left-top\n", "to the bottom-right. Any direction will do.\n", "\n", "## Reset Zoom Focus ##\n", "\n", "Double click anywhere on\n", "the plot background to reset the focus range to its default values.\n", "\n", "It is possible to reset\n", "the focused range of only the x / y axis! To reset the zoom along the x-axis,\n", "double click anywhere below the x-axis. To reset the zoom along the y-axis, double\n", "click anywhere left to the y-axis.\n", "\n", "## TRY IT NOW! ##\n", "\n", "Now it would be a good\n", "time for you to try the above interactions in the following demo plot. How\n", "about some challenges? :)\n", "\n", "Okay.. Challenge accepted. Now use the navigation method to:\n", "* Find and display an orange ‘T’ character without distortion!\n", "* Find and display a blue ‘S’ character without distortion!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "p = new Plot()\n", "p << new Line(x:[1000, 10000], y:[10000, 10000], width: 10, color: Color.orange)\n", "p << new Line(x:[5500, 5500], y:[10000, 9999], width: 10, color: Color.orange)\n", "p << new Line(x:[14000, 14000, 15002], y:[900, 901, 901], width: 1, color: Color.blue)\n", "p << new Line(x:[14000, 15002, 15002], y:[900, 900, 899], width: 1, color: Color.blue)\n", "p << new Line(x:[14000, 15002], y:[899, 899], width: 1, color: Color.blue)" ] } ], "metadata": { "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" } }, "nbformat": 4, "nbformat_minor": 2 }