{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## Spiral plot ##" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[Spiral plot](http://cs.lnu.se/isovis/courses/spring07/dac751/papers/TimeSpiralsInfoVis2001.pdf) is a method of visualizing (periodic) time series. Here we adapt it to visualize tennis tournament results for Simona Halep, No 2 WTA 2015 ranking." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We generate bar charts of set results in each tournament along an Archimedean spiral of equation\n", "$z(\\theta)=a\\theta e^{-i \\theta}$, $a>0, \\theta>3\\pi/2$. Our bars are curvilinear bars, i.e. they have spiral arcs as base." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Matplotlib plot of this spiral:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": true }, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "import numpy as np\n", "%matplotlib inline" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [], "source": [ "PI=np.pi" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "(-60.0, 60.0, -50.0, 50.0)" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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\nQmCC\n", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "a=2\n", "theta=np.linspace(3*PI/2, 8*PI, 400)\n", "z=a*theta*np.exp(-1j*theta)\n", "plt.figure(figsize=(6,6))\n", "plt.plot(z.real, z.imag)\n", "plt.axis('equal')\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Each ray (starting from origin O(0,0)) crosses successive turnings of the spiral at constant distance points, namely at distance=$2\\pi a$.\n", "With our choice a=2, this distance is $4\\pi=12.56637$. Hence we set the tallest bar corresponding to \n", "a set score of 7 as having the height 10. The bar height corresponding to any set score in $\\{0, 1, 2, \\ldots, 7\\}$ can be read from the following dictionary:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "8.571428571428571" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "h=7.0\n", "score={0: 0., 1:10./h, 2: 20/h, 3: 30/h, 4: 40/h, 5: 50/h, 6: 60/h, 7: 70/h}\n", "score[6]" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import plotly.plotly as py\n", "from plotly.graph_objs import *" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Read the json file created from data posted at [wtatennis.com](http://www.wtatennis.com/players/player/13516/title/simona-halep):" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[{u'rank': 3}, {u'points': 280}, {u'prize': 111163}, {u'A Beck (55)': [4, 6, 6, 4, 6, 3]}, {u'N Vikhlyantseva (584)': [6, 2, 6, 2]}, {u'A Krunic (84)': [6, 3, 6, 3]}, {u'S Zheng (97)': [6, 2, 6, 3]}, {u'T Bacsinszky (67)': [6, 2, 6, 2]}]\n" ] } ], "source": [ "import json\n", "with open(\"halep2015.json\") as json_file:\n", " jdata = json.load(json_file)\n", "print jdata['Shenzen']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`played_at` is the list of tournaments Simona Halep participated in:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": true }, "outputs": [], "source": [ "played_at=['Shenzen', 'Australian Open', 'Fed Cup', 'Dubai', 'Indiana Wells', 'Miami',\n", " 'Stuttgart', 'Madrid', 'Rome', 'French Open', 'Birmingham', 'Wimbledon', 'Toronto',\n", " 'Cincinnati', 'US Open', 'Guangzhou', 'Wuhan', 'Beijing', 'WTA Finals' ]" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": false }, "outputs": [], "source": [ "#define a dict giving the number of matches played by Halep in each tournament k\n", "nmatches={ k: len(jdata[where][3:]) for (k, where) in enumerate(played_at) } " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The arcs of spiral are defined as Plotly SVG paths:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def make_arc(aa, theta0, theta1, dist, nr=4):# defines the arc of spiral between theta0 and theta1, \n", " \n", " theta=np.linspace(theta0, theta1, nr)\n", " pts=(aa*theta+dist)*np.exp(-1j*theta)# points on spiral arc r=aa*theta\n", " \n", " string_arc='M '\n", " for k in range(len(theta)):\n", " string_arc+=str(pts.real[k])+', '+str(pts.imag[k])+' L '\n", " return string_arc" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "' -4.57526296667, 0.927451718436 L -4.61366881509, 0.618827320468 L -4.63134090185, 0.309214291159 L -4.62831853072, -5.66805547408e-16 L '" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "make_arc(0.2, PI+0.2, PI, 4)[1:]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The function `make_bar` returns a Plotly dict that will be used to generate the bar shapes:" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def make_bar(bar_height, theta0, fill_color, rad=0.2, a=2):\n", " theta1=theta0+rad\n", " C=(a*theta1+bar_height)*np.exp(-1j*theta1)\n", " D=a*theta0*np.exp(-1j*theta0)\n", " \n", " return dict( \n", " line=Line(color=fill_color, width=0.5\n", " ), \n", " path= make_arc(a, theta0, theta0+rad, 0.0)+str(C.real)+', '+str(C.imag)+' '+\\\n", " make_arc(a, theta1, theta0, bar_height)[1:]+ str(D.real)+', '+str(D.imag),\n", " type='path',\n", " fillcolor=fill_color \n", " ) \n", " " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Define a function setting the plot layout:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def make_layout(title, plot_size):\n", " axis=dict(showline=False, # hide axis line, grid, ticklabels and title\n", " zeroline=False,\n", " showgrid=False,\n", " showticklabels=False,\n", " title='' \n", " )\n", "\n", " return Layout(title=title,\n", " font=Font(size=12), \n", " xaxis=XAxis(axis),\n", " yaxis=YAxis(axis),\n", " showlegend=False,\n", " width=plot_size,\n", " height=plot_size,\n", " margin=Margin(t=30, b=30, l=30, r=30),\n", " hovermode='closest',\n", " shapes=[]# below we append to shapes the dicts defining \n", " #the bars associated to set scores\n", " \n", " ) " ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "collapsed": true }, "outputs": [], "source": [ "title='Simona Halep 2015 Tournament Results
Each arc of spiral corresponds to a tournament'" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "collapsed": false }, "outputs": [], "source": [ "layout=make_layout(title, 700)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The bar charts corresponding to two consecutive matches in a tournament are separated by an arc of length `interM`,\n", "whereas the bar charts corresponding to two consecutive tournaments are separated by a longer arc, `interT`:" ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "collapsed": true }, "outputs": [], "source": [ "interM=2.0#the length of circle arc approximating an arc of spiral, between two consecutive matches\n", "interT=3.5# between two tournaments" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The bars are colored by the following rule: the bars associated to Halep's results are colored in red (`colors[0]`),\n", "while the colors for opponents are chosen according to their rank (see the code below). The darker colors correspond to high ranked opponents, while the lighter ones to lower ranked opponents." ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "collapsed": true }, "outputs": [], "source": [ "colors=['#dc3148','#864d7f','#9e70a2', '#caaac2','#d6c7dd', '#e6e1dd'] " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Get data for generating bars and data to be displayed when hovering the mouse over the plot:" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "collapsed": false }, "outputs": [], "source": [ "a=2.0 # the parameter in spiral equation z(theta)=a*theta exp(-i theta)\n", "theta0=3*PI/2 # the starting point of the spiral\n", "Theta=[]# the list of tournament arc ends\n", "Opponent=[]# the list of opponents in each set of all matches played by halep\n", "rankOp=[]# rank of opponent list\n", "middleBar=[]# theta coordinate for the middle point of each bar base\n", "half_h=[]# the list of bar heights/2\n", "wb=1.5# bar width along the spiral\n", "rad=wb/(a*theta0)#the angle in radians corresponding to an arc of length wb, \n", " #within the circle of radius a*theta\n", "rank_Halep=[]\n", "Halep_set_sc=[]# list of Halep set scores\n", "Opponent_set_sc=[]# list of opponent set scores\n", "bar_colors=[]# the list of colors assigned to each bar in bar charts\n", "\n", "for k, where in enumerate(played_at):\n", " nr=nmatches[k]# nr is the number of matches played by Halep in the k^th tournament\n", " Theta.append(theta0)\n", " for match in range(nr):\n", " player=jdata[where][3+match].keys()[0]# opponent name in match match\n", " \n", " rankOp.append(int(player.partition('(')[2].partition(')')[0]))#Extract opponent rank:\n", " set_sc=jdata[where][3+match].values()[0]#set scores in match match\n", " sets=len(set_sc)\n", " #set bar colors according to opponent rank\n", " if rankOp[-1] in range(1,11): col=colors[1]\n", " elif rankOp[-1] in range(11, 21): col=colors[2] \n", " elif rankOp[-1] in range(21, 51): col=colors[3] \n", " elif rankOp[-1] in range(51, 101): col=colors[4] \n", " else: col=colors[5] \n", " \n", " \n", " for s in range(0, sets, 2):\n", " middleBar.append(0.5*(2*theta0+rad))# get the middle of each angular interval \n", " # defining bar base\n", " rank_Halep+=[jdata[where][0]['rank']]\n", " Halep_set_sc.append(set_sc[s])\n", " \n", " half_h.append(0.5*score[set_sc[s]])# middle of bar height\n", " bar_colors.append(colors[0])\n", " \n", " layout['shapes'].append(make_bar(score[set_sc[s]], theta0, colors[0], rad=rad, a=2))\n", " rad=wb/(a*theta0)\n", " \n", " theta0=theta0+rad\n", " middleBar.append(0.5*(2*theta0+rad))\n", " Opponent_set_sc.append(set_sc[s+1])\n", " half_h.append(0.5*score[set_sc[s+1]])\n", " Opponent.append(jdata[where][3+match].keys()[0])\n", " bar_colors.append(col)\n", " \n", " layout['shapes'].append(make_bar(score[set_sc[s+1]], theta0, col , rad=rad, a=2))\n", " \n", " rad=wb/(a*theta0)\n", " theta0=theta0+rad\n", " gapM=interM/(a*theta0) \n", " theta0=theta0-rad+gapM\n", " gapT=interT/(a*theta0) \n", " Theta.append(theta0)\n", " theta0=theta0-gapM+gapT \n", " " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Check list lengths:" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "308 308 154 308\n" ] } ], "source": [ "print len(bar_colors), len(middleBar), len(Opponent), len(half_h)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Define the list of strings to be displayed for each bar:" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "collapsed": false }, "outputs": [], "source": [ "nrB=nrB=len(bar_colors)\n", "playersRank=['n']*nrB\n", "\n", "for k in range(0,nrB, 2):\n", " playersRank[k]=u'Halep'+' ('+'{:d}'.format(rank_Halep[k/2])+')'+'
'+\\\n", " 'set score: '+str(Halep_set_sc[k/2])\n", "for k in range(1, nrB, 2):\n", " playersRank[k]=Opponent[(k-1)/2]+'
'+'set score: '+str(Opponent_set_sc[(k-1)/2])" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": 22, "metadata": { "collapsed": false }, "outputs": [], "source": [ "players=[]# Plotly traces that define position of text on bars\n", "\n", "for k in range(nrB):\n", " z=(a*middleBar[k]+half_h[k])*np.exp(-1j*middleBar[k])\n", " players.append(Scatter(x=[z.real],\n", " y=[z.imag],\n", " mode='markers',\n", " marker=Marker(size=0.25, color=bar_colors[k]),\n", " name='',\n", " text=playersRank[k],\n", " hoverinfo='text'\n", " )\n", " )" ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "collapsed": false }, "outputs": [], "source": [ "LT=len(Theta)\n", "aa=[a-0.11]*2+[a-0.1]*3+[a-0.085]*5+[a-0.075]*5+[a-0.065]*4# here is a trick to get spiral arcs \n", "#looking at the same distance from the bar charts\n", "\n", "spiral=[] #Plotly traces of spiral arcs\n", "for k in range(0, LT, 2):\n", " X=[]\n", " Y=[]\n", " theta=np.linspace(Theta[k], Theta[k+1], 40)\n", " Z=aa[k/2]*theta*np.exp(-1j*theta)\n", " X+=Z.real.tolist()\n", " Y+=Z.imag.tolist()\n", " X.append(None)\n", " Y.append(None)\n", " spiral.append(Scatter(x=X,\n", " y=Y,\n", " mode='lines',\n", " line=Line(color='#23238E', width=4),\n", " name='',\n", " text=played_at[k/2],\n", " hoverinfo='text'))" ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "collapsed": false }, "outputs": [], "source": [ "data=Data(spiral+players)\n", "fig=Figure(data=data,layout=layout)" ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "py.sign_in('empet', 'my_api_key')\n", "py.iplot(fig, filename='spiral-plot')" ] }, { "cell_type": "code", "execution_count": 64, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 64, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from IPython.core.display import HTML\n", "def css_styling():\n", " styles = open(\"./custom.css\", \"r\").read()\n", " return HTML(styles)\n", "css_styling()" ] } ], "metadata": { "kernelspec": { "display_name": "Python 2", "language": "python", "name": "python2" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", "version": "2.7.11" } }, "nbformat": 4, "nbformat_minor": 0 }