diff --git a/code/Project 3.ipynb b/code/Project 3.ipynb new file mode 100644 index 00000000..94c52d58 --- /dev/null +++ b/code/Project 3.ipynb @@ -0,0 +1,1552 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# If you want the figures to appear in the notebook, \n", + "# and you want to interact with them, use\n", + "# %matplotlib notebook\n", + "\n", + "# If you want the figures to appear in the notebook, \n", + "# and you don't want to interact with them, use\n", + "# %matplotlib inline\n", + "\n", + "# If you want the figures to appear in separate windows, use\n", + "# %matplotlib qt5\n", + "\n", + "# tempo switch from one to another, you have to select Kernel->Restart\n", + "\n", + "%matplotlib inline\n", + "\n", + "\n", + "\n", + "\n", + "from modsim import *" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
value
t0
\n", + "
" + ], + "text/plain": [ + "t 0\n", + "dtype: int64" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "init = State(t=0)\n", + "init" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
value
initt 0\n", + "dtype: int64
cod0.72
\n", + "
" + ], + "text/plain": [ + "init t 0\n", + "dtype: int64\n", + "cod 0.72\n", + "dtype: object" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "downforce = System(init=init,\n", + " cod=.72\n", + " )\n", + "downforce" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def update(state, system):\n", + " \"\"\"Update the thermal transfer model.\n", + " \n", + " state: State (temp)\n", + " system: System object\n", + " \n", + " returns: State (temp)\n", + " \"\"\"\n", + " unpack(system)\n", + " T = state.t\n", + " #T += 1\n", + " df= (0.5*(T**2)*0.72)\n", + "\n", + " return df" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.0" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "update(init, downforce)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def run_simulation(system, update_func):\n", + " \"\"\"Runs a simulation of the system.\n", + " \n", + " Add a TimeFrame to the System: results\n", + " \n", + " system: System object\n", + " update_func: function that updates state\n", + " \"\"\"\n", + " unpack(system)\n", + " \n", + " frame = TimeFrame(columns=init.index)\n", + " frame.loc[0] = init\n", + " ts = linrange(0, 130, 1)\n", + " \n", + " for t in ts:\n", + " frame.loc[t+1] = df= (0.5*(t**2)*0.72)\n", + " \n", + " system.results = frame" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
t
00.00
10.00
20.36
31.44
43.24
55.76
69.00
712.96
817.64
923.04
1029.16
1136.00
1243.56
1351.84
1460.84
1570.56
1681.00
1792.16
18104.04
19116.64
20129.96
21144.00
22158.76
23174.24
24190.44
25207.36
26225.00
27243.36
28262.44
29282.24
......
1023672.36
1033745.44
1043819.24
1053893.76
1063969.00
1074044.96
1084121.64
1094199.04
1104277.16
1114356.00
1124435.56
1134515.84
1144596.84
1154678.56
1164761.00
1174844.16
1184928.04
1195012.64
1205097.96
1215184.00
1225270.76
1235358.24
1245446.44
1255535.36
1265625.00
1275715.36
1285806.44
1295898.24
1305990.76
1316084.00
\n", + "

132 rows × 1 columns

\n", + "
" + ], + "text/plain": [ + " t\n", + "0 0.00\n", + "1 0.00\n", + "2 0.36\n", + "3 1.44\n", + "4 3.24\n", + "5 5.76\n", + "6 9.00\n", + "7 12.96\n", + "8 17.64\n", + "9 23.04\n", + "10 29.16\n", + "11 36.00\n", + "12 43.56\n", + "13 51.84\n", + "14 60.84\n", + "15 70.56\n", + "16 81.00\n", + "17 92.16\n", + "18 104.04\n", + "19 116.64\n", + "20 129.96\n", + "21 144.00\n", + "22 158.76\n", + "23 174.24\n", + "24 190.44\n", + "25 207.36\n", + "26 225.00\n", + "27 243.36\n", + "28 262.44\n", + "29 282.24\n", + ".. ...\n", + "102 3672.36\n", + "103 3745.44\n", + "104 3819.24\n", + "105 3893.76\n", + "106 3969.00\n", + "107 4044.96\n", + "108 4121.64\n", + "109 4199.04\n", + "110 4277.16\n", + "111 4356.00\n", + "112 4435.56\n", + "113 4515.84\n", + "114 4596.84\n", + "115 4678.56\n", + "116 4761.00\n", + "117 4844.16\n", + "118 4928.04\n", + "119 5012.64\n", + "120 5097.96\n", + "121 5184.00\n", + "122 5270.76\n", + "123 5358.24\n", + "124 5446.44\n", + "125 5535.36\n", + "126 5625.00\n", + "127 5715.36\n", + "128 5806.44\n", + "129 5898.24\n", + "130 5990.76\n", + "131 6084.00\n", + "\n", + "[132 rows x 1 columns]" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "run_simulation(downforce,update)\n", + "downforce.results" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plot(downforce.results)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Torque
RPM
8756.147541220.693752
8807.377049223.237408
8838.114754224.509979
8868.852459224.514433
8899.590164227.055120
8909.836066227.056605
8971.311475228.333630
8971.311475228.333630
9053.278689232.149857
9073.770492232.152827
9155.737705232.164707
9186.475410234.705393
9186.475410235.973509
9278.688525235.986873
9278.688525235.986873
9391.393443241.075671
9391.393443241.075671
9534.836066244.900808
9616.803279246.180803
9668.032787247.456344
9739.754098248.734854
9831.967213248.748218
9842.213115248.749703
9913.934426248.760097
9985.655738248.770492
10057.377050250.049002
10098.360660250.054942
10180.327870251.334937
10211.065570252.607508
10231.557380253.878593
......
16040.983610337.148076
16051.229510337.149561
16112.704920337.158470
16122.950820337.159955
16122.950820337.159955
16194.672130335.902233
16235.655740333.371941
16266.393440333.376396
16286.885250333.379366
16338.114750333.386790
16338.114750333.386790
16409.836070332.129069
16461.065570332.136493
16471.311480332.137978
16471.311480332.137978
16532.786890332.146888
16532.786890332.146888
16532.786890332.146888
16584.016390329.618080
16594.262300329.619565
16665.983610328.361844
16665.983610328.361844
16727.459020328.370753
16727.459020328.370753
16788.934430328.379663
16819.672130328.384117
16850.409840328.388572
16911.885250325.861250
16963.114750323.332442
17014.344260322.071751
\n", + "

184 rows × 1 columns

\n", + "
" + ], + "text/plain": [ + " Torque\n", + "RPM \n", + "8756.147541 220.693752\n", + "8807.377049 223.237408\n", + "8838.114754 224.509979\n", + "8868.852459 224.514433\n", + "8899.590164 227.055120\n", + "8909.836066 227.056605\n", + "8971.311475 228.333630\n", + "8971.311475 228.333630\n", + "9053.278689 232.149857\n", + "9073.770492 232.152827\n", + "9155.737705 232.164707\n", + "9186.475410 234.705393\n", + "9186.475410 235.973509\n", + "9278.688525 235.986873\n", + "9278.688525 235.986873\n", + "9391.393443 241.075671\n", + "9391.393443 241.075671\n", + "9534.836066 244.900808\n", + "9616.803279 246.180803\n", + "9668.032787 247.456344\n", + "9739.754098 248.734854\n", + "9831.967213 248.748218\n", + "9842.213115 248.749703\n", + "9913.934426 248.760097\n", + "9985.655738 248.770492\n", + "10057.377050 250.049002\n", + "10098.360660 250.054942\n", + "10180.327870 251.334937\n", + "10211.065570 252.607508\n", + "10231.557380 253.878593\n", + "... ...\n", + "16040.983610 337.148076\n", + "16051.229510 337.149561\n", + "16112.704920 337.158470\n", + "16122.950820 337.159955\n", + "16122.950820 337.159955\n", + "16194.672130 335.902233\n", + "16235.655740 333.371941\n", + "16266.393440 333.376396\n", + "16286.885250 333.379366\n", + "16338.114750 333.386790\n", + "16338.114750 333.386790\n", + "16409.836070 332.129069\n", + "16461.065570 332.136493\n", + "16471.311480 332.137978\n", + "16471.311480 332.137978\n", + "16532.786890 332.146888\n", + "16532.786890 332.146888\n", + "16532.786890 332.146888\n", + "16584.016390 329.618080\n", + "16594.262300 329.619565\n", + "16665.983610 328.361844\n", + "16665.983610 328.361844\n", + "16727.459020 328.370753\n", + "16727.459020 328.370753\n", + "16788.934430 328.379663\n", + "16819.672130 328.384117\n", + "16850.409840 328.388572\n", + "16911.885250 325.861250\n", + "16963.114750 323.332442\n", + "17014.344260 322.071751\n", + "\n", + "[184 rows x 1 columns]" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data1 = pd.read_csv('Torque_curve.csv',index_col='RPM')\n", + "data1\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\nGGZrAAAAAElFTkSuQmCC\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plot(data1, 'bo', label='Torque')\n", + "decorate(xlabel='RPM (min)',\n", + " ylabel='Torque (mg/dL)')" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plot(data)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "I1 = interpolate(data1.Torque, kind ='linear')" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "ts = linrange(8500, 18000, 2000)\n", + "\n", + "plot(data1.Torque, 'go', label='Torque data')\n", + "plot(ts, I1(ts), color='green', label='interpolated')\n", + "\n", + "decorate(xlabel='RPM (min)',\n", + " ylabel='Torque ($\\mu$U/mL)')\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "I = interpolate(downforce.results.t,kind='cubic')" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\nQghv/gc1Zw908bT+oAAAAABJRU5ErkJggg==\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "ts = linrange(1, 100, 1000)\n", + "\n", + "plot(downforce.results, 'go', label='downforce data')\n", + "plot(ts, I(ts), color='green', label='interpolated')\n", + "\n", + "decorate(xlabel='Time (min)',\n", + " ylabel='Torque ($\\mu$U/mL)')\n" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
RPM
Speed
0.1224486388.837401
1.6272086420.745921
1.9299586452.548344
1.9299586452.548344
2.8393296563.843564
2.8415766595.619463
3.7487016675.138784
4.9540826722.908729
6.1605866786.566624
7.3704616897.888368
8.5780896977.434212
9.4874607088.729432
10.0929597152.334279
11.3005877231.880123
11.9038397263.709071
12.8087177311.452492
14.3190957422.800760
15.2239737470.544181
15.8305957550.036978
17.6459687724.963568
18.8547207820.397363
19.4579727852.226310
20.6644767915.884205
21.2688527963.601102
22.4776038059.034896
23.6852308138.580741
24.8939828234.014535
26.4032358329.474854
27.3114848424.882124
28.2163628472.625545
......
287.29294813357.175400
287.89507713373.116400
290.00533613468.629760
291.20959413500.511760
292.41385113532.393760
294.51961713564.355320
296.02437713596.263840
298.73676513707.718210
300.54652213803.205050
302.05352913866.889470
303.86103913930.600410
305.97017414010.225830
308.37869014073.989820
310.18395314105.924860
311.69096014169.609280
314.40447114296.951600
315.90923114328.860120
317.11461214376.630060
318.31887014408.512060
320.42800614488.137480
321.63451014551.795370
322.83989114599.565320
323.74364614631.420790
326.75429014711.125780
327.65916814758.869200
328.86454914806.639140
331.27194114854.515190
332.47619914886.397180
334.28483214965.996070
335.78846914982.016640
\n", + "

409 rows × 1 columns

\n", + "
" + ], + "text/plain": [ + " RPM\n", + "Speed \n", + "0.122448 6388.837401\n", + "1.627208 6420.745921\n", + "1.929958 6452.548344\n", + "1.929958 6452.548344\n", + "2.839329 6563.843564\n", + "2.841576 6595.619463\n", + "3.748701 6675.138784\n", + "4.954082 6722.908729\n", + "6.160586 6786.566624\n", + "7.370461 6897.888368\n", + "8.578089 6977.434212\n", + "9.487460 7088.729432\n", + "10.092959 7152.334279\n", + "11.300587 7231.880123\n", + "11.903839 7263.709071\n", + "12.808717 7311.452492\n", + "14.319095 7422.800760\n", + "15.223973 7470.544181\n", + "15.830595 7550.036978\n", + "17.645968 7724.963568\n", + "18.854720 7820.397363\n", + "19.457972 7852.226310\n", + "20.664476 7915.884205\n", + "21.268852 7963.601102\n", + "22.477603 8059.034896\n", + "23.685230 8138.580741\n", + "24.893982 8234.014535\n", + "26.403235 8329.474854\n", + "27.311484 8424.882124\n", + "28.216362 8472.625545\n", + "... ...\n", + "287.292948 13357.175400\n", + "287.895077 13373.116400\n", + "290.005336 13468.629760\n", + "291.209594 13500.511760\n", + "292.413851 13532.393760\n", + "294.519617 13564.355320\n", + "296.024377 13596.263840\n", + "298.736765 13707.718210\n", + "300.546522 13803.205050\n", + "302.053529 13866.889470\n", + "303.861039 13930.600410\n", + "305.970174 14010.225830\n", + "308.378690 14073.989820\n", + "310.183953 14105.924860\n", + "311.690960 14169.609280\n", + "314.404471 14296.951600\n", + "315.909231 14328.860120\n", + "317.114612 14376.630060\n", + "318.318870 14408.512060\n", + "320.428006 14488.137480\n", + "321.634510 14551.795370\n", + "322.839891 14599.565320\n", + "323.743646 14631.420790\n", + "326.754290 14711.125780\n", + "327.659168 14758.869200\n", + "328.864549 14806.639140\n", + "331.271941 14854.515190\n", + "332.476199 14886.397180\n", + "334.284832 14965.996070\n", + "335.788469 14982.016640\n", + "\n", + "[409 rows x 1 columns]" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data = pd.read_csv('Gear_ratios.csv',index_col='Speed')\n", + "data" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "I = interpolate(data.RPM,kind='linear')" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAaEAAAEPCAYAAADrvntcAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzsnXl8VOW9uJ8zW2ZLJpiFBEgCQkuwKCEYqL2gtWgNXhXb\naqt1AdrcevmhVeq9UOQqaq2iXGoFtN4SWgHr2ku1iHGtRbQWJwS5oCwGBUPIQBaSkFkyc+ac3x/D\nOcxkIdtk5X385CM558x533cy837Pd5dUVVURCAQCgaAfMPT3BAQCgUBw9iKEkEAgEAj6DSGEBAKB\nQNBvCCEkEAgEgn7D1N8TGCwEAgH27NlDWloaRqOxv6cjEAgEg4JwOEx1dTUTJ07EarW2Oi+EUCfZ\ns2cPN910U39PQyAQCAYlf/rTn7jwwgtbHRdCqJOkpaUBkTcyIyOjn2cjEAgEgwOPx8NNN92k76Et\nEUKok2gmuIyMDEaNGtXPsxEIzi7Wf7Ke9bvWc6zpGMOdw5kzaQ5z8ub097TOetyVborLiimrKgMJ\n8jPyKcovomBkQatr23NjCCEkEAxyhvIG7a50859v/ScfVX6EoioYJANHm47yxYkvAHplnX39fror\n3ZSUl1B1sorMxExmjZvV5iY+0HBXunl428Psq92nH3v/q/ep9lWzZPqSTq9BCCHBWUNXntriQV9s\nZus/Wc/yD5frv1c1Vem/99bGuey9ZWz4vw00BBpwWV3cesGtPHDpA3EfZ/0n61n+wXI+r/scRVUA\nUCSFpmATsiKz5uM1vfJ+Lvv7MrwhL7Iic9x3nGV/Xwb0nsBb/fFqfCEfdrOdbFc2lY2VAANaELkr\n3Sx+ZzG7j+8GwGlxYjVFgg4qGip4o/wNIYQEgmi0p7adnp36BnOo/hAHag/w2OWPxf0L3xfCYf0n\n67nrzbtoCjYhIWE2mLFb7DjMDjbs2hD3TdNd6ea2zbfxf8f/DwCjwUhICbHq41UAcRVE7ko3qz9e\nTY2/BkVVUIlUF1NVFVVVCYaDHG44HNfxSspLWL19NU2hJkwGEyaDCVmRaWhu6BWBp6/RV6N/Jg83\nHGZi2sQubeJ9jSY4D544SEAO6O9TsjUZq8mKN+Tl6Mmjnb6fEEKCs4LismK2fbWNk8GTGCQDJkPk\no7+neg/rytbFXwjtWt/m8XgJh2XvLeOp0qdoCDTox8JqGIIgKzJfnviyx2NEownxPdV7dK0kHA4j\nKzIJxgQ2/t/GuAqh4rJiDjccprG5URdAGioqsiLHbSx3pZtHPniErxq+4kTgRETISUH9c2IymOIq\n8DSKy4opryvHL/tbfSbPsZ0T9/F6imZJ2LRvU8zxYDgIQFOwCavJisPsYETiiE7fVwghwZDHXelm\n21fb8Ia8KKpCWAkTDAcxGUxYjBbKPGVxH/NQ/SFOBk8iKzImg0k3V3iaPD2+t7vSzdqytciKjCRJ\nulBAjWwIFpMFpB4PE0NxWTHbK7cTUkIxxzWtpMZXE5dxtI3upc9e0je3lkin/ku1p8ZlzEc+eIRt\nX21DVuTTWtcpuaeoCsFwEJvJFpexNLTPZEgJtfmZrA/Ux3W8nqJpP4cbDtMUbNIFpnTqgyYrsv5g\nkOXKonBcYafvLYSQYMhTUl6C3WxHUZXTGzYQVsLIkkxTsCmu463/ZD3VvmoCckA/1hRsYph1GBNS\nJ/To3u5KN/O3zOe49zgQEQIaKiphNaKdjE4e3aNxWo657att+GU/ElKMZqKe+s9o6HkCt6aR/PPI\nPwnIAX1zbjkmRHwQPX0vIfK3erP8TWRVxiDFFpCJfm/jJfA0tM+kqqptfiajj/U3mtlQMxnCqYcd\nowWL0QJAc7gZh9nBJTmX8NPJP+2SZUEIIcGQp+pkFVlJWew5vkffWFRU/YnaYXHEbSx3pZtHP3wU\nOSzHmIwUVaHWX8v07Ok9uvfD2x7m4ImDugbUcnOWJIlESyJfP+fr3R6nJcVlxdQH6mOEagwqjB02\ntkdjaMJV8zNoT9iSJCGpp4WQAQMWkwW72U6ave28k66Mufrj1SicCnposfGrRPxPSQlJcRF40Wif\nyb01ezFIhoiv69Qah1mHtRKI/YlmGpUVmWA4GKP9mEwmMpwZOM1OnvrXp7pl1hZCSDDkyUzMRFEV\nnBYnJ/wndAFkkAwYDUacZmfcxiouK6aqqQoFJeYJXlVVTJKJY03HenTv7ZXbdWHQshWYhITdbI88\nncbBHKeZYHYf331aKLTQSiQkEhMSuTCzdSZ8V8f5tPpT4LQwMEpGDJKBoBLEKBkxGozYzXYA/LKf\n477j3RpPM/m9duA16gJ1uoZskAz6+iQkzEYzSQlJOC3OHgu86LFLyksoPVqKiordFNHQZUXWP5Oa\niW4goGnBGtF/DxUVs8GM0+zk9qm3d9uvKoSQYEjjrnRT2VjJtq+20Rxuxmw0E1bDKKqC2Wgm0ZIY\nt6dOd6Wb1z5/jYAcIBQO6ZuZtmmbjeZu+5+iTWImgymiBUkR85uGQTLoPoxqb3WP1qJF99X4avT7\nKqqCJEm6v8QoGUlMSMSV4Oq20NM0x2pfNaHwaX+TJEU2ZKvJiqzImA1mVFR8IR8mgwlXgosjjUe6\nNZ6W2+KTfUBE6KmqGlmDBKiR9zLBmABw+lwP0YQfwKikUZH8GgkcZgcngycJK2GQIhrGsaZjuCvd\n/RIhF53KcLTpKMFwELPBrPs3IfKeOc1Ovj/h+102v7VECCHBkCX6Sz8+ZTwVDRUEw5GoJ03wnAye\njMtTpzaW5lwOcEpb4bT5zy/7uyUctJyMal+1Pn+L0RLxHcgRk5ymKSiqwsngSb5q+Krba9FCv30h\nH4qi6P4eg2QgrIQxSkZdIAXDwR4JvUc+eIQv6788nQd06r5S1K6vrU3bACGiCXXVl6eZ/PbW7NXH\n07QPJHThLiFhM9v0dUuS1COhrmk/m/dvRkUl25VNuiMdgP3qfr6o/yLyNzVb9DX6w/5eidrszFyj\nE1B9IR+yIhMgQKIlUQ9MMRlMrLh8RVwiPYUQEgxZSspL9H+nO9JJMCXgl/26/V0zgcQjMEEbK9WW\nisfr0bWHaMJKmBOBE116wtWc9buP7yYgB/QILqvJitVkpVlujni2pMimrWlC3Y1W0zQgXyiiJaio\nhJQQZoM5InQIYsSI2WiOMY11R+i1NPVEa1mqqnKO9RymjpzK/tr9VDRW6MEKWjhzV3x5WuLrF/Vf\nRIIdpNNCTtOyLEYLRsmIxWhBkiTdp6eqarej1aIfhLwhLyoqe2v2QmrkM5nuSKfKW4WqqjSHm5EV\nGavJiqqqvRK12RGayVfTuCEicFQ1otWn2dNwmB1MyZwSt7wpIYQEQ5aqk1UxvzfLzRHN5NRTL0Ry\na3oaXuyudLP5wGa8QS8ANpMNX9BHUI0NMVaJhDN35Qm3uKyYnZ6d+hOphqzI2Ey2mHXISiTCy2ww\ntwql7ixa8qRuojpFWAnjTHAih2UMBoMeFaXhDXm7NI6mldQH6lEUBSR0Hx1E/j5Xj7+an07+KYve\nXkRFY0Wre3TWl7f+k/UseXcJJwIn9GAOVVV1jViSJJxmJ+enn09DcwP7a/frwt4gGQjIAcYkj+nS\n+jSKy4rZUbUDX8hHfaCeBFMCVpOVioYK3c+kJXtqFQcAGpobdCHfV6z/ZD2b9m2isbkxJm9Jm6PL\n6mJG9gwAfpr/07iNO3BCMASCOJOZmBnzuxYsgIq+yRglY7c3bIh8cedvmc+h+kORsOxwAIvRQpI1\nKcaZrznZVVTe/+r9Tt9/21fbqA/Ux/itNF/J93K/hyvBpfuFtGtCSghVUdu8X0dr+bT6UxqbGwH0\nDTvar+VMcGI2mPVNtbG5EVVVcVo6JxC0qgs/fPmHeiACEjGhyiaDiVljZ/H0VU9TMLIASYrkBDkt\nTuxmO06Lk1R7aqd8eVoEnF/26/fXqi5oQtZitDA9ezrLL4tUtAgrYT3vRVZkwkq4W9pydH6apmlp\nUYbRQjvNnhYxeckBfCGfrvHGM2qzM3Nd/fFqINa3CBFzqN0Ued9HJY2Ke6krIYQEQ5ZZ42bF/G7g\nlInslCVGVSOmJovB0sarOyY6f8JhdiArMvWBeiRJIs2WhtFgxHDqKxZWw4SVMKqq6pt8Z+5/pPGI\nrgVpggwiG2VRfhFmoxlU9MABRVUiJq0ufrO1tWj317WEU29WYkIiv73it4xxjcEX8p0OdT+1nrAS\nbvfe0WMsensRz+95norGCoJyEFU5HakoIWExWhjjGsOSGUv01w2zDsNqspJqTyXDmUGqPRWryUqy\nNbnD8Ra/s5iDJw7qG6qmbWnrNEkmxg0bpxfcrPXVElbDuiZgkAzd0paj/Xg1vhoCcgCb2YYrwUVQ\nDsZs6MMdw9u8RzyjNjsz14MnDhIKh2L8cVpC9LRR03jyyie595J74+6nEuY4wZAjuioxoDu6rSYr\n/pA/5gnfgAGruXW3x85QUl6i+05s5khGvTfkxRv0kpYcsZ1rZWe0L3ZntRQtbLk53ExYCaNIih6Q\nYDKYyHRmUjCygFA4pOe5aCgoBOW2qw20RfQmJCHpZihts7aarPz2it8yJ28Od791d6tkVYCvGjv2\nCf3n2//J9srtBMPBmLwYzcekqAp2s53F0xfHbHSTMiZR56/jQO0BfLIPu8nO11O+Tl5GXofvnyaA\nojUtLRAhKSGJGdkzYio+a+HHWph0d8ybmh/I0+TBYXbQ0NxAfaCeZGsyNrMNu9nOk1c+qY+p5XY1\nNDfoY8YzavNMtHyftL+7EaNu/o0W0r2BEEKCIUW0I1hDVVV+mv9T3ih/gzp/XUzEmqqq+EP+bo2z\n+cBmqn2RqCmnxYnNbMNmtiEhcfXXr+Z3pb+jKdgUI/QkpA61lOiwZW3+2pwVVcGV4OLi7IsBCIRP\nJ3ZGC7tAuJ3E0jbG0jbM6PBbFVXfEC/NuVR3Qp8MnmzzPh1pd+s/Wc+HFR/qvqaWgsxqsmI32bn6\n61e3cnjnuHLweD0kWZNIIgkAj9dDtiu7zbGWvbeMx//5OM3hZt33o+W0aNF3BgytBBCAxWDRNSFd\n61TDndaWNYHuafLoPiBXgkt/OEm1pTIlc0rMmKqqxkRpahGOvZkr1FYdOINk0CshaJpnT5JQO4sQ\nQoIhRXREXDRvlL8RKU4Z5ePQ/t/VyCftC6yqaqsnXa2AY+G4Qp4ufbrtG3SgCGkJrxDxV2gbt0Ey\nYDfbmZwxWXcMR5tOomnveFtj7ajaoefphNUwCaYETAaTvglFm8ba2xjPtGFqgQGaya5lsquERIYz\ngwmpE9p0eB9uOMyE1AlUNFTops8sV1abEXnL3lvGf3/03zFVF8JqWI/us5lsjBs2jtun3t5mdFeK\nPYUaf01MYILJYCLFkdLu+uD0Z2LbV9uo9lXjtDh1H1CyNZlUeyoSEvmZ+a3WqOUIRY8Zr6jNtmiv\nDhyc/rzJitzjJNTOIoSQYMgQHaWm9WbRIpCOnjxKSAkhSZIebqoJIr/cNU1I27hrfbV4Q15sJhsh\nJaQ/6WpfXBVVf+rWNSHpzMIhOuEVIk56LWET4IL0C7hnxj36xpBgSsAX9BHm9AZvxBgTaXWmsbZ9\ntQ2VU8JUadAFZHubUMsqDR0djw4M0PwrLUkwJpyx5ljVyaoY7UnTYKPbBWj5LVs+33I6tPrU+6+Z\nGG1GG/kZ+Sy/bHm7G2uOK4ejJ4+2Mo1lJ7WtdWlja58JbY6a8NF8QDaTjUxnZptO/VpfbcRMG+Vn\nCymhuBWFbTnX9urAGaWIWVRW5A7fp3gihJBgSKDl01Q2Vuo5DrX+WiZnTCbNnsaIxBFYjBaa5eYY\nH4pW9LOzuTtaGKuWPa75CxItiaTaU2Ns/XDalKYJIINkIMGU0O4aohNetURQzTxiNphbbQxOs5Na\namOEqoKCw9xxZJVWE057vzRhKiFxfvr5bW5CXdWENL+ZVh06uv6cQTLgtDh5ovCJM+acKKoS073T\nG/Kyr3af7tDXBNAHFR/oQk7XttRTPkFJYtywcR1urKn2VBJMCdgVu/43TjAlnLFsj6Z9a/5BTTtu\nCjaRak/FbrYzI3tGu1FlTaG2NZ6uhr13hmg/ptamIhgO6nXgNO23rwQQiOg4wRChuKyYvTV79fwV\nLVJtX01k8yocV8jYYWPb1EQMkoF1Zes6HCM6jFUbwy/7cVqcpNhSuPrrV+tfXHelm5ASIsGYoGtC\nqOjCqr017KjaQSgciomG0zbD6VnT29wY9PsT2XwNnfhaa8L0ZPAkATlAQA7oa0m1p7a7CbUsmHqm\n49F+s1A4hNEQ0dCMBiOSFKlzd+e0OzuV9OgP+anx1eBp8lDjq4n48U79KbUES80v1Vb/oQRjQqdN\nSy21ujOV7dHWqIXSR0fBQcTc2J4GFI0WEGAymGKi9+KFu9LNg1sf5MU9L+rzdJgd+sMBEJc6cN1B\naEKCIYGWXR4dpSYrMo3NjfoGcMfUOyjaXNTqtRJSp3J3tKdI7UlXoynYhM1ki+mhUlJegsPsoCnY\nhMFgwCRFnjolKeIXaEm0aSzZmkytv1avmZZgSmB61vQY34w+dqgJJPRK0xISSO0/RUc7pH0hn+7z\n0KpHBOUgV5x7RY83oVZ+s1OmvgRTAgkkYDfZeXjmw50SQDW+mlYPD1opneiaetEh5YCufVpNVhZ+\nc2GPx2prfZrwSTAlxPiAbGYbafY08jM7biGfZk/DG/S2isiLV9HU6Bbimv8z2lzoDXmRkOJSB647\n9KsQuu+++wiHw/z6179udS4UCnH99deTm5vL8uWn2yTX1tby4IMP8uGHH2I2m/n+97/PwoULMZlO\nL+WZZ55h/fr11NXVkZ+fz7Jlyxg9erR+fvfu3fz6179m7969DB8+nP/3//4f1157ba+uVdDLRD28\nalFqENE8tC/VnLw53F5yO96gV9+wtWrAHdnfW0bDaaYrza5+cfbFMV/eXZ5dBMNBvSdOmEjR1CRL\nEj+d3Nr53tI0ptXp0kxj0X6gaELh1hWXFVWJKQYavQZN29KqK0Sb+7Ss+J5mw0dHiKlqxC8Tvdnl\nuHLaDQxoC63baTRaKZ3oNhNa5JsRo/73tZvtLPzmwk53fT0ROKGXRIqmPlCvh/7v8uzicMPhSL5U\nVBJqSx/QlBFTOrWpj08ZT0VjRUxEotFgZHzq+E7NuT1aRsBpwRINzQ3YTDaCchCX1UWaPa1Lf494\n0y9CSFVVVq1axYsvvsh1113X5jWrVq1i79695Obmxhy/4447kCSJZ599lmPHjvHLX/4Sk8nEwoUL\nAXj55ZdZtWoVDz/8MGPGjOHxxx+nqKiI119/HYvFQl1dHUVFRVx11VX8+te/5h//+AdLly4lNTWV\n6dO73+tF0H+4K92oqHqYsdbFFCA/I1brsJqsBOSA7qvRvvgd3b9lNJysyHo0nNPsbLVxH2443GY4\ns8vqarUpaU/zFqMFv+zXM/WTrcnYTLYO7fNt5e20hSaAonNCtGgojZbCtCVtNZjTjmtr0UK+tRJJ\nqqpiN9v1agct/WYdoaqqrhlGl9JJsaXo75vm2wD00j9jh41l8b8s7tLmOsw6jC9OfKFr0iaDCYfZ\ngaIqeuj/4YbDeENePE0eXesB9E3d6ejaGtMd6aTaU2kKNsV04tWKnHaHlg8cEKv9hMIhkq3J3DDx\nBgrHFfZLtW6NPhdCFRUV3HPPPXz++eeMGNF2H/IdO3bwv//7v3z967GNuXbu3MmOHTt45513yMrK\nIjc3l0WLFvGrX/2KBQsWYLFYKC4uZt68eRQWRkwjK1euZPr06bz55ptcffXVvPzyyzidTpYuXYrB\nYGDs2LF89tln/OEPfxBCaBCifdmykrKo8dXgDXmpD9ST6cxkfMr4VsLBaY70FGqZsNpedvqZnupb\nRsNFU+urjRF2WoRWy5yk6Mx6iNWwOmsaaytPqK11aOY+zfwW3R1Ta0zWkRbUkRDSnPR2s103CdrM\nNhxmB/mZ+YxKGtXlDa+9EGZPk4fMxExUVFJIoT5QT3O4GQMGzks7r1v5Lan21FbmuGA4yIHaAxzz\nHsNutlPnr9PD2JuCTVhNVj0JdUb2jC6v0SAZGO0azYHaA8iKjMVgYbRrdKfD7FsS/ZnVPlca0cES\nN0y8gXsvubdbY8STPg9MKCsrIzMzk82bNzNq1KhW571eL4sXL+a//uu/SEmJjc0vLS1l5MiRZGVl\n6cemTp2K1+tl79691NbWcujQIaZOnaqfdzgcTJw4kdLSUv0eBQUFGAyGmHuUlZW1G2YqGLhoT3v7\na/djM0Xs8JnOTDKdmW2asNoLXW6rasKZnurT7GmMTh7NU//6VJtP2p2JeNLqzu307CQUDsUEB2Q4\nMzplGjMbza2c2AbJECnnE7WO6BIyZoNZd0grqtIlh7TJ2PZzq8Fg0B3fO6p2kGhJbHPd0X6zztJe\nKZ2TwZNkJUX2ApvZRmZiJqOTR5OTnNOjBMvoEkEOswO/7McnR0xv3pBXD+bQSjVpaBGJXV2joip6\nMm6GM4MkaxIer6db+1GrzyzomrX2b22u3flb9AZ9rgnNnj2b2bNnt3v+4Ycf5vzzz+fKK6/kpZde\nijl37Ngx0tNjVVTt96qqKt0vNHz48FbXeDweADweD+edd16r836/nxMnTnDOOed0b2GCPif66R6I\nCAlUJqROYLhjeJubUHstqtuqmtAbT/XRc9fyNTTNRFtGe5n1baFpdm0d18ZpWUJGq8CtaVxdcUjb\nzXbd7BWNqqq8sOcF6gP1+GQf3pCXDEcGTcEmvCFvpyLE2iOoRDS26M0UoDncjCRJ5KbkcqTxiJ7I\n2pn3rT0MkoEMRwYHag/QGGyMhMtLJpAinx0tGVnXKEx2HGYH3pC30z6g9vCH/DFmwK52jm2rWoMm\nKFU1ogFLSP0SAXcmBlR03LvvvsvWrVt57bXX2jzv9/tJSIjNsTCbI5nQzc3N+P2RjaTlNRaLhebm\nZgACgQAWi6XVeYBgsPP1tgT9T0tnvuYLqmioYHLG5DZf05WcDM0BXeurpSnUpN+/M0/1HZn9isuK\nOdxwWN8gwmpYz9tItae2mVnfFh1pdtGCVBPW2kY32jWaKZlTePqqdio7tEFyQjInAyf15FgNrTRO\ntJO+KdikRwL2pPKyK8FFY3Pj6e6up6LeLEYLe2v2MiF1QkzEYU8CKxRV4cv6L2lobtCDHWRkEkwJ\nMZFv2mae7comLyOvR34VTfDtqd4T4xPaV7OvU/lrHVVr0MzHafY0Ls65uF8i4M7EgBFCdXV13Hvv\nvTz88MMkJ7ddHddqtbYSFKFQJNPYbrdjtUa+eC2vCQaD2Gy2du+h/a5dIxj4tOXM1750ElK7AqKz\n0WTuSrfugLaaraioNAWbkJAYkzymw03VarK2WS3BarbqOTpaWZbosimyIndJawjIgTbH8Yf8MRUk\nVFUlEA7E1LfrrKBrtS6DhFE16gJWew+1HBmIOOl9IR+jkkb12PE9PmU8h+oP6T4hTaCn2lPJTcml\nIdDAcMdwRiSO6PFYx73HqfWf8udpa0MhpIRINiXrkW/nDjs3bgmdmYmZuI+6W+WPOcwO3ih/44xj\ndKZag8vqYuywsX2agNoVBowQ2rp1K7W1tXqUG0Bzc0TdfvPNN9m5cycZGRls3bo15nXHj0dU1uHD\nh5OZGekfU11dTU5OTsw1Y8eOBSAjI4Pq6upW97Db7SQmxtqxBQOXkvKSNp/uO+PM70w0WXFZMd6g\nF4/3dMRdV7LJJUnSqyloAQ1mgxl/yK8nvLasimAymBjtGt2lzSKoBPWyPtG1zrwhrx7RF+3P0pzd\n3TWPaesIhoOt3seWlaLj6fg2GoxI4dMtH7TggXRHOhnODH531e/iMs6RxiMxDwV60MepUjpp9rQz\nVj/oDrPGzeKFPS+0Op7lyoopTdQW0RGPWgUPWZE7Xa1hIDBgKiZcfvnlvPXWW7zyyiv6zwUXXMB3\nvvMdXnnlFQCmTJlCRUUFVVWnO2Zu374dh8NBbm4uKSkpjB49mo8//lg/7/V62bNnDwUFBfo9SktL\nY5x+27dvJz8/PyZYQTBw0Z7wa321enKh5kjujDNfr2bd4t/R99/21TaQ0DPf6wP1SEhku7J79GVu\nCjXpCa9acIBWFQHosq3eleDSzXjRzchONp+MNFQLenU/mObPmpE9o8dPxe0Jb027i6fj+0jjEb2c\njslgwmw0R8yipzrZjkhsO8q2W5z6KJiNkeANk9GkV3joqpbaWQpGFjAjewZOs1M3801InaCXm2qP\n6KZ5ml/RL/uxmWynltK5ag39zYDZdZ1OJzk5OTE/VqsVh8OhazWTJ08mLy+PhQsX8umnn7J161ZW\nrFjBvHnzdL/O3LlzWbt2LVu2bOHAgQPcfffdpKenc/nllwNw3XXXUVdXx7Jlyzh48CAbN27ktdde\no6iodSa9YOARnbNjNZ92EjfLzTjNzg7zXDoTTab5mjxNHrwhrx6t5jA7ztjDJhrtybllUcpmuZn6\nQD0NzQ26s9hqsuK0OPlB7g+6nDA4I3sGNpNN14TgVIM7lEhh1igNSNMgerIpaetoadKUkPSNMO6O\nbyliBkyzp2E32/XEWo14RnnlZ+TrQl1Dq3HXmdpz3aUovwiH2UF9oJ7yE+X888g/2V+zv921tRXx\nqBFSQox2jY7Lw0ZfMGDMcZ1BkiTWrFnD/fffz0033YTD4eD6669nwYIF+jU33ngjjY2NPPLII3i9\nXvLz8ykuLtaFVGpqKsXFxTz00ENce+21jBgxgkcffZSLLrqov5Yl6ALRFay1YAHNTNYZH0dnosm6\n42tqiZYjFO03QY2YDbUQY22jS7Ymk2pL7ZZDvSi/iG1fbcMX8tEcbtYrIViMlpgclnhE9GnrUpTW\nyb0qKomWRMYkj4n7xpefkc/7X73fqiRTTnJO3J/yi/KLOFB7gD3VewD0FvCZzsxejSj7rPozDtQd\n0KMXg+EgB+oO8Fn1Z20mN3cU8djTSL2+pF+F0MaNG894/plnnml1LC0tjSeffPKMr7vtttu47bbb\n2j2fl5fHn//8507NUTBwiA7JbhkskGhJ7NSGdKaAAYiNuNN8OUCXa6q1F4WnVXWOtmYF5WC3N7iC\nkQUMdwzjxKw7AAAgAElEQVTn6MmjeokgRVJQlMgP9sh1PcnTiUarVdfSGichkWJL6ZUn76L8Iqp9\n1VQ0VCAhkWZPI8uV1SvdPgtGFvDY5Y+xrmydXo8wPzO/1zf01R+vbrOx3ZqP17TSjuMd8djfDCpN\nSHB201ZItqYFRVewPhPtBQxAay1IE0Ba+ZyuaCqhcAitn02kgPbpSCvNDGc2mMlx5ZDtyu5R3a6T\nwZMEw8HTTeNUlTBhZFXucSBCexgkw2lT46l19tRf1h4FIwtYMn0Jb5S/wdGTR+MSBdfReH2tQRys\nOxiTf6X59srryoHT2k9ZVRmHGw6TYk8hw5ER6WfVw4jH/kYIIcGgIF5mMohEWrUsFgk9i7hrieZ7\nUlU1pn9RdGSXw3LaRNYTan21MdFq0WHTmhkuXgIozZ5GY3NjROBJp9fjtDg77S/rDv0hGPqSsBqO\naX2uva/BcJDbNt/GWwff0s3PWp3EgBxgtGt0XBKC+xMhhASDgngJCLvZ3srxrKFF3EX7miCy0Xb1\n6TLNnkZADkQ0lPDpxM7oSLygHHny7amJLKgE9Y6x0eNoml48N6YZ2TOoD9RzInAiJiQ805k5YMrA\nDEYSLYkxCdMqKmEljIQU03ZD8/1oYdjxSgjuTwZMdJxA0B49DcmOJseVQ7I1WRdCWkdRzQfUnYi7\ntpiRPYNES+LpvJZT/0WnAbisrrhsHK4Elx7xp3VvlSQJo8FIfmZ+3B333xz1Tca4xpCUkESiJZGs\npCwW/8viQbkBDhQyEzOxGq2nGxKq6EVvm4JNej6ZrMiElJCeOqAlBA9WAQRCExIMcFqGZEcHI6TY\nUrpcJ2xSxiTq/HUxFYubw82cDJ6kxleDoii4rK4uRdy1RXTUmqzIKEqk143FYMFusjN15NS4CYgZ\n2TOoaKwgrIRjTDl2s71VAEFP6Wv/zNlCjiuHoyeP0tDcEOlDhXI6iAV0s65WP09rmnfN+GsGRCXs\nniCEkGBAo0UCZSVlsa92n+6E7a6AyHHl6BWLk0ii3h8xLVmNViwmCzIyJwInuhRx1xZa1Fq1rxqr\natVrgpkMJiwmC+mO9LiZr4ryi3j7i7ep89fRHI7USLSarOQNz2uznXlPGer+mf5AM/2GlbD+MKGh\n5V9pIf+aFp/lyhoSJlAhhAQDlujaZ3azPaYqc3d9HYcbDutVkn2yT8+6bw43o6DoyaNApyPu2kMz\nG0JshWSJ+PppCkYWcPm5l1NWVaZXks5yZXWYcS8YOBz3Hqc+UB8RNlECSIt4tJqskYreBhPp9nRm\n5MwYNHlAHSGEkGBAEm2G0/q4eENevZxJd5Mud3l28WX9lwSVoG7aiG46p4XJ+mRfj58yh1mHUdUU\nKTEV3XL8vNTzeiWXRuv8Gc1QeFI+G9hfs5+wGhE4LRsHKqqCxWghyZLEwzMf7rc23L2FEEKCAUlL\nM5xGRUMFafa0bm+uhxsO09DcAJxu8AWRL75We01RFcYNG9djQTEpYxIqKhUNFTEaSm+EMmtzFb6a\nwUlDMPKZNBqMSKqkh2trLSvGDRvH7VNvH3ICCIQQEgxQtF4+vpAvxkHb05BjX8hHs9yslzfRkWJ7\n89w+9fYezR8i1ZErGytJs6fFHO8t7UT4agYvrgQXdf46PewdImHaRoOR/Iz8QVEDrrsIISQYcET3\n8gFiOqZOzpjcoy+jP+Q/XS1BK9PP6X/bTXamjZwWlydOoZ0IOkvL/CstiCUrKWtICyAQQkgwAGmr\nl4/WMXXJ9CU9undzuDnypCmhmz0kJBJMCfzwvB8CEf9KvBDaiaAzaPXx9lXvo9pfjUQkqOVsyL8S\nQkgwoGjZy8cb8lIfqCfTmRmX2mRWkxWL0aKb4jTTh1EyxqULqEDQHc7m/CshhAQDCq08T3RhRqBL\nvXzOxOjk0XrCq5a747Q4OTf53EGf9CcY3JytWrMo2yMYMLQsz6N1BIVIrbh4OPTnTJqD1WTVy/6k\n2lOxmqzcOunWHt9bIBB0HaEJCQYE8S7P0x5awMGGXRvwNHnIcGZw66Rbh2Toq0AwGBBCSDAgiHd5\nnjMxJ2+OEDoCwQBBCCHBgKC38oIEAsHARgghQb/Tm3lBAoFgYCMCEwT9Tkl5CVlJWa2OVzRUiNpn\nAsEQR2hCgn4lulJ2tBnOYXbEJS9IIBAMbIQQEvQbLStlR5vhtErZAoFgaCPMcYJ+o7ismB1VO1rl\nBVU0VACiDYFAcDYgNCFBv7D+k/Vs2rdJr1pgNpj1vKCedDQVCASDCyGEBH2Ou9LN6o9X679rzeWS\nrcmk2FJ63NFUIBAMHoQ5TtDnlJSX4Av5cJgdMce11t3CDCcQnD0ITUjQ5+zy7KI+UI9f9uvdIzUu\nzr5YaEECwVmEEEKCPkVLTLUYLfhlvy6Akq3JpNpS41qeRyAQDHyEOU7Qp2gN6xqaG1BVVT8elIPc\nPvV2oQUJBGcZQhMS9BltNayTFZlMZyYTUieIoqICwVmIEEKCPqO4rFj3BUW37Y5XwzqBQDD4EOY4\nQZ+gaUEWowWIhGXXB+oJyAEREScQnMUITUjQJ2htu1UifiDNFBeUg1xx7hXCFyQQnKUIISTodaLb\ndjeFmnBanKTaUwGQkEREnEBwFiOEkKBX6au23QKBYHAifEKCXiW6bTeAzWwj1Z5Kii0l7m27BQLB\n4ENoQoJeRbTtFggEZ6JfNaH77ruPpUuXxhx79tlnKSwsJC8vjyuvvJKXX3455nxtbS133nknF154\nIRdddBErVqxAluWYa5555hkuvfRSJk2axLx58zh06FDM+d27d3PDDTcwadIkvvvd7/LKK6/0yvrO\ndqLbdkf3C8pNzRVFSgUCAdBPQkhVVZ544glefPHFmOPPPfccK1euZP78+fz1r39l3rx5PPDAAzFC\n4o477qCmpoZnn32W5cuXs2nTJlavPl2R+eWXX2bVqlUsXryYl156iYSEBIqKiggGgwDU1dVRVFTE\nN77xDTZt2sQtt9zC0qVL+eCDD/pm8WcRom23QCDoiD4XQhUVFdx66608//zzjBgxIubcCy+8wI9/\n/GNmz55NdnY2119/Pddccw2bNm0CYOfOnezYsYPly5eTm5vLJZdcwqJFi9i4caMuZIqLi5k3bx6F\nhYWMHz+elStXUltby5tvvglEhJTT6WTp0qWMHTuWW265hWuuuYY//OEPfftGnAXs8uyiorGCQChA\nY6CRZrkZp9kp2nYLBAKdPhdCZWVlZGZmsnnzZkaNim3f/F//9V/ccMMNMccMBgONjY0AlJaWMnLk\nSLKyTj9dT506Fa/Xy969e6mtreXQoUNMnTpVP+9wOJg4cSKlpaX6PQoKCjAYDDH3KCsri6llJugZ\n6z9Zz0dHPuLgiYM0hZqwmCwkmBLIcmWJ6ggCgUCnzwMTZs+ezezZs9s8Fy08AI4ePcqWLVu4+eab\nATh27Bjp6ekx12i/V1VVYTJFljN8+PBW13g8HgA8Hg/nnXdeq/N+v58TJ05wzjnndHNlAo31n6xn\nybtLOBk8qXdO1ZrWVTRUsGT6kv6eokAgGCAM2Oi4uro6brvtNlJTU/nZz34GgN/vJyEhIeY6s9mM\nJEk0Nzfj9/sBWl1jsVhobm4GIBAIYLFYWp0HdJOeoPtoXVO1+nAQKdEjIRGUg8IUJxAIYhiQQqii\nooKioiICgQDPPvssiYmJAFit1laCIhQKoaoqdrsdq9UKtBYmwWAQm83W7j2037VrBN1H65qqaT8m\ng0n/cVldwhQnEAhiGHDJqp9++ik/+tGPMBgMvPDCCzH+n4yMDKqrq2OuP378OBAxwWVmZgK0eY1m\nomvvHna7XRd2gu6jdU0NyAECcgBZiYTPy4qMw+wQUXECgSCGASWEDh48yE9+8hNGjhzJc889pwsV\njSlTplBRUUFVVZV+bPv27TgcDnJzc0lJSWH06NF8/PHH+nmv18uePXsoKCjQ71FaWhoThLB9+3by\n8/NjghUEXSe6a6qm/ciKTFgJYzfZRdM6gUDQigG16y5evBiLxcJjjz2GLMtUV1dTXV1NXV0dAJMn\nTyYvL4+FCxfy6aefsnXrVlasWMG8efN0v87cuXNZu3YtW7Zs4cCBA9x9992kp6dz+eWXA3DddddR\nV1fHsmXLOHjwIBs3buS1116jqKio39Y9VNDygmxmG64EF1aTFavJSqIlkYdnPiya1gkEglYMGJ/Q\nl19+ye7duwEoLIw12WRnZ/P2228jSRJr1qzh/vvv56abbsLhcHD99dezYMEC/dobb7yRxsZGHnnk\nEbxeL/n5+RQXF+tCKjU1leLiYh566CGuvfZaRowYwaOPPspFF13Ud4sdgmiVsr1BL6hgN9uxm+04\nzA6yXdlCAAkEgjaRVJEc0ymOHDnCzJkzeffdd1vlN53taJWyd1TtwBvy6scnpE4gzZ7GqKRR3HvJ\nvf04Q4FA0F90tHcOKHOcYHDSslK2RkVDBYAIRhAIBO0yYMxxgsFL1clIoEi6I5I4fKTxCN6QV1TK\nFggEHSKEkKBHuCvd7K/dj6fJg91sJ9uVTX5mPgCjkkYJASQQCM6IMMcJuo3mC3IluFBR8Ya87K3Z\nS7UvkoclzHACgaAjhBASdBvNF5TuSCc3JRen2YmEREOgQZjhBAJBpxDmOEG3iA7JbmmGM0gGIYAE\nAkGnEJqQoMtoZjhVVds0w41IHNHBHQQCgSCCEEKCLiNCsgUCQbwQ5jhBlxEh2QKBIF4IISToMpmJ\nmVQ2VgIRQaQJIxGSLRAIusoZhdArr7zSpZtde+21PZqMYODirnRTUl5C1ckqFFWh2ldNmj0t5hph\nhhMIBF3ljELol7/8JZIkAdBRiTlJkoQQGqJogQjRqKqKJElISIxIHEHhuEKhBQkEgi5zRiGUkZGB\nx+PhvPPOY9asWcycOROHw9FXcxMMELRAhGjSHemMTBwpCpMKBIIecUYh9Pe//52dO3fy+uuvs2HD\nBp588kkuvvhirrrqKr797W/r7REEQ5tdnl0cbjiML+TTc4LS7GkcPXm0v6cmEAgGOR2GaE+ePJml\nS5fy/vvv8/vf/57U1FQeeOABLrroIv7jP/6D9957D1mW+2Kugn5A65bqDXlb5QSJfCCBQNBTOp0n\nJEkSU6dO5b777mPbtm2sWbMGu93O0qVL+da3vsXSpUt7c56CfqK4rBhv0IunyUONr4aAHAAiOUEi\nEEEgEPSUbiWrGgwGpk2bxqxZs7jsssvw+Xxs2rQp3nMT9DPuSjfbvtoGErgSXADUB+qRkMh2ZYtA\nBIFA0GO6lCekKAofffQRb7zxBu+88w719fXk5uby85//nFmzZvXWHAX9REl5CXazHW/Ii81sw2a2\nAeAwO8jLyOvn2QkEgqFAh0JIlmX+8Y9/8MYbb/C3v/1NFzxz585l1qxZZGdn98U8Bf3ALs+uiCnO\n68FkMOG0OLGarHhDXmGKEwgEcaHDPKH33nuPxsZGxo8fz9y5cyksLGT06NF9ND1Bf6EFJGimOG/I\nS32gnkxnJhdnXyxMcQKBIC50WDHBYDAwZcoUxowZQ2VlJevWrWvzWkmSePDBB3tlkoK+p6S8hKyk\nLPbV7mtlivtp/k/7eXYCgWCocEYhNGJEJAT36NGjHD165pwQrbKCYGhQdbKqVYFSh9khAhIEAkFc\nOaMQ+tvf/tZX8xAMINyVbvbX7sfT5IlJToVIkVKBQCCIF50K0Q6Hw9TV1fX2XAQDAK1OnCvB1WbD\nOhGQIBAI4skZhZCqqvzmN79h2rRp/Mu//AtTpkxh5cqVBIPBvpqfoI/R6sSlO9LJTcnFaXYiIdEQ\naBC9ggQCQdw5ozlu7dq1/P73v+db3/oW5513Hl9++SXFxcU0NjbywAMP9NUcBX2I1rAOYnsFGSSD\nEEACgSDudBgdd8stt8SU5Fm3bh2rVq3i3nvvxWQSPfGGGoqqsKNqR6tipaJOnEAg6A3OaI47cuQI\nM2fOjDl21VVX0dzczJEjR3p1YoK+x13p5rj3eJvFSoUvSCAQ9AZnVGWCwSB2uz3mWEpKCgA+n6/3\nZiXoF0rKS9oMy063pwtTnEAg6BW6bE/rbKdVweCjZd+g3NRc0uxpIgdMIBD0Gt126oiNaWjhrnTr\npjdZkTEZTNT6a5mcMZnJGZP7e3oCgWCI0qEQ+p//+R/OOecc/XdNA3rqqacYNmxYzLW/+tWv4jw9\nQV/xyAePcPTkUfyyH4NkwGQwISsy+2r2sWT6kv6enkAgGKJ0WLZn7969bR7/7LPPYo4JzWjwovUN\nkiQJi9GCrMgEw0FMhsjHQ/iDBAJBbxGXsj2KovD888/HZUKCvqe4rBhfyIesyLoWpP04Lc7+np5A\nIBjCdGiOe//99/nLX/6CwWDgmmuu4ZJLLok5X1paykMPPcT+/fu56aabem2igt5B04LMBjOyIqOo\nCsHw6YoY+Rn5/Tg7gUAw1DmjEPrrX//KokWLMJvNWCwWXn/9dVatWsXll19OfX09Dz30EFu2bMFo\nNDJv3ry+mrMgTrgr3Sx+Z7FeF84oGVFRUVQFRVXIdGSKtg0CgaBXOWOy6vr165k0aRIfffQRH330\nEVdeeSVPPfUUhw4d4nvf+x6vvfYa06dPZ/PmzSxatKjLg993330x1RgAPvjgA2bPns0FF1zA1Vdf\nzdatW2PO19bWcuedd3LhhRdy0UUXsWLFCmRZjrnmmWee4dJLL2XSpEnMmzePQ4cOxZzfvXs3N9xw\nA5MmTeK73/0ur7zySpfnPtjRCpV6mjw4zA4kScJoMGI1WbGb7djNdhZPXyz8QQKBoFc5oxA6dOgQ\nc+bMwel0YrFYWLBgAfv27WPBggUEg0GeeOIJ1q5dy5gxY7o0qKqqPPHEE7z44osxx8vLy5k/fz6F\nhYX85S9/YebMmSxYsIDPP/9cv+aOO+6gpqaGZ599luXLl7Np0yZWr16tn3/55ZdZtWoVixcv5qWX\nXiIhIYGioiK96GpdXR1FRUV84xvfYNOmTXpZog8++KBLaxjsFJcVs6NqB9W+arwhLzaTDavJitlg\nZtywcfwg9wfMyZvT39MUCARDnDMKIZ/PR2Zmpv77qFGjUFUVo9HIX//6V6644oouD1hRUcGtt97K\n888/rzfN09iwYQN5eXnMnz+fsWPHctdddzF58mQ2bNgAwM6dO9mxYwfLly8nNzeXSy65hEWLFrFx\n40ZdyBQXFzNv3jwKCwsZP348K1eupLa2ljfffBOICCmn08nSpUsZO3Yst9xyC9dccw1/+MMfuryW\nwcr6T9azad8mDp44SCgcIiAH8Mt+nBYnqfZU8jPzhRlOIBD0CR22cjAajfrv2r/vuusuvXxPVykr\nKyMzM5PNmzczalRsg7TS0lKmTp0ac2zatGmUlpbq50eOHElWVpZ+furUqXi9Xvbu3UttbS2HDh2K\nuYfD4WDixIkx9ygoKMBgMMTco6ys7KyoAuGudLP649OaY3RovTfoJdOZKVo2CASCPqNbFROGDx/e\n7QFnz57N7Nmz2zzn8Xha3Ts9PR2PxwPAsWPHSE9Pb3UeoKqqSq/qfaZ7eDwezjvvvFbn/X4/J06c\niEnMHYoUlxVzuOEwATmgV0bQflLtqSy/bLkQQAKBoM/olhDqrcTUQCCAxWKJOWaxWGhubgbA7/eT\nkJAQc95sNiNJEs3Nzfj9foBW10Tfo70xgCHfrE8Lxwb0RFRZkZGQMBlMXJx9sRBAAoGgT+lQCD30\n0EM4nZGERc1c9cADD+BwOGKukySJdevW9WgyCQkJhEKhmGPBYBCbzQaA1WptJShCoRCqqmK327Fa\nrfprunIP7XftmqFKcVkx9YH6GC3IarJiMpgY7Rot/EACgaDPOaNPqKCgQBcMoVAIWZYpKCjAYrHo\nx7SfeGgRmZmZHD9+PObY8ePHdfNaRkYG1dXVrc5DxASnBVG0dU1H97Db7SQmJvZ4DQMVTQuyGC26\n+U1WZMJKGIDbp94utCCBQNDnnFET2rhxY1/NA4ApU6bgdrtjjm3fvp0LL7xQP//f//3fVFVV6QJn\n+/btOBwOcnNzsVgsjB49mo8//lh/jdfrZc+ePdxwww36PTZt2oSqqrpZcfv27eTn58cEKww1SspL\nsJvtqES0WW/Ii6zI2E12rv761SIcWyAQ9AsDate9+eabKS0tZdWqVRw8eJAnnniCXbt2MWdOZIOc\nPHkyeXl5LFy4kE8//ZStW7eyYsUK5s2bp/t15s6dy9q1a9myZQsHDhzg7rvvJj09ncsvvxyA6667\njrq6OpYtW8bBgwfZuHEjr732GkVFRf227r6g6mQVWUmRqEKb2UaqPZUMZwYuq0uY4QQCQb/R7X5C\nvcH48eNZs2YNK1asYO3atZx77rk8/fTTjB07Foj4ndasWcP999/PTTfdhMPh4Prrr2fBggX6PW68\n8UYaGxt55JFH8Hq95OfnU1xcrAup1NRUiouLeeihh7j22msZMWIEjz76KBdddFG/rLkvcFe62V+7\nH0+TB9TTgSUOs4MpmVOEGU4gEPQbkno2JMfEgSNHjjBz5kzefffdVvlNAxmtPM9x73H21e7Tj09I\nnUCaPU3kBAkEgl6lo71zQGlCgviiFSj1NHmwm+1kODJoCjbhDXlpCDSwZPoSIYAEAkG/IoTQECW6\nQKmKijfkxRvy6hqQQTIIASQQCPqdARWYIIgfJeUlANjN9pjjFQ0VAIxIHNHqNQKBQNDXCE1oiLLL\ns4vDDYep9dXSFGrCaXFiNVnxhrwAFI4r7OcZCgQCgRBCQxJ3pZvDDYfxhrxYzVZUVJqCTUhIjEke\nI4IRBALBgEEIoSFIcVkx3qAXj9eDyWDSWzQ4zU5RoFQgEAwohE9oiKEXKZXAleACoD5Qj4REtitb\nCCCBQDCgEJrQEEMrz+MNebGZbdjMkaKsDrODvIy8fp6dQCAQxCKE0BBjl2dXK1OcFpAgghEEAsFA\nQ5jjhhBaQEJbpjjRK0ggEAxEhCY0hGgrIMFqsuIwO0SRUoFAMCARmtAQQQQkCASCwYjQhIYIIiBB\nIBAMRoQQGiKIgASBQDAYEea4IYAISBAIBIMVIYSGACXlJW12TRUBCQKBYKAjzHGDHHelm80HNuMN\nelt1TRUBCQKBYKAjhNAgRusZpKoqKipIoKLqPYNGJQ2eDrACgeDsRAihQYq70s38LfM53HCYUDiE\nJEkkW5OxmqxUNFSQZk8TAQkCgWDAI3xCg5D1n6zn1r/cyu7ju2kKNhFWw8iKTH2gnma5GUmSRLsG\ngUAwKBBCaJDhrnSz+uPV1PhrMEgGFFUhGA4CYDKYSLGlcPXXrxYCSCAQDAqEEBpklJSX4Av5kBUZ\nk+G0NVVWZGRFFnlBAoFgUCF8QoOMqpNVAATDQWRF1o8rqoLdZBd5QQKBYFAhNKFBhqIq+EI+DFLs\nn85utjNt1DSRFyQQCAYVQggNQmxmGym2FGwmGwbJgEEykOnIZMn0JUILEggEgwphjhtEuCvdlHnK\nCIQChMIhzrGdQ4othVFJo8hwZggBJBAIBh1CCA0SohNTrWYrVrMVgCxXFmn2NEYkjujnGQoEAkHX\nEea4QUJxWTE7qnZQ66ulxldDQA4AUNFQASAi4gQCwaBEaEKDAHelm7e/eJuTwZPIioyqqtQH6hlm\nHUaiJVEkpgoEgkGL0IQGAcVlxboAgtNFSq0mq0hMFQgEgxohhAYBZZ4yHGZHq+M1vhphhhMIBIMa\nYY4bBHiDXrwhL7Iio6gKRslIgimBVHuq0IIEAsGgRgihAY670o2qqq3K9DgtTi7OvrgfZyYQCAQ9\nR5jjBjDuSjeL31lMQA6gqqp+3GQwYTPaRHUEgUAw6BGa0ABFywvyNHmwmq0kk4w35CXRkkiKLUV0\nTRUIBEMCIYQGKFpeULWvGoiY31LtqTjNTvIz80XXVIFAMCQQQmgA4q50s+2rbaioOMwOGpobqA/U\nk2xNRiISni2i4gQCwVBgwPmEfD4fv/rVr5g+fToXXnghRUVFlJeX6+c/+OADZs+ezQUXXMDVV1/N\n1q1bY15fW1vLnXfeyYUXXshFF13EihUrkGU55ppnnnmGSy+9lEmTJjFv3jwOHTrUF0vrNMVlxdQH\n6vE0efCGvNhMNkwGE96gl0xnpkhOFQiGIE899RTf+c53Yo41NTUxefJkmpqauOWWWxg/fnzMz/nn\nn8/MmTN5/PHHCYfD+uu+853vxFw3YcIEfT/dt29fq+uee+65NudUVFTE+PHjefXVV3tn0QxAIfTr\nX/+af/zjHzzxxBO8+OKLJCQkUFRURHNzM+Xl5cyfP5/CwkL+8pe/MHPmTBYsWMDnn3+uv/6OO+6g\npqaGZ599luXLl7Np0yZWr16tn3/55ZdZtWoVixcv5qWXXtLvHwwG+2O5rdC0IIvRAkSa1fllv26O\nW37ZciGABIKzhI8++oiJEyfidDoBuOqqq/jggw/0n1dffZXrrruOp59+mnXr1sW89t/+7d/06/7+\n97+zfv16mpqamDdvHk1NTfp1ZrOZN998s9XY9fX1/POf/+zdBTIAhdA777zDj3/8Y6ZMmcLYsWNZ\nuHAhVVVVlJeXs2HDBvLy8pg/fz5jx47lrrvuYvLkyWzYsAGAnTt3smPHDpYvX05ubi6XXHIJixYt\nYuPGjbqQKS4uZt68eRQWFjJ+/HhWrlxJbW1tm3+E/kDTghqaG2Ii4oJyUDSsEwxJ3JVuHtz6IPNf\nm8+DWx/EXenu7ykNGLZt28bFF59OxbBaraSlpek/5557LvPnz+eb3/wmJSUlMa+12+36dcOHD+cb\n3/gGixcvpq6uLka4fPOb38TtdlNXVxfz+rfffptJkyb17gIZgELonHPO4fXXX6e2tpZgMMif//xn\nXC4XWVlZlJaWMnXq1Jjrp02bRmlpKQClpaWMHDmSrKws/fzUqVPxer3s3buX2tpaDh06FHMPh8PB\nxIkT9Xv0Jy21IK08T7I1GZfVJUKyBUMOLQq0srESRVWobKykuKy4TwTRpk2bmDVrFhMnTuTSSy9l\n1SxV374AACAASURBVKpVKIrC6tWrmTt3Lo8//jgFBQVMmzaNhx56KMZaUlVVxc9//nPy8/P51re+\nxcKFCzl27Jh+XlEUnn76aS699FLy8vL4wQ9+0Mp18PrrrzNr1iwuuOACioqKOHHiRKs5btu2jRkz\nZnS4FovFgtFo7PA67RqLxaIfmzx5Mqmpqbzzzjsx15aUlHDllVd2eM+eMuCE0K9+9Ss8Hg/f+ta3\nyMvL46WXXuL3v/89SUlJeDwehg8fHnN9eno6Ho8HgGPHjpGent7qPEQ+NNp1Z7pHfyK0IMHZRkl5\nSZvH3yh/o1fH3bdvH/fddx8LFy7krbfe4p577mHdunX89a9/BSIPtDt37mTjxo089thjvPHGGzz0\n0ENAxG99yy23kJCQwAsvvMC6desIhULMmTNHF1QrV65k06ZNPPjgg7z66qt873vf4/bbb2f79u0A\nuN1ufvGLX/C9732PV199lenTp/OnP/0pZo7l5eXIskxubm676wgGg7zyyit8+OGHXHPNNWdcc0VF\nBStXriQtLY38/Hz9uCRJfPe7342xBtXV1eF2u7niiiu68K52jwEXHXf48GFSU1O5//77SU5OZt26\ndfz85z/npZdeIhAIxEhwiEj05uZmAPx+PwkJCTHnzWYzkiTR3NyM3+8HaHVN9D36i/WfrGfTvk0E\n5IBeHcEkmUi2JmMzicRUwdCk6mRVm8ePnjzaq+NWVFQgSRIjRozQf/74xz+SkZFBRUUFRqORxx9/\nnJSUFHJzc7nrrru4//77WbRoESUlJfj9fpYvX65rFr/5zW+YNm0ab731FpdeeikbNmxg9erVuhaT\nk5PDvn37+P3vf8+0adP405/+xLRp0/jZz34GwJgxY9i5cye7d+/W59iWFvTKK6/w+uuv678HAgFy\ncnJYsmQJN998c8y1Tz31FGvXrgUgFAohyzLnnXcea9as0X1MGoWFhcydO5eGhgZcLhdvvfUW+fn5\npKamxukdb58BJYQqKiq49957ee6558jLywMiTxRXXnklzzzzDAkJCYRCoZjXBINBbDYbELGXtgww\nCIVCqKqK3W7HarXqr2nvHv3B+k/Ws+TdJTQFI85CCQlZkZGQCMpBrjj3CqEFCYYkmYmZVDZWtjre\n200aZ8yYwaRJk/jBD35ATk4O06dPp7CwkBEjIuOee+65pKSk6Nfn5eURCoX48ssv+eyzz6irq+PC\nCy+Muaff7+fgwYNkZ2cTDAa58847MRhOG5tCoZC+qX/++edccsklMa/Py8uLEULvv/8+P/zhD2Ou\nueyyy/jFL36BoiiUlpby6KOPctlll3HLLbe0WuNNN93Ej3/8YyBihktOTm4lfDSmTJnCsGHDePfd\nd/n+97/fZ6Y4GGBCaM+ePYTDYSZOnKgfM5vNTJgwgcOHD5OZmcnx48djXnP8+HHdvJaRkdHK7qpd\nP3z4cDIzMwGorq4mJycn5pqxY8f2ypo6wl3pZvXHq/HLfkwGE8FwREBajBYSTAnCFyQY0swaN4vi\nsuJWx3s7D85qtfLss8+ye/du3n//fbZt28af/vQn7rjjDgBMptitUQt/NhgMmM1mxo0bx5o1a1rd\nNzExUd9zVq9eHbPPaK+HiAks2uQOkb1Ow+/388knn/DEE0/EXON0OvV7jhkzhsTERO68806SkpJ0\nrUrD5XK1Gr89JEniiiuu4M033+Tb3/42ZWVlPP744516bU8ZUD6hjIwMAPbv368fU1WVgwcPMnr0\naKZMmYLbHeuw3L59u/5EMmXKFCoqKqiqqoo573A4yM3NJSUlhdGjR/Pxxx/r571eL3v27KGgoH80\njeKyYg43HNbNcEbJiEEy6L2DhC9IMJQpGFlAUX4Ro5JGYZAMjEoa1Sd5cB9++CFPPvkk559/PgsW\nLOCFF17gxhtv1E1dX3zxBV6vV79+165dWK1Wzj33XL72ta9x5MgRkpOTycnJIScnh5SUFB555BEO\nHDhATk4OZrOZY8eO6edzcnLYvHkzmzZtAiA3N5edO3fGzGnPnj36v7dv305ubi5JSUlnXEdhYSFX\nXXUVq1atitk3u0NhYSH/+Mc/eOWVV5g6dSrnnHNOj+7XWQaUELrgggvIy8vjl7/8JaWlpRw8eJBl\ny5Zx9OhRbr75Zm6++WZKS0tZtWoVBw8e5IknnmDXrl3MmTMHiER55OXlsXDhQj799FO2bt3KihUr\nmDdvnu5Lmjt3LmvXrmXLli0cOHCAu+++m/T0dC6//PI+X68WDQeRoqSKqhBWw5gMJqwmK6Ndo4UW\nJBjyFIws4N5L7uV3V/2Oey+5t08eusxmM08++SQbNmygoqKCnTt3sn37dj0kuampiXvuuYfy8nLe\ne+89fvvb3/LjH/8Ym83G1VdfzbBhw7jrrrvYvXu3vo/s2rWLr33ta9hsNubOncvKlSt5/fXXqaio\nYMOGDTz55JN65O6cOXPYvXs3jz/+OF9++SUvvPACW7Zs0ef3/vvvdyoqDmDp0qU4HA7uu+8+FEXp\n9nuSn5+Py+VizZo1fWaKgwEmhIxGI7/73e+YNGkSv/jFL/jRj37EV199xXPPPcfIkSMZP348a9as\n4c033+Taa6/lb3/7G08//bRuSpMkiTVr1pCSksJNN93EPffcw/XXX8+CBQv0MW688Ub+/d//nUce\neYQf/ehHhEIhiouLWwU89AUl5SXYzXYcZgcmgwmL0aJrQXaTndun3i60IIGgF5g6dSoPP/wwL730\nEv/6r//KggULKCgoYOnSpQCMGjWK7OxsfvjDH3Lvvffyox/9iP/4j/8AIqa8P/7xj1itVubMmcON\nN96ILMusX79e9yPddddd3HjjjTz22GPMmjWL559/ngcffJDvf//7AJx//vn87ne/4+9//zvXXHMN\nr776Kj/5yU/0+XU2NBsiaS1Llizhk08+4dlnn+32e2IwGLjiiisIBoN9+lAuqS0Nk4I2OXLkCDNn\nzuTdd99l1Kj4FA+d/9p8PE0e9tXu4/+3d+dRTV7pH8C/CQECgSJiUFywCoLKNhEFRFo9Kp5RwaVH\ncQPX0TljR4S6YtXR0Yq4gK22Utdax2V0Rqb2OM4ZjlvFaRWkRBBkE5SggIAWjAGSvPf3Bz/eGgFx\nAd5Qn885nFPf+yb55sLJ0/e+N/dqtBp+4zqJWIIdgTsw53dzWuV1CCGvbvfu3Th79iwSExOFjvKb\n0NJnp1FNTHjXcIxDUVURarQ10Oq1/DYN3g7eVIAIIe8EKkICSS5ORpm6DGqtGlJTKaSm9dPHe9n0\novtAhJB3hlHdE3qXHEg9wF8FVdVUoVZXCytTK9hb2tN9IEIEtGTJEhqKa0d0JSSA5/cLevEqqGG9\nOEIIeRfQlZAAnt8vqPxZOWp0NQCAol+K2vyb4oQQYkyoCLWzpvYLelLzBDW6Gqi1atoxlRDyTqEi\n1M5opWxCCPkV3RNqR7RSNiGEGKIroXby/ErZDStk6zgd9JyeroIIIe8sKkLt4MWVsp9fI45WyiZE\nGK6urvjuu+9e+fzLly8jLy+vDRO1TKVSwdXV9ZV3gtbpdPjmm2/e6jVLSkrg6urKb8jX2qgItQNa\nKZsQ45OUlITf//7VJgKVlpbij3/8IyoqKto4Vev697//jejoaKFjvBTdE2pjL66U/fx+QRKxhFbK\nJkQgcrn8lc/tqEtsdoTcdCXUxhpmwzV1FUQrZRMinOeH41avXo01a9Zg8+bN8PX1hUKhwLJly/D0\naf1uxw27oM6ePRurV68GADx8+BDh4eEYNGgQ/P39ERkZidLSUv75w8LCsH79enz00UcYMmQILl68\niLCwMGzbtg1LliyBp6cnRo4ciRMnThjkSklJQWhoKBQKBfz9/bF582ZoNJom38OTJ08QFRWFgIAA\nuLm5ISAgADExMeA4DtevX8fKlSv599qwl1FKSgqmT58OT09PjBo1Cjt37kRtbS3/nMXFxVi0aBEU\nCgVGjhyJq1evtkZ3N4uuhNrQ898Jkojru1rH6WAqNoW5xBxbRm2hhUrJb0ZifiK+z/ketbralk9u\nZeYScwS7BCPQ6c23IDh79iymTp2KkydP4v79+4iIiICTkxMWL16MhIQETJ48Gbt378bQoUPx7Nkz\nhIWFQaFQ4OTJk9Dr9fjyyy8xZ84cnD17lt8a5vTp04iLi8P777+Pnj174vDhw/j2228xY8YMJCQk\n4KeffsKmTZtgbW2NoKAgKJVKzJ07F2FhYdi4cSNUKhU2bNgAlUqF+Pj4RplXrVqFx48fY+/evejU\nqRN++OEHbNq0Cd7e3vjwww+xfv16/PWvf0VSUhKsra2RlZWFBQsWIDw8HDExMXjw4AE+++wzlJeX\nIzo6GlqtFn/4wx/QpUsXnDhxAk+ePMG6deveuE9fBRWhNnQ+7zwA8Fs0cIyDqdgU1mbWCHYJpgJE\nflMS7yYKUoAAoFZXi8S7iW9VhDp16oS1a9fCxMQEffr0gb+/P9LS0gCA32XUxsYG1tbWOH36NDQa\nDbZu3QoTExMAQGxsLHx9ffHf//4XQUFBAOo36nzxvpOLiwu/b5GTkxOUSiWOHj2KoKAgHDp0CO7u\n7li1ahXfvmHDBixatAi5ubmwsLAweK4PPvgAvr6+6NevHwBg1qxZOHDgALKzszF69GhYWVkB+HXo\n8eDBgxg+fDgWLKi/BdC7d29s3LgRM2fORGRkJLKyslBQUICDBw+ie/f61VvWrl3baOvw1kRFqA0p\nS5R4pn3GfyeogZnEjO4Dkd+cwL6Bgl4JBfZ9u43YHB0d+YICANbW1gbDa8/LzMxEZWUlBg8ebHBc\no9EgPz+f/3dT++cMGWI4/O7l5cUvmJqbm8sP/TVoeI3c3Fx4enoatM2YMQMXLlzA6dOnUVhYiOzs\nbJSUlDS7w2pWVhbu3bsHhULBH2u4b5Sfn4/c3FzY2tryBaghX1uiItRGkouTkVqSyq+M0LAwqUQs\nQReLLnQfiPzmBDoFvtWViNCa2l25uRv7pqamcHZ2xp49exq1WVtb8/8tlUobtUskhh+7HMfxnw9N\nnd+QoanHLVq0CAUFBQgODsbEiRPh6emJOXOaH2ExNTXFpEmTsHDhwkZtcrkcmZmZjd6zqalps8/X\nGmhiQhtILk7GgdQDwP//Lhv+wDpJO6GLZRc42jgKmI4Q8rpeXN2+X79+UKlU6NSpE3r37o3evXvD\nzs4O0dHRyMnJeelzZWRkGPw7LS0NAwcOBFA//Pbzzz8btN+8eZNve15mZiaSkpKwe/duREZGYvz4\n8bC1tcWjR4/4QvJibmdnZ+Tn5/OZe/fujcrKSsTExECtVmPAgAF4/PgxCgsLm83b2qgItYGGe0F2\nlnawMbfhh+LqdHXob9cfv+v2OyHjEUJek0wmAwBkZ2fj8ePHCA4Ohq2tLSIiIpCeno6cnBwsW7YM\nSqWSvz/TnJ9++gnx8fEoKCjAt99+i/Pnz2P+/PkAgIULFyI9PR0xMTG4e/curl69io0bN2L48OGN\nipBcLodEIsH58+ehUqnw888/Y/Hixairq0NdXZ1B7vT0dKjVaixcuBC3bt1CdHQ08vPzcePGDaxa\ntQrV1dWQy+Xw9fWFm5sbVqxYgfT0dKSmpmLz5s2t3Z0GqAi1AWWJEjcf3kTFswqotWpYmVmhm1U3\n2EhtYC+zp5WyCelgrKysEBYWhh07dmDt2rWQSqU4fPgwpFIp5syZgxkzZkCn0+HIkSOws7N76XON\nGTMGt27dwsSJE3HixAls374dI0eOBFA/aSE+Ph43btzAhAkTEBUVhcDAQHz++eeNnqdr167YsmUL\n/vOf/2Ds2LFYsWIFvLy8MGHCBKSnpwMAfH194ePjgxkzZuDUqVNwdXXF119/jdTUVEyaNAkREREY\nMmQIP6xoYmKC/fv3w8HBAbNnz8bSpUsxd+7c1u3MF4hYR/g2kxFQqVQYNWoULly40OTNxgbJxcn4\n07k/Qa1VAwA0Wg3UWjWszazRp1MfbB29le4HEfKOCgsLg6OjIz777DOho7Sblj47aWJCKzuQegDq\nOjVK1CWQiCWwMrNCF8susDK1ogJECCEvoOG4VtSwVUOJugSMMX7DOhFEcLRxpAJECCEvoCuhVtKw\nUnaD52fEyUxlNBmBEIKjR48KHcHoUBFqJdFJ0ch6lIU6rg5g9QuUmknM8LTuKSwkFjQZgRBCmkDD\nca3gSNoRXCq8BA4cxCIxIAJq9bWo09VPk6StGgghpGlUhFrBEeWR+q26///7QGKRGCbi+uU/aKsG\nQghpHg3HtYLsimxU11ZDy2khYiKIxWKIRCJw4GirBkIIeQkqQm/pSNoRVGoqoeN0YIyBgYHjOMjM\nZOhv159WyiaEkJeg4bi3FHMtBjpOBz3T88dEIhF0nA5/9vmzgMkIIcT4URF6C8nFySh4UlB/D0hU\nfw+IgUEEESQiCV0FEUJIC2g47i2czzsPsUgMjnEwEZvABPWFSCwSw0ZqI3A6QggxfnQl9BYeVj+E\n3FLe6DjHOPh09xEgESGEdCxUhN6Cg7UDFN0U6CztzE/Plogl6G7VHVEfRAmcjhBCjB8Nx72Fsc5j\nUVxVDL+eflBVqaDWqiEzldG0bEIIeUVUhF6RXl8/+62kpIQ/5gAHTOw+EVcKr8BGaoOudl0x/P3h\n8OziCZVKJVRUQggxGg2fmQ2foS+iIvSKHj16BACYNWvWS8/7F/7VHnEIIaRDefToEXr37t3oOG1q\n94pqamqQkZEBuVwOExMToeMQQkiHoNfr8ejRI7i7u0MqlTZqpyJECCFEMDQ7jhBCiGCoCBFCCBEM\nFSFCCCGCoSJECCFEMFSECCGECIaK0FvQ6/XYuXMnAgICoFAoEB4ejvLycqFjNSsvLw+urq6NflJS\nUgAASUlJmDhxIjw9PREcHIwrV64InLje+vXr8emnnxocaylrRUUFli5disGDB2Po0KHYvn07dDpd\ne8bmNZV/ypQpjX4Pz58jdP7y8nKsWrUKAQEBGDx4MBYsWICcnBy+3dj7v6X8xt7/JSUlCA8Ph4+P\nDwYPHozIyEiUlpby7cbe/6+FkTcWFxfHhg0bxpKSklhGRgabOnUqmz59utCxmnXu3Dnm6+vLysrK\nDH7q6upYbm4uc3d3Z1999RXLy8tjcXFxzM3NjeXk5AiWl+M4tmvXLubi4sLWrFnDH3+VrDNmzGAz\nZ85kWVlZ7PLly8zPz4/FxsYaRX6O45iXlxc7e/aswe+hurraKPLr9Xo2bdo0FhISwpRKJcvNzWXh\n4eFs6NChrLKy0uj7v6X8xt7/HMex4OBgNmfOHJaVlcWysrLYrFmz2OTJkxljHefv/1VREXpDtbW1\nTKFQsH/+85/8saKiIubi4sJu3rwpYLLmxcXFsVmzZjXZtm7dOhYaGmpwLDQ0lK1du7Y9ojVy//59\nFhoaynx9fdmIESMMPsRbypqamspcXFzY/fv3+fYzZ84whULBamtrBc9/7969RvmeJ3T+27dvMxcX\nF5aXl8cfq62tZV5eXiwhIcHo+7+l/Mbe/2VlZSwiIoIVFRXxxxITE5mLiwt78uSJ0ff/66LhuDd0\n584dqNVq+Pj8umVDz5490aNHD354y9jk5uaib9++TbalpKQYvBcA8PX1Fey9pKamwsHBAd9//z16\n9uxp0NZS1pSUFPTo0QO9evXi2318fKBWq5GVldX24fHy/Dk5OZBKpejRo0eTjxU6v4ODA77++mv0\n6dOHPyYSiQAAv/zyi9H3f0v5jb3/5XI54uLi+L+bkpIS/P3vf4eHhwdsbGyMvv9fFxWhN9SwKF/X\nrl0Njtvb2xsscmpMcnNz8eDBA4SEhGDYsGGYO3cubt26BaD+/RjTe5k4cSK2bdsGubzxfk0tZS0t\nLYW9vX2jdgB4+PBhGyU29LL8ubm5sLa2xvLlyxEQEIDg4GAcPnwYHMcBED6/ra0tRowYAbH414+H\no0ePoqamBgEBAUbf/y3lN/b+f97ixYsxfPhwKJVKbN68GUDH+Pt/HVSE3pBGo4FYLIapqanBcTMz\nM9TW1gqUqnk1NTUoKirC06dPsXLlSuzduxf29vYIDQ1Ffn4+ampqYGZmZvAYY34vL8uq0Whgbm5u\n0G5qagqRSGQU7ycvLw/Pnj1DQEAADh48iJkzZ+KLL77Anj17ABhf/gsXLiA2Nhbz5s2Dk5NTh+v/\nF/N3pP5funQpTp8+jUGDBmHevHkoLS3tcP3fElpF+w1JpVJwHAedTgeJ5NdurKurg4WFhYDJmiaV\nSpGcnAwzMzP+D3jr1q24ffs2jh8/DnNzc2i1WoPHGOt7aSmrVCpFXV2dQbtWqwVjDJaWlu2Wszkx\nMTF49uwZ3nvvPQCAq6srqqurER8fjyVLlhhV/jNnzmDdunUYN24cVqxYAaBj9X9T+TtS/7u6ugIA\n4uLiMGLECCQkJHSo/n8VdCX0hhwcHAD8usVDg7KyskaXysbCysrK4P+gxGIxnJ2d8fDhQzg4OKCs\nrMzgfGN9Ly1l7datW5O/F6Dx8KkQJBIJ/wHYwNXVFWq1GtXV1UaTf+/evYiKisL06dOxbds2fnir\no/R/c/mNvf/Ly8tx7tw5g2MWFhbo1asXSktLO0z/vyoqQm+of//+kMlkuHHjBn9MpVKhuLgYQ4YY\n366qGRkZGDRoEDIyMvhjer0ed+7cQb9+/eDt7Y3k5GSDx1y/fh2DBw9u76gtaimrt7c3ioqKDMa/\nr1+/DplMhv79+7dr1qaEhITw4/sN0tPTYW9vj/fee88o8u/fvx+7du1CeHg41q1bx9/YBzpG/78s\nv7H3/4MHD/DJJ58gPT2dP1ZdXY2CggI4Ozt3iP5/LYLOzevgtm/fzvz9/dmVK1f47wm9OHXSWGi1\nWhYUFMQmT57M0tLSWE5ODluxYgUbMmQIKy8vZ3fu3GFubm7s888/Z3l5eWzXrl3Mw8PDYJqrUEJD\nQw2mOLeUleM4FhISwqZNm8YyMjL470l88cUXRpF/3759zN3dnZ8ufOrUKebl5cVOnTplFPmzsrLY\ngAEDWFRUVKPvlKnVaqPv/5byG3v/6/V6NnPmTDZhwgSmVCrZ7du32fz589no0aPZ06dPjb7/XxcV\nobeg1WpZdHQ08/HxYYMGDWJLly5lFRUVQsdqVklJCfvkk0+Yn58f8/LyYvPmzWPZ2dl8+6VLl9i4\nceOYu7s7mzBhArt27ZqAaX/14oc4Yy1nLSsrY4sXL2ZeXl7M39+f7dy5k+n1+vaMzXsxP8dx7NCh\nQ2zMmDHM3d2djRkzhp08edLgMULm37lzJ3NxcWny58svv2SMGXf/t5Tf2PufMcYqKirYqlWrmJ+f\nH1MoFGzJkiWspKSEbzfm/n9dtKkdIYQQwdA9IUIIIYKhIkQIIUQwVIQIIYQIhooQIYQQwVARIoQQ\nIhgqQoQQQgRDRYiQdpadnY3IyEgMGzYM7u7uCAgIQEREBO7cuSN0NAOrV69GYGCg0DHIbxwVIULa\n0Z07dzB9+nRUVVVh3bp1OHToEFauXAmVSoWQkBCkpaUJHZGQdkWraBPSjo4cOQI7Ozvs27cPJiYm\n/PFRo0Zh7Nix+Oqrr7Bv3z4BExLSvqgIEdKOKioqwBgDx3EGRUgmk2HNmjXQaDQAgLCwMDg6OsLe\n3h7Hjx+HXq/Hhx9+iLVr16Jz587845KTk7Fr1y5kZGRAKpUiMDAQK1euNFgluri4GNu3b8e1a9eg\n1Wrh7e2NqKgoODs78+f88ssv2Lp1Ky5cuADGGEJCQvhN3ghpS7RsDyHt6G9/+xs2bdoEd3d3fPTR\nR/Dz84OTk1Oj88LCwpCVlQW5XI7IyEhUV1dj27Zt6NGjB/7xj39ALBYjOTkZ8+bNg7+/P2bOnImK\nigrExcXBwcEBJ06cgEQiQWVlJSZNmgRLS0ssWbIE5ubmOHDgAO7evYuEhAT06NEDHMdh2rRpKC4u\nxrJly9CpUyccOHAA6enpcHBwQGJiogA9Rd4ZQi5cR8i7huM4Fhsbyzw8PPhFNf38/Njy5cuZUqnk\nzwsNDWVubm7swYMH/LGLFy8yFxcXdunSJcYYY9OmTWMTJkwwWJgyMzOTubq6su+++44xxlhsbCzz\n9PRkDx8+5M/RaDQsICCAffrpp4yx+sUwXVxc2A8//MCfo1arma+vLxs9enSb9AMhDWhiAiHtSCQS\nITIyElevXsXOnTsxZcoUyGQynD17FiEhITh27Bh/rre3N795IgCMGDECZmZmSElJgUajgVKpxIgR\nI/gdfnU6Hfr164fu3bvjf//7HwDgxx9/hJubG7p06cKfI5FIMGzYMP6clJQUmJub44MPPuBfy9LS\nEsOHD2+nXiHvMronRIgAbGxsEBQUhKCgIABAZmYmVqxYgZiYGP6Yvb29wWNEIhE6d+6MqqoqVFVV\ngeM4xMfHIz4+vtHzN+yk+eTJE9y7dw9ubm6NzjE1NQVQfz/I1ta2UbtcLn+7N0nIK6AiREg7KSkp\nwZQpU7B06VJMnTrVoG3gwIGIjIzExx9/DJVKBaC+gDyPMYaKigp07twZMpkMIpEI8+fPx9ixYxu9\nlkwmA1C/pbufnx+WL1/ebC5bW1tUVlaCMWawA+mLr09IW6DhOELaiVwuh4mJCY4fP47a2tpG7Xfv\n3oWFhQUcHR0BAKmpqaiqquLbL168CK1WCz8/P1hZWWHgwIEoLCyEh4cH/9OnTx/s2rULSqUSAODj\n44OCggI4OTkZnHfq1CmcO3cOADB06FDU1dXhwoUL/GvV1dXh2rVrbdkdhAAATDZs2LBB6BCEvAvE\nYjEcHR1x9OhRJCYmQiQSQaPRIC8vD8ePH8f+/fsREREBPz8/JCQkoLCwEMnJybCzs0NKSgo2bdoE\nb29vfPzxxwCAbt26Yc+ePVCpVDAzM0Nubi7+8pe/ICMjA4sXL4adnR369euHY8eO4cqVK7CyskJZ\nWRl2796NM2fOYNq0aRgwYAB69eqFtLQ0nDhxAtbW1qioqMCWLVuQn58PmUyG2bNnC9xz5LeM/Vag\nlAAAAOBJREFUpmgT0s4yMjJw8OBBpKamoqKiAubm5hg4cCBmz57NL5MTFhYGkUgEhUKBY8eOQSKR\nYPz48Vi+fDksLCz457p27Rr27NmDzMxMmJubw8PDAxEREfDw8ODPKSwsRGxsLH788UdotVr07dsX\nCxYswPjx4/lzNBoNduzYgXPnzqG2thbjxo2DpaUlLl++TFO0SZuiIkSIEQoLC4OJiQm++eYboaMQ\n0qbonhAhhBDBUBEihBAiGBqOI4QQIhi6EiKEECIYKkKEEEIEQ0WIEEKIYKgIEUIIEQwVIUIIIYL5\nP0DH/ykcJviuAAAAAElFTkSuQmCC\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "ts = linrange(1, 300, 1000)\n", + "\n", + "plot(data, 'go', label='speed/RPM')\n", + "plot(ts, I(ts), color='green', label='interpolated')\n", + "\n", + "decorate(xlabel='Speed',\n", + " ylabel='RPM')\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array(14973.6158648135)" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "I(335)" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\nrkJggg==\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "ts = linrange(1, 300, 1000)\n", + "\n", + "plot(data, 'go', label='Torque')\n", + "plot(ts, I1(I(ts)), color='green', label='interpolated')\n", + "\n", + "decorate(xlabel='Speed',\n", + " ylabel='Torque')\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "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.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/code/chap01_fig01.pdf b/code/chap01_fig01.pdf new file mode 100644 index 00000000..e1ef0ea2 Binary files /dev/null and b/code/chap01_fig01.pdf differ diff --git a/code/chap01mine.ipynb b/code/chap01mine.ipynb new file mode 100644 index 00000000..caf7fe2f --- /dev/null +++ b/code/chap01mine.ipynb @@ -0,0 +1,2199 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Modeling and Simulation in Python\n", + "\n", + "Chapter 1: Modeling\n", + "\n", + "Copyright 2017 Allen Downey\n", + "\n", + "License: [Creative Commons Attribution 4.0 International](https://creativecommons.org/licenses/by/4.0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Jupyter\n", + "\n", + "Welcome to Modeling and Simulation, welcome to Python, and welcome to Jupyter.\n", + "\n", + "This is a Jupyter notebook, which is a development environment where you can write and run Python code. Each notebook is divided into cells. Each cell contains either text (like this cell) or Python code (like the cell below this one).\n", + "\n", + "### Selecting and running cells\n", + "\n", + "To select a cell, click in the left margin next to the cell. You should see a blue frame surrounding the selected cell.\n", + "\n", + "To edit a code cell, click inside the cell. You should see a green frame around the selected cell, and you should see a cursor inside the cell.\n", + "\n", + "To edit a text cell, double-click inside the cell. Again, you should see a green frame around the selected cell, and you should see a cursor inside the cell.\n", + "\n", + "To run a cell, hold down SHIFT and press ENTER. If you run a text cell, it will typeset the text and display the result.\n", + "\n", + "If you run a code cell, it runs the Python code in the cell and displays the result, if any.\n", + "\n", + "To try it out, edit this cell, change some of the text, and then press SHIFT-ENTER to run it." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Adding and removing cells\n", + "\n", + "You can add and remove cells from a notebook using the buttons in the toolbar and the items in the menu, both of which you should see at the top of this notebook.\n", + "\n", + "You might want to try the following exercises:\n", + "\n", + "1. From the Insert menu select \"Insert cell below\" to add a cell below this one. By default, you get a code cell, and you can see in the pulldown menu that says \"Code\".\n", + "\n", + "2. In the new cell, add a print statement like `print('Hello')`, and run it.\n", + "\n", + "3. Add another cell, select the new cell, and then click on the pulldown menu that says \"Code\" and select \"Markdown\". This makes the new cell a text cell.\n", + "\n", + "4. In the new cell, type some text, and then run it.\n", + "\n", + "5. Use the arrow buttons in the toolbar to move cells up and down.\n", + "\n", + "6. Use the cut, copy, and paste buttons to delete, add, and move cells.\n", + "\n", + "7. As you make changes, Jupyter saves your notebook automatically, but if you want to make sure, you can press the save button, which looks like a floppy disk from the 1990s.\n", + "\n", + "8. Finally, when you are done with a notebook, selection \"Close and Halt\" from the File menu." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Using the notebooks\n", + "\n", + "The notebooks for each chapter contain the code from the chapter along with addition examples, explanatory text, and exercises. I recommend you read the chapter first to understand the concepts and vocabulary, then run the notebook to review what you learned and see it in action, and then attempt the exercises.\n", + "\n", + "The notebooks contain some explanatory text, but it is probably not enough to make sense if you have not read the book. If you are working through a notebook and you get stuck, you might want to re-read (or read!) the corresponding section of the book.\n", + "\n", + "If you try to work through the notebooks without reading the book, you're gonna have a bad time. If you have previous programming experience, you might get through the first few notebooks, but sooner or later, you will get to the end of your leash, and you won't like it." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Importing modsim\n", + "\n", + "The following cell imports `modsim`, which is a collection of functions we will use throughout the book. Whenever you start the notebook, you will have to run the following cell. It does two things:\n", + "\n", + "1. It uses a Jupyter \"magic command\" to specify whether figures should appear in the notebook, or pop up in a new window.\n", + "\n", + "2. It imports everything defined in `modsim`.\n", + "\n", + "Select the following cell and press SHIFT-ENTER to run it." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "If this cell runs successfully, it produces no output other than this message.\n" + ] + } + ], + "source": [ + "# If you want the figures to appear in the notebook, \n", + "# and you want to interact with them, use\n", + "# %matplotlib notebook\n", + "\n", + "# If you want the figures to appear in the notebook, \n", + "# and you don't want to interact with them, use\n", + "# %matplotlib inline\n", + "\n", + "# If you want the figures to appear in separate windows, use\n", + "# %matplotlib qt5\n", + "\n", + "# To switch from one to another, you have to select Kernel->Restart\n", + "\n", + "%matplotlib qt5\n", + "\n", + "from modsim import *\n", + "\n", + "print('If this cell runs successfully, it produces no output other than this message.')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## The penny myth\n", + "\n", + "The following cells contain code from the beginning of Chapter 1.\n", + "\n", + "`modsim` defines `UNITS`, which contains variables representing pretty much every unit you've ever heard of. The following to lines create new variables named `meter` and `second`." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "meter = UNITS.meter\n", + "second = UNITS.second" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To find out what units are defined, type `UNITS.` in the next cell and then press TAB. You should see a pop-up menu with a list of units." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "invalid syntax (, line 1)", + "output_type": "error", + "traceback": [ + "\u001b[1;36m File \u001b[1;32m\"\"\u001b[1;36m, line \u001b[1;32m1\u001b[0m\n\u001b[1;33m UNITS.\u001b[0m\n\u001b[1;37m ^\u001b[0m\n\u001b[1;31mSyntaxError\u001b[0m\u001b[1;31m:\u001b[0m invalid syntax\n" + ] + } + ], + "source": [ + "UNITS." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create a variable named `a` and display its value:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "9.8 meter/second2" + ], + "text/latex": [ + "$9.8 \\frac{meter}{second^{2}}$" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "a = 9.8 * meter / second**2\n", + "a" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "Create `t` and display its value:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "4 second" + ], + "text/latex": [ + "$4 second$" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "t = 4 * second\n", + "t" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "If you create a variable and don't display the value, you don't get any output:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "156.8 meter" + ], + "text/latex": [ + "$156.8 meter$" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "h = a * t**2\n", + "h" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "Add a second line to the previous cell to display the value of `h`.\n", + "\n", + "Now let's solve the falling penny problem. The following lines set `h` to the height of the Empire State Building and compute the time it would take a penny to fall, assuming constant acceleration." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "8.817885349720552 second" + ], + "text/latex": [ + "$8.817885349720552 second$" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "h = 381 * meter\n", + "t = sqrt(2 * h / a)\n", + "t" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "Given `t`, we can compute the velocity of the penny when it lands." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "86.41527642726142 meter/second" + ], + "text/latex": [ + "$86.41527642726142 \\frac{meter}{second}$" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "v = a * t\n", + "v" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "We can convert from one set of units to another like this:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "mile = UNITS.mile\n", + "hour= UNITS.hour" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "193.30546802805438 mile/hour" + ], + "text/latex": [ + "$193.30546802805438 \\frac{mile}{hour}$" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "v.to(mile/hour)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise:** In reality, air resistance prevents the penny from reaching this velocity. At about 20 meters per second, the force of air resistance equals the force of gravity and the penny stops accelerating.\n", + "\n", + "As a simplification, let's assume that the acceleration of the penny is `a` until the penny reaches 20 meters per second, and then 0 afterwards. What is the total time for the penny to fall 381 meters?" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "20.070408163265306 second" + ], + "text/latex": [ + "$20.070408163265306 second$" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tv= 20 * meter/second\n", + "t1 = tv/a \n", + "h1 = a / 2 * t1**2\n", + "td= 381 * meter\n", + "t2 = (td - h1) / tv\n", + "\n", + "tf = t1 + t2\n", + "tf\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Modeling a bikeshare system" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We'll start with a `System` object that represents the number of bikes at each station." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "bikeshare = System(olin=10, wellesley=2, babson=0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you display the value of a `System` object, it lists the system variables and their values (not necessarily in the order you defined them):" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
value
olin10
wellesley2
babson0
\n", + "
" + ], + "text/plain": [ + "olin 10\n", + "wellesley 2\n", + "babson 0\n", + "dtype: int64" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bikeshare" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can access the system variables using dot notation." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "10" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bikeshare.olin" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "2" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bikeshare.wellesley" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise:** What happens if you spell the name of a system variable wrong? Edit the previous cell, change the spelling of `wellesley`, and run the cell again.\n", + "\n", + "The error message uses the word \"attribute\", which is another name for what we are calling a system variable. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise:** Add a third attribute called `babson` with initial value 0, and print the state of `bikeshare` again." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Plotting\n", + "\n", + "`newfig` creates a new figure, which should appear either in the notebook or in a new window, depending on which magic command you ran in the first code cell.\n", + "\n", + "`plot` adds a data point to the figure; in this example, you should see a red square and a blue circle representing the number of bikes at each station." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "newfig()\n", + "plot(bikeshare.olin, 'rs-')\n", + "plot(bikeshare.wellesley, 'bo-')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can use the operators `+=` and `-=` to increase and decrease the system variables. The following lines move a bike from Olin to Wellesley." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
value
olin9
wellesley3
babson0
\n", + "
" + ], + "text/plain": [ + "olin 9\n", + "wellesley 3\n", + "babson 0\n", + "dtype: int64" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bikeshare.olin -= 1\n", + "bikeshare.wellesley += 1\n", + "bikeshare" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And the following lines plot the updated state of the system. You should see two new data points with lines connecting them to the old data points." + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "plot(bikeshare.olin, 'rs-')\n", + "plot(bikeshare.wellesley, 'bo-')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise:** In the cell below, write a few lines of code to move a bike from Wellesley to Olin and plot the updated state." + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [], + "source": [ + "bikeshare.olin += 1\n", + "bikeshare.wellesley -= 1\n", + "bikeshare\n", + "\n", + "plot(bikeshare.olin, 'rs-')\n", + "plot(bikeshare.wellesley, 'bo-')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Functions\n", + "\n", + "Now we can take the code we've written so far and encapsulate it in functions." + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def bike_to_wellesley():\n", + " bikeshare.olin -= 1\n", + " bikeshare.wellesley += 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "When you define a function, it doesn't run the statements inside the function, yet." + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def plot_state():\n", + " plot(bikeshare.olin, 'rs-', label='Olin')\n", + " plot(bikeshare.wellesley, 'bo-', label='Wellesley')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now when we run the functions, it runs the statements inside." + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
value
olin9
wellesley3
babson0
\n", + "
" + ], + "text/plain": [ + "olin 9\n", + "wellesley 3\n", + "babson 0\n", + "dtype: int64" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bike_to_wellesley()\n", + "plot_state()\n", + "bikeshare" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You should see two more data points that represent the current state of the system. If the figure is embedded in the notebook, you might have to scroll up to see the change.\n", + "\n", + "One common error is to omit the parentheses, which has the effect of looking up the function, but not running it." + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bike_to_wellesley" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The output indicates that `bike_to_wellesley` is a function defined in a \"namespace\" called `__main__`, but you don't have to understand what that means." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise:** Define a function called `bike_to_olin` that moves a bike from Wellesley to Olin. Run the new function and print or plot the results to confirm that it works." + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
value
olin11
wellesley1
babson0
\n", + "
" + ], + "text/plain": [ + "olin 11\n", + "wellesley 1\n", + "babson 0\n", + "dtype: int64" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def bike_to_olin():\n", + " bikeshare.olin += 1\n", + " bikeshare.wellesley -= 1\n", + "bike_to_olin()\n", + "bikeshare" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Parameters" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Before we go on, let's start with a new state object and a new plot." + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "bikeshare = System(olin=10, wellesley=2)\n", + "newfig()\n", + "plot_state()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Since we have two similar functions, we can create a new function, `move_bike` that takes a parameter `n`, which indicates how many bikes are moving, and in which direction." + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def move_bike(n):\n", + " bikeshare.olin -= n\n", + " bikeshare.wellesley += n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can use `move_bike` to write simpler versions of the other functions." + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def bike_to_wellesley():\n", + " move_bike(1)\n", + " \n", + "def bike_to_olin():\n", + " move_bike(-1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "When we define these functions, we replace the old definitions with the new ones.\n", + "\n", + "Now we can test them and update the figure." + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
value
olin9
wellesley3
\n", + "
" + ], + "text/plain": [ + "olin 9\n", + "wellesley 3\n", + "dtype: int64" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bike_to_wellesley()\n", + "plot_state()\n", + "bikeshare" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Again, each time you run `plot_state` you should see changes in the figure." + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
value
olin10
wellesley2
\n", + "
" + ], + "text/plain": [ + "olin 10\n", + "wellesley 2\n", + "dtype: int64" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bike_to_olin()\n", + "plot_state()\n", + "bikeshare" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "At this point, `move_bike` is complicated enough that we should add some documentation. The text in triple-quotation marks is in English, not Python. It doesn't do anything when the program runs, but it helps people understand what this function does and how to use it." + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def move_bike(n):\n", + " \"\"\"Move bikes.\n", + " \n", + " n: number of bikes: positive moves from Olin to Wellesley;\n", + " negative moves from Wellesley to Olin\n", + " \"\"\"\n", + " bikeshare.olin -= n\n", + " bikeshare.wellesley += n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Whenever you make a figure, you should put labels on the axes to explain what they mean and what units they are measured in. Here's how:" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "label_axes(title='Olin-Wellesley Bikeshare',\n", + " xlabel='Time step (min)', \n", + " ylabel='Number of bikes')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Again, you might have to scroll up to see the effect.\n", + "\n", + "And you can save figures as files; the suffix of the filename indicates the format you want. This example saves the current figure in a PDF file." + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Saving figure to file chap01_fig01.pdf\n" + ] + } + ], + "source": [ + "savefig('chap01_fig01.pdf')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise:** The following function definitions start with print statements so they display messages when they run. Run each of these functions (with appropriate arguments) and confirm that they do what you expect.\n", + "\n", + "Adding print statements like this to functions is a useful debugging technique. Keep it in mind!" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def move_bike_debug(n):\n", + " print('Running move_bike_debug with argument', n)\n", + " bikeshare.olin -= n\n", + " bikeshare.wellesley += n\n", + " \n", + "def bike_to_wellesley_debug():\n", + " print('Running bike_to_wellesley_debug')\n", + " move_bike_debug(1)\n", + " \n", + "def bike_to_olin_debug():\n", + " print('Running bike_to_olin_debug')\n", + " move_bike_debug(-1)" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Running move_bike_debug with argument 1\n" + ] + } + ], + "source": [ + "move_bike_debug(1)" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Running bike_to_wellesley_debug\n", + "Running move_bike_debug with argument 1\n" + ] + } + ], + "source": [ + "bike_to_wellesley_debug()" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Running bike_to_olin_debug\n", + "Running move_bike_debug with argument -1\n" + ] + } + ], + "source": [ + "bike_to_olin_debug()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Conditionals" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The function `flip` takes a probability and returns either `True` or `False`, which are special values defined by Python.\n", + "\n", + "In the following example, the probability is 0.7 or 70%. If you run this cell several times, you should get `True` about 70% of the time and `False` about 30%." + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "flip(0.7)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Modify the argument in the previous cell and see what effect it has.\n", + "\n", + "In the following example, we use `flip` as part of an if statement. If the result from `flip` is `True`, we print `heads`; otherwise we do nothing." + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [], + "source": [ + "if flip(0.7):\n", + " print('heads')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With an else clause, we can print heads or tails depending on whether `flip` returns `True` or `False`." + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "heads\n" + ] + } + ], + "source": [ + "if flip(0.7):\n", + " print('heads')\n", + "else:\n", + " print('tails')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now let's get back to the bikeshare system. Again let's start with a new `System` object and a new plot." + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "bikeshare = System(olin=10, wellesley=2)\n", + "newfig()\n", + "plot_state()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Suppose that in any given minute, there is a 70% chance that a student picks up a bike at Olin and rides to Wellesley. We can simulate that like this." + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Moving a bike to Wellesley\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
value
olin9
wellesley3
\n", + "
" + ], + "text/plain": [ + "olin 9\n", + "wellesley 3\n", + "dtype: int64" + ] + }, + "execution_count": 42, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "if flip(0.7):\n", + " bike_to_wellesley()\n", + " print('Moving a bike to Wellesley')\n", + "\n", + "plot_state()\n", + "bikeshare" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And maybe at the same time, there is also a 60% chance that a student at Wellesley rides to Olin." + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Moving a bike to Olin\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
value
olin10
wellesley2
\n", + "
" + ], + "text/plain": [ + "olin 10\n", + "wellesley 2\n", + "dtype: int64" + ] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "if flip(0.6):\n", + " bike_to_olin()\n", + " print('Moving a bike to Olin')\n", + "\n", + "plot_state()\n", + "bikeshare" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can wrap that code in a function called `step` that simulates one time step. In any given minute, a student might ride from Olin to Wellesley, from Wellesley to Olin, or both, or neither, depending on the results of `flip`." + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def step():\n", + " if flip(0.7):\n", + " bike_to_wellesley()\n", + " print('Moving a bike to Wellesley')\n", + " \n", + " if flip(0.6):\n", + " bike_to_olin()\n", + " print('Moving a bike to Olin')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you run `step` a few times, it should update the current figure. In each time step, the number of bikes at each location might go up, down, or stay the same." + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Moving a bike to Wellesley\n", + "Moving a bike to Olin\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
value
olin10
wellesley2
\n", + "
" + ], + "text/plain": [ + "olin 10\n", + "wellesley 2\n", + "dtype: int64" + ] + }, + "execution_count": 45, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "step()\n", + "plot_state()\n", + "bikeshare" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The following function labels the axes and adds a legend to the figure." + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def decorate(): \n", + " legend(loc='random string')\n", + " label_axes(title='Olin-Wellesley Bikeshare',\n", + " xlabel='Time step (min)', \n", + " ylabel='Number of bikes')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As always, when you define a function, it has no effect until you run it." + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\ProgramData\\Miniconda3\\lib\\site-packages\\matplotlib\\legend.py:326: UserWarning: Unrecognized location \"random string\". Falling back on \"best\"; valid locations are\n", + "\tbest\n", + "\tupper right\n", + "\tupper left\n", + "\tlower left\n", + "\tlower right\n", + "\tright\n", + "\tcenter left\n", + "\tcenter right\n", + "\tlower center\n", + "\tupper center\n", + "\tcenter\n", + "\n", + " six.iterkeys(self.codes))))\n" + ] + } + ], + "source": [ + "plot_state()\n", + "decorate()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise:** Change the argument of `legend` to `'random string'` and run `decorate` again. You should get an error message that lists the valid location where you can put the legend." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Optional parameters" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Again let's start with a new `System` object and a new plot." + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "bikeshare = System(olin=10, wellesley=2)\n", + "newfig()\n", + "plot_state()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can make `step` more general by adding parameters. Because these parameters have default values, they are optional." + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def step(p1=0.5, p2=0.5):\n", + " print('p1 ->', p1)\n", + " print('p2 ->', p2)\n", + " if flip(p1):\n", + " bike_to_wellesley()\n", + " \n", + " if flip(p2):\n", + " bike_to_olin()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "I added print statements, so each time we run `step` we can see the arguments.\n", + "\n", + "If you provide no arguments, you get the default values:" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "p1 -> 0.5\n", + "p2 -> 0.5\n" + ] + } + ], + "source": [ + "step()\n", + "plot_state()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you provide one argument, it overrides the first parameter." + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "p1 -> 0.4\n", + "p2 -> 0.5\n" + ] + } + ], + "source": [ + "step(0.4)\n", + "plot_state()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you provide two arguments, they override both." + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "p1 -> 0.4\n", + "p2 -> 0.2\n" + ] + } + ], + "source": [ + "step(0.4, 0.2)\n", + "plot_state()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can specify the names of the parameters you want to override." + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "p1 -> 0.4\n", + "p2 -> 0.2\n" + ] + } + ], + "source": [ + "step(p1=0.4, p2=0.2)\n", + "plot_state()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Which means you can override the second parameter and use the default for the first." + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "p1 -> 0.5\n", + "p2 -> 0.2\n" + ] + } + ], + "source": [ + "step(p2=0.2)\n", + "plot_state()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can combine both forms, but it is not very common:" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "p1 -> 0.4\n", + "p2 -> 0.2\n" + ] + } + ], + "source": [ + "step(0.4, p2=0.2)\n", + "plot_state()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "One reason it's not common is that it's error prone. The following example causes an error." + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "positional argument follows keyword argument (, line 4)", + "output_type": "error", + "traceback": [ + "\u001b[1;36m File \u001b[1;32m\"\"\u001b[1;36m, line \u001b[1;32m4\u001b[0m\n\u001b[1;33m step(p1=0.4, 0.2)\u001b[0m\n\u001b[1;37m ^\u001b[0m\n\u001b[1;31mSyntaxError\u001b[0m\u001b[1;31m:\u001b[0m positional argument follows keyword argument\n" + ] + } + ], + "source": [ + "# If you remove the # at the beginning of the next line and run it, you get\n", + "# SyntaxError: positional argument follows keyword argument\n", + "\n", + "step(p1=0.4, 0.2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "From the error message, you might infer that arguments like `step(0.4, 0.2)` are called \"positional\" and arguments like `step(p1=0.4, p2=0.2)` are called \"keyword arguments\"." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise:** Write a version of `decorate` that takes an optional parameter named `loc` with default value `'best'`. It should pass the value of `loc` along as an argument to `legend.` Test your function with different values of `loc`. [You can see the list of legal values here](https://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.legend)." + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def decorate(loc='best'): \n", + " legend(loc=loc)\n", + " label_axes(title='Olin-Wellesley Bikeshare',\n", + " xlabel='Time step (min)', \n", + " ylabel='Number of bikes')" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "plot_state()\n", + "decorate(0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## For loop" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Before we go on, I'll redefine `step` without the print statements." + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def step(p1=0.5, p2=0.5):\n", + " if flip(p1):\n", + " bike_to_wellesley()\n", + " \n", + " if flip(p2):\n", + " bike_to_olin()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And let's start again with a new `System` object and a new figure." + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "bikeshare = System(olin=10, wellesley=2)\n", + "newfig()\n", + "plot_state()\n", + "decorate()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can use a for loop to move 4 bikes from Olin to Wellesley." + ] + }, + { + "cell_type": "code", + "execution_count": 61, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "for i in range(4):\n", + " bike_to_wellesley()\n", + " plot_state()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Or we can simulate 4 random time steps." + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "for i in range(4):\n", + " step()\n", + " plot_state()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If each step corresponds to a minute, we can simulate the rest of the hour like this." + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "for i in range(52):\n", + " step(p1=0.4, p2=0.2)\n", + " plot_state()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise:** Combine the examples from the previous two sections to write a function named `run_steps` that takes three parameters, named `num_steps`, `p1`, and `p2`. It should use a for loop to run `step` the number of times specified by `num_steps`, passing along the specified values of `p1` and `p2`. After each step, it should plot the updated state.\n", + "\n", + "Test your function by creating a new `System` object, creating a new figure, and running `run_steps`." + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Solution goes here\n", + "def run_steps(num_steps,p1,p2):\n", + " for i in range(num_steps):\n", + " step(p1,p2)\n", + " plot_state()\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "metadata": {}, + "outputs": [], + "source": [ + "bikeshare = System(olin = 10, wellesley = 2)\n", + "newfig()\n", + "run_steps(2,.7,.3)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "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.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/code/chap02mine.ipynb b/code/chap02mine.ipynb new file mode 100644 index 00000000..85219a35 --- /dev/null +++ b/code/chap02mine.ipynb @@ -0,0 +1,9297 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Modeling and Simulation in Python\n", + "\n", + "Chapter 2: Simulation\n", + "\n", + "Copyright 2017 Allen Downey\n", + "\n", + "License: [Creative Commons Attribution 4.0 International](https://creativecommons.org/licenses/by/4.0)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We'll start with the same code we saw last time: the magic command that tells Jupyter where to put the figures, and the import statement that gets the functions defined in the `modsim` module." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# If you want the figures to appear in the notebook, \n", + "# and you want to interact with them, use\n", + "# %matplotlib notebook\n", + "\n", + "# If you want the figures to appear in the notebook, \n", + "# and you don't want to interact with them, use\n", + "# %matplotlib inline\n", + "\n", + "# If you want the figures to appear in separate windows, use\n", + "# %matplotlib qt5\n", + "\n", + "%matplotlib notebook\n", + "\n", + "from modsim import *" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## More than one System object\n", + "\n", + "Here's the code from the previous chapter, with two changes:\n", + "\n", + "1. I've added DocStrings that explain what each function does, and what parameters it takes.\n", + "\n", + "2. I've added a parameter named `system` to the functions so they work with whatever `System` object we give them, instead of always using `bikeshare`. That will be useful soon when we have more than one `System` object." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def run_steps(system, num_steps=1, p1=0.5, p2=0.5):\n", + " \"\"\"Simulate the given number of time steps.\n", + " \n", + " system: bikeshare System object\n", + " num_steps: number of time steps\n", + " p1: probability of an Olin->Wellesley customer arrival\n", + " p2: probability of a Wellesley->Olin customer arrival\n", + " \"\"\"\n", + " for i in range(num_steps):\n", + " step(system, p1, p2)\n", + " plot_system(system)\n", + " \n", + "def step(system, p1=0.5, p2=0.5):\n", + " \"\"\"Simulate one minute of time.\n", + " \n", + " system: bikeshare System object\n", + " p1: probability of an Olin->Wellesley customer arrival\n", + " p2: probability of a Wellesley->Olin customer arrival\n", + " \"\"\"\n", + " if flip(p1):\n", + " bike_to_wellesley(system)\n", + " \n", + " if flip(p2):\n", + " bike_to_olin(system)\n", + " \n", + "def bike_to_wellesley(system):\n", + " \"\"\"Move one bike from Olin to Wellesley.\n", + " \n", + " system: bikeshare System object\n", + " \"\"\"\n", + " move_bike(system, 1)\n", + " \n", + "def bike_to_olin(system):\n", + " \"\"\"Move one bike from Wellesley to Olin.\n", + " \n", + " system: bikeshare System object\n", + " \"\"\"\n", + " move_bike(system, -1)\n", + " \n", + "def move_bike(system, n):\n", + " \"\"\"Move a bike.\n", + " \n", + " system: bikeshare System object\n", + " n: +1 to move from Olin to Wellesley or\n", + " -1 to move from Wellesley to Olin\n", + " \"\"\"\n", + " system.olin -= n\n", + " system.wellesley += n\n", + " \n", + "def plot_system(system):\n", + " \"\"\"Plot the current system of the bikeshare system.\n", + " \n", + " system: bikeshare System object\n", + " \"\"\"\n", + " plot(system.olin, 'rs-', label='Olin')\n", + " plot(system.wellesley, 'bo-', label='Wellesley')\n", + " \n", + "def decorate_bikeshare():\n", + " \"\"\"Add a title and label the axes.\"\"\"\n", + " decorate(title='Olin-Wellesley Bikeshare',\n", + " xlabel='Time step (min)', \n", + " ylabel='Number of bikes')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can create more than one `System` object:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
value
olin10
wellesley2
\n", + "
" + ], + "text/plain": [ + "olin 10\n", + "wellesley 2\n", + "dtype: int64" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bikeshare1 = System(olin=10, wellesley=2)\n", + "bikeshare1" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
value
olin10
wellesley2
\n", + "
" + ], + "text/plain": [ + "olin 10\n", + "wellesley 2\n", + "dtype: int64" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bikeshare2 = System(olin=10, wellesley=2)\n", + "bikeshare2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And whenever we call a function, we indicate which `System` object to work with:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "bike_to_olin(bikeshare1)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'bikeshare2' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mbike_to_wellesley\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mbikeshare2\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[1;31mNameError\u001b[0m: name 'bikeshare2' is not defined" + ] + } + ], + "source": [ + "bike_to_wellesley(bikeshare2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And you can confirm that the different systems are getting updated independently:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
value
olin11
wellesley1
\n", + "
" + ], + "text/plain": [ + "olin 11\n", + "wellesley 1\n", + "dtype: int64" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bikeshare1" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'bikeshare2' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mbikeshare2\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[1;31mNameError\u001b[0m: name 'bikeshare2' is not defined" + ] + } + ], + "source": [ + "bikeshare2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Negative bikes" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the code we have so far, the number of bikes at one of the locations can go negative, and the number of bikes at the other location can exceed the actual number of bikes in the system.\n", + "\n", + "If you run this simulation a few times, it happens quite often." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "application/javascript": [ + "/* Put everything inside the global mpl namespace */\n", + "window.mpl = {};\n", + "\n", + "\n", + "mpl.get_websocket_type = function() {\n", + " if (typeof(WebSocket) !== 'undefined') {\n", + " return WebSocket;\n", + " } else if (typeof(MozWebSocket) !== 'undefined') {\n", + " return MozWebSocket;\n", + " } else {\n", + " alert('Your browser does not have WebSocket support.' +\n", + " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", + " 'Firefox 4 and 5 are also supported but you ' +\n", + " 'have to enable WebSockets in about:config.');\n", + " };\n", + "}\n", + "\n", + "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", + " this.id = figure_id;\n", + "\n", + " this.ws = websocket;\n", + "\n", + " this.supports_binary = (this.ws.binaryType != undefined);\n", + "\n", + " if (!this.supports_binary) {\n", + " var warnings = document.getElementById(\"mpl-warnings\");\n", + " if (warnings) {\n", + " warnings.style.display = 'block';\n", + " warnings.textContent = (\n", + " \"This browser does not support binary websocket messages. \" +\n", + " \"Performance may be slow.\");\n", + " }\n", + " }\n", + "\n", + " this.imageObj = new Image();\n", + "\n", + " this.context = undefined;\n", + " this.message = undefined;\n", + " this.canvas = undefined;\n", + " this.rubberband_canvas = undefined;\n", + " this.rubberband_context = undefined;\n", + " this.format_dropdown = undefined;\n", + "\n", + " this.image_mode = 'full';\n", + "\n", + " this.root = $('
');\n", + " this._root_extra_style(this.root)\n", + " this.root.attr('style', 'display: inline-block');\n", + "\n", + " $(parent_element).append(this.root);\n", + "\n", + " this._init_header(this);\n", + " this._init_canvas(this);\n", + " this._init_toolbar(this);\n", + "\n", + " var fig = this;\n", + "\n", + " this.waiting = false;\n", + "\n", + " this.ws.onopen = function () {\n", + " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", + " fig.send_message(\"send_image_mode\", {});\n", + " if (mpl.ratio != 1) {\n", + " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n", + " }\n", + " fig.send_message(\"refresh\", {});\n", + " }\n", + "\n", + " this.imageObj.onload = function() {\n", + " if (fig.image_mode == 'full') {\n", + " // Full images could contain transparency (where diff images\n", + " // almost always do), so we need to clear the canvas so that\n", + " // there is no ghosting.\n", + " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", + " }\n", + " fig.context.drawImage(fig.imageObj, 0, 0);\n", + " };\n", + "\n", + " this.imageObj.onunload = function() {\n", + " this.ws.close();\n", + " }\n", + "\n", + " this.ws.onmessage = this._make_on_message_function(this);\n", + "\n", + " this.ondownload = ondownload;\n", + "}\n", + "\n", + "mpl.figure.prototype._init_header = function() {\n", + " var titlebar = $(\n", + " '
');\n", + " var titletext = $(\n", + " '
');\n", + " titlebar.append(titletext)\n", + " this.root.append(titlebar);\n", + " this.header = titletext[0];\n", + "}\n", + "\n", + "\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._init_canvas = function() {\n", + " var fig = this;\n", + "\n", + " var canvas_div = $('
');\n", + "\n", + " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", + "\n", + " function canvas_keyboard_event(event) {\n", + " return fig.key_event(event, event['data']);\n", + " }\n", + "\n", + " canvas_div.keydown('key_press', canvas_keyboard_event);\n", + " canvas_div.keyup('key_release', canvas_keyboard_event);\n", + " this.canvas_div = canvas_div\n", + " this._canvas_extra_style(canvas_div)\n", + " this.root.append(canvas_div);\n", + "\n", + " var canvas = $('');\n", + " canvas.addClass('mpl-canvas');\n", + " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", + "\n", + " this.canvas = canvas[0];\n", + " this.context = canvas[0].getContext(\"2d\");\n", + "\n", + " var backingStore = this.context.backingStorePixelRatio ||\n", + "\tthis.context.webkitBackingStorePixelRatio ||\n", + "\tthis.context.mozBackingStorePixelRatio ||\n", + "\tthis.context.msBackingStorePixelRatio ||\n", + "\tthis.context.oBackingStorePixelRatio ||\n", + "\tthis.context.backingStorePixelRatio || 1;\n", + "\n", + " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n", + "\n", + " var rubberband = $('');\n", + " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", + "\n", + " var pass_mouse_events = true;\n", + "\n", + " canvas_div.resizable({\n", + " start: function(event, ui) {\n", + " pass_mouse_events = false;\n", + " },\n", + " resize: function(event, ui) {\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " stop: function(event, ui) {\n", + " pass_mouse_events = true;\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " });\n", + "\n", + " function mouse_event_fn(event) {\n", + " if (pass_mouse_events)\n", + " return fig.mouse_event(event, event['data']);\n", + " }\n", + "\n", + " rubberband.mousedown('button_press', mouse_event_fn);\n", + " rubberband.mouseup('button_release', mouse_event_fn);\n", + " // Throttle sequential mouse events to 1 every 20ms.\n", + " rubberband.mousemove('motion_notify', mouse_event_fn);\n", + "\n", + " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", + " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", + "\n", + " canvas_div.on(\"wheel\", function (event) {\n", + " event = event.originalEvent;\n", + " event['data'] = 'scroll'\n", + " if (event.deltaY < 0) {\n", + " event.step = 1;\n", + " } else {\n", + " event.step = -1;\n", + " }\n", + " mouse_event_fn(event);\n", + " });\n", + "\n", + " canvas_div.append(canvas);\n", + " canvas_div.append(rubberband);\n", + "\n", + " this.rubberband = rubberband;\n", + " this.rubberband_canvas = rubberband[0];\n", + " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", + " this.rubberband_context.strokeStyle = \"#000000\";\n", + "\n", + " this._resize_canvas = function(width, height) {\n", + " // Keep the size of the canvas, canvas container, and rubber band\n", + " // canvas in synch.\n", + " canvas_div.css('width', width)\n", + " canvas_div.css('height', height)\n", + "\n", + " canvas.attr('width', width * mpl.ratio);\n", + " canvas.attr('height', height * mpl.ratio);\n", + " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n", + "\n", + " rubberband.attr('width', width);\n", + " rubberband.attr('height', height);\n", + " }\n", + "\n", + " // Set the figure to an initial 600x600px, this will subsequently be updated\n", + " // upon first draw.\n", + " this._resize_canvas(600, 600);\n", + "\n", + " // Disable right mouse context menu.\n", + " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", + " return false;\n", + " });\n", + "\n", + " function set_focus () {\n", + " canvas.focus();\n", + " canvas_div.focus();\n", + " }\n", + "\n", + " window.setTimeout(set_focus, 100);\n", + "}\n", + "\n", + "mpl.figure.prototype._init_toolbar = function() {\n", + " var fig = this;\n", + "\n", + " var nav_element = $('
')\n", + " nav_element.attr('style', 'width: 100%');\n", + " this.root.append(nav_element);\n", + "\n", + " // Define a callback function for later on.\n", + " function toolbar_event(event) {\n", + " return fig.toolbar_button_onclick(event['data']);\n", + " }\n", + " function toolbar_mouse_event(event) {\n", + " return fig.toolbar_button_onmouseover(event['data']);\n", + " }\n", + "\n", + " for(var toolbar_ind in mpl.toolbar_items) {\n", + " var name = mpl.toolbar_items[toolbar_ind][0];\n", + " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", + " var image = mpl.toolbar_items[toolbar_ind][2];\n", + " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", + "\n", + " if (!name) {\n", + " // put a spacer in here.\n", + " continue;\n", + " }\n", + " var button = $('');\n", + " button.click(method_name, toolbar_event);\n", + " button.mouseover(tooltip, toolbar_mouse_event);\n", + " nav_element.append(button);\n", + " }\n", + "\n", + " // Add the status bar.\n", + " var status_bar = $('');\n", + " nav_element.append(status_bar);\n", + " this.message = status_bar[0];\n", + "\n", + " // Add the close button to the window.\n", + " var buttongrp = $('
');\n", + " var button = $('');\n", + " button.click(function (evt) { fig.handle_close(fig, {}); } );\n", + " button.mouseover('Stop Interaction', toolbar_mouse_event);\n", + " buttongrp.append(button);\n", + " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n", + " titlebar.prepend(buttongrp);\n", + "}\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(el){\n", + " var fig = this\n", + " el.on(\"remove\", function(){\n", + "\tfig.close_ws(fig, {});\n", + " });\n", + "}\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(el){\n", + " // this is important to make the div 'focusable\n", + " el.attr('tabindex', 0)\n", + " // reach out to IPython and tell the keyboard manager to turn it's self\n", + " // off when our div gets focus\n", + "\n", + " // location in version 3\n", + " if (IPython.notebook.keyboard_manager) {\n", + " IPython.notebook.keyboard_manager.register_events(el);\n", + " }\n", + " else {\n", + " // location in version 2\n", + " IPython.keyboard_manager.register_events(el);\n", + " }\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._key_event_extra = function(event, name) {\n", + " var manager = IPython.notebook.keyboard_manager;\n", + " if (!manager)\n", + " manager = IPython.keyboard_manager;\n", + "\n", + " // Check for shift+enter\n", + " if (event.shiftKey && event.which == 13) {\n", + " this.canvas_div.blur();\n", + " // select the cell after this one\n", + " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", + " IPython.notebook.select(index + 1);\n", + " }\n", + "}\n", + "\n", + "mpl.figure.prototype.handle_save = function(fig, msg) {\n", + " fig.ondownload(fig, null);\n", + "}\n", + "\n", + "\n", + "mpl.find_output_cell = function(html_output) {\n", + " // Return the cell and output element which can be found *uniquely* in the notebook.\n", + " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", + " // IPython event is triggered only after the cells have been serialised, which for\n", + " // our purposes (turning an active figure into a static one), is too late.\n", + " var cells = IPython.notebook.get_cells();\n", + " var ncells = cells.length;\n", + " for (var i=0; i= 3 moved mimebundle to data attribute of output\n", + " data = data.data;\n", + " }\n", + " if (data['text/html'] == html_output) {\n", + " return [cell, data, j];\n", + " }\n", + " }\n", + " }\n", + " }\n", + "}\n", + "\n", + "// Register the function which deals with the matplotlib target/channel.\n", + "// The kernel may be null if the page has been refreshed.\n", + "if (IPython.notebook.kernel != null) {\n", + " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", + "}\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "IOPub data rate exceeded.\n", + "The notebook server will temporarily stop sending output\n", + "to the client in order to avoid crashing it.\n", + "To change this limit, set the config variable\n", + "`--NotebookApp.iopub_data_rate_limit`.\n" + ] + } + ], + "source": [ + "bikeshare = System(olin=10, wellesley=2)\n", + "newfig()\n", + "plot_system(bikeshare)\n", + "decorate_bikeshare()\n", + "run_steps(bikeshare, 60, 0.4, 0.2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The variables `olin` and `wellesley` are created inside `move_bike`, so they are local. When the function ends, they go away.\n", + "\n", + "If you try to access a local variable from outside its function, you get an error:" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# If you remove the # from the last line in this cell and run it, you'll get\n", + "# NameError: name 'olin' is not defined\n", + "\n", + "#olin" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise:** Add print statements in `move_bike` so it prints a message each time a customer arrives and doesn't find a bike. Run the simulation again to confirm that it works as you expect. Then you might want to remove the print statements before you go on." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Comparison operators" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `if` statements in the previous section used the comparison operator `<`. The other comparison operators are listed in the book.\n", + "\n", + "It is easy to confuse the comparison operator `==` with the assignment operator `=`.\n", + "\n", + "Remember that `=` creates a variable or gives an existing variable a new value." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "x = 5" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Whereas `==` compared two values and returns `True` if they are equal." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "x == 5" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can use `==` in an `if` statement." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "yes, x is 5\n" + ] + } + ], + "source": [ + "if x == 5:\n", + " print('yes, x is 5')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "But if you use `=` in an `if` statement, you get an error." + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# If you remove the # from the if statement and run it, you'll get\n", + "# SyntaxError: invalid syntax\n", + "\n", + "#if x = 5:\n", + "# print('yes, x is 5')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise:** Add an `else` clause to the `if` statement above, and print an appropriate message.\n", + "\n", + "Replace the `==` operator with one or two of the other comparison operators, and confirm they do what you expect." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Metrics" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now that we have a working simulation, we'll use it to evaluate alternative designs and see how good or bad they are. The metric we'll use is the number of customers who arrive and find no bikes available, which might indicate a design problem." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First we'll make a new `System` object that creates and initializes the system variables that will keep track of the metrics." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "bikeshare = System(olin=10, wellesley=2, \n", + " olin_empty=0, wellesley_empty=0, clock=0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next we need a version of `move_bike` that updates the metrics." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def move_bike(system, n):\n", + " olin_temp = system.olin - n\n", + " if olin_temp < 0:\n", + " system.olin_empty += 1\n", + " return\n", + " \n", + " wellesley_temp = system.wellesley + n\n", + " if wellesley_temp < 0:\n", + " system.wellesley_empty += 1\n", + " return\n", + " \n", + " system.olin = olin_temp\n", + " system.wellesley = wellesley_temp" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now when we run a simulation, it keeps track of unhappy customers." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "application/javascript": [ + "/* Put everything inside the global mpl namespace */\n", + "window.mpl = {};\n", + "\n", + "\n", + "mpl.get_websocket_type = function() {\n", + " if (typeof(WebSocket) !== 'undefined') {\n", + " return WebSocket;\n", + " } else if (typeof(MozWebSocket) !== 'undefined') {\n", + " return MozWebSocket;\n", + " } else {\n", + " alert('Your browser does not have WebSocket support.' +\n", + " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", + " 'Firefox 4 and 5 are also supported but you ' +\n", + " 'have to enable WebSockets in about:config.');\n", + " };\n", + "}\n", + "\n", + "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", + " this.id = figure_id;\n", + "\n", + " this.ws = websocket;\n", + "\n", + " this.supports_binary = (this.ws.binaryType != undefined);\n", + "\n", + " if (!this.supports_binary) {\n", + " var warnings = document.getElementById(\"mpl-warnings\");\n", + " if (warnings) {\n", + " warnings.style.display = 'block';\n", + " warnings.textContent = (\n", + " \"This browser does not support binary websocket messages. \" +\n", + " \"Performance may be slow.\");\n", + " }\n", + " }\n", + "\n", + " this.imageObj = new Image();\n", + "\n", + " this.context = undefined;\n", + " this.message = undefined;\n", + " this.canvas = undefined;\n", + " this.rubberband_canvas = undefined;\n", + " this.rubberband_context = undefined;\n", + " this.format_dropdown = undefined;\n", + "\n", + " this.image_mode = 'full';\n", + "\n", + " this.root = $('
');\n", + " this._root_extra_style(this.root)\n", + " this.root.attr('style', 'display: inline-block');\n", + "\n", + " $(parent_element).append(this.root);\n", + "\n", + " this._init_header(this);\n", + " this._init_canvas(this);\n", + " this._init_toolbar(this);\n", + "\n", + " var fig = this;\n", + "\n", + " this.waiting = false;\n", + "\n", + " this.ws.onopen = function () {\n", + " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", + " fig.send_message(\"send_image_mode\", {});\n", + " if (mpl.ratio != 1) {\n", + " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n", + " }\n", + " fig.send_message(\"refresh\", {});\n", + " }\n", + "\n", + " this.imageObj.onload = function() {\n", + " if (fig.image_mode == 'full') {\n", + " // Full images could contain transparency (where diff images\n", + " // almost always do), so we need to clear the canvas so that\n", + " // there is no ghosting.\n", + " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", + " }\n", + " fig.context.drawImage(fig.imageObj, 0, 0);\n", + " };\n", + "\n", + " this.imageObj.onunload = function() {\n", + " this.ws.close();\n", + " }\n", + "\n", + " this.ws.onmessage = this._make_on_message_function(this);\n", + "\n", + " this.ondownload = ondownload;\n", + "}\n", + "\n", + "mpl.figure.prototype._init_header = function() {\n", + " var titlebar = $(\n", + " '
');\n", + " var titletext = $(\n", + " '
');\n", + " titlebar.append(titletext)\n", + " this.root.append(titlebar);\n", + " this.header = titletext[0];\n", + "}\n", + "\n", + "\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._init_canvas = function() {\n", + " var fig = this;\n", + "\n", + " var canvas_div = $('
');\n", + "\n", + " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", + "\n", + " function canvas_keyboard_event(event) {\n", + " return fig.key_event(event, event['data']);\n", + " }\n", + "\n", + " canvas_div.keydown('key_press', canvas_keyboard_event);\n", + " canvas_div.keyup('key_release', canvas_keyboard_event);\n", + " this.canvas_div = canvas_div\n", + " this._canvas_extra_style(canvas_div)\n", + " this.root.append(canvas_div);\n", + "\n", + " var canvas = $('');\n", + " canvas.addClass('mpl-canvas');\n", + " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", + "\n", + " this.canvas = canvas[0];\n", + " this.context = canvas[0].getContext(\"2d\");\n", + "\n", + " var backingStore = this.context.backingStorePixelRatio ||\n", + "\tthis.context.webkitBackingStorePixelRatio ||\n", + "\tthis.context.mozBackingStorePixelRatio ||\n", + "\tthis.context.msBackingStorePixelRatio ||\n", + "\tthis.context.oBackingStorePixelRatio ||\n", + "\tthis.context.backingStorePixelRatio || 1;\n", + "\n", + " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n", + "\n", + " var rubberband = $('');\n", + " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", + "\n", + " var pass_mouse_events = true;\n", + "\n", + " canvas_div.resizable({\n", + " start: function(event, ui) {\n", + " pass_mouse_events = false;\n", + " },\n", + " resize: function(event, ui) {\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " stop: function(event, ui) {\n", + " pass_mouse_events = true;\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " });\n", + "\n", + " function mouse_event_fn(event) {\n", + " if (pass_mouse_events)\n", + " return fig.mouse_event(event, event['data']);\n", + " }\n", + "\n", + " rubberband.mousedown('button_press', mouse_event_fn);\n", + " rubberband.mouseup('button_release', mouse_event_fn);\n", + " // Throttle sequential mouse events to 1 every 20ms.\n", + " rubberband.mousemove('motion_notify', mouse_event_fn);\n", + "\n", + " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", + " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", + "\n", + " canvas_div.on(\"wheel\", function (event) {\n", + " event = event.originalEvent;\n", + " event['data'] = 'scroll'\n", + " if (event.deltaY < 0) {\n", + " event.step = 1;\n", + " } else {\n", + " event.step = -1;\n", + " }\n", + " mouse_event_fn(event);\n", + " });\n", + "\n", + " canvas_div.append(canvas);\n", + " canvas_div.append(rubberband);\n", + "\n", + " this.rubberband = rubberband;\n", + " this.rubberband_canvas = rubberband[0];\n", + " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", + " this.rubberband_context.strokeStyle = \"#000000\";\n", + "\n", + " this._resize_canvas = function(width, height) {\n", + " // Keep the size of the canvas, canvas container, and rubber band\n", + " // canvas in synch.\n", + " canvas_div.css('width', width)\n", + " canvas_div.css('height', height)\n", + "\n", + " canvas.attr('width', width * mpl.ratio);\n", + " canvas.attr('height', height * mpl.ratio);\n", + " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n", + "\n", + " rubberband.attr('width', width);\n", + " rubberband.attr('height', height);\n", + " }\n", + "\n", + " // Set the figure to an initial 600x600px, this will subsequently be updated\n", + " // upon first draw.\n", + " this._resize_canvas(600, 600);\n", + "\n", + " // Disable right mouse context menu.\n", + " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", + " return false;\n", + " });\n", + "\n", + " function set_focus () {\n", + " canvas.focus();\n", + " canvas_div.focus();\n", + " }\n", + "\n", + " window.setTimeout(set_focus, 100);\n", + "}\n", + "\n", + "mpl.figure.prototype._init_toolbar = function() {\n", + " var fig = this;\n", + "\n", + " var nav_element = $('
')\n", + " nav_element.attr('style', 'width: 100%');\n", + " this.root.append(nav_element);\n", + "\n", + " // Define a callback function for later on.\n", + " function toolbar_event(event) {\n", + " return fig.toolbar_button_onclick(event['data']);\n", + " }\n", + " function toolbar_mouse_event(event) {\n", + " return fig.toolbar_button_onmouseover(event['data']);\n", + " }\n", + "\n", + " for(var toolbar_ind in mpl.toolbar_items) {\n", + " var name = mpl.toolbar_items[toolbar_ind][0];\n", + " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", + " var image = mpl.toolbar_items[toolbar_ind][2];\n", + " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", + "\n", + " if (!name) {\n", + " // put a spacer in here.\n", + " continue;\n", + " }\n", + " var button = $('');\n", + " button.click(method_name, toolbar_event);\n", + " button.mouseover(tooltip, toolbar_mouse_event);\n", + " nav_element.append(button);\n", + " }\n", + "\n", + " // Add the status bar.\n", + " var status_bar = $('');\n", + " nav_element.append(status_bar);\n", + " this.message = status_bar[0];\n", + "\n", + " // Add the close button to the window.\n", + " var buttongrp = $('
');\n", + " var button = $('');\n", + " button.click(function (evt) { fig.handle_close(fig, {}); } );\n", + " button.mouseover('Stop Interaction', toolbar_mouse_event);\n", + " buttongrp.append(button);\n", + " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n", + " titlebar.prepend(buttongrp);\n", + "}\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(el){\n", + " var fig = this\n", + " el.on(\"remove\", function(){\n", + "\tfig.close_ws(fig, {});\n", + " });\n", + "}\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(el){\n", + " // this is important to make the div 'focusable\n", + " el.attr('tabindex', 0)\n", + " // reach out to IPython and tell the keyboard manager to turn it's self\n", + " // off when our div gets focus\n", + "\n", + " // location in version 3\n", + " if (IPython.notebook.keyboard_manager) {\n", + " IPython.notebook.keyboard_manager.register_events(el);\n", + " }\n", + " else {\n", + " // location in version 2\n", + " IPython.keyboard_manager.register_events(el);\n", + " }\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._key_event_extra = function(event, name) {\n", + " var manager = IPython.notebook.keyboard_manager;\n", + " if (!manager)\n", + " manager = IPython.keyboard_manager;\n", + "\n", + " // Check for shift+enter\n", + " if (event.shiftKey && event.which == 13) {\n", + " this.canvas_div.blur();\n", + " // select the cell after this one\n", + " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", + " IPython.notebook.select(index + 1);\n", + " }\n", + "}\n", + "\n", + "mpl.figure.prototype.handle_save = function(fig, msg) {\n", + " fig.ondownload(fig, null);\n", + "}\n", + "\n", + "\n", + "mpl.find_output_cell = function(html_output) {\n", + " // Return the cell and output element which can be found *uniquely* in the notebook.\n", + " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", + " // IPython event is triggered only after the cells have been serialised, which for\n", + " // our purposes (turning an active figure into a static one), is too late.\n", + " var cells = IPython.notebook.get_cells();\n", + " var ncells = cells.length;\n", + " for (var i=0; i= 3 moved mimebundle to data attribute of output\n", + " data = data.data;\n", + " }\n", + " if (data['text/html'] == html_output) {\n", + " return [cell, data, j];\n", + " }\n", + " }\n", + " }\n", + " }\n", + "}\n", + "\n", + "// Register the function which deals with the matplotlib target/channel.\n", + "// The kernel may be null if the page has been refreshed.\n", + "if (IPython.notebook.kernel != null) {\n", + " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", + "}\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n", + "1\n", + "2\n", + "3\n", + "4\n", + "5\n", + "6\n", + "7\n", + "8\n", + "9\n", + "10\n", + "11\n", + "12\n", + "13\n", + "14\n", + "15\n", + "16\n", + "17\n", + "18\n", + "19\n", + "20\n", + "21\n", + "22\n", + "23\n", + "24\n", + "25\n", + "26\n", + "27\n", + "28\n", + "29\n", + "30\n", + "31\n", + "32\n", + "33\n", + "34\n", + "35\n", + "36\n", + "37\n", + "38\n", + "39\n", + "40\n", + "41\n", + "42\n", + "43\n", + "44\n", + "45\n", + "46\n", + "47\n", + "48\n", + "49\n", + "50\n", + "51\n", + "52\n", + "53\n", + "54\n", + "55\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "IOPub data rate exceeded.\n", + "The notebook server will temporarily stop sending output\n", + "to the client in order to avoid crashing it.\n", + "To change this limit, set the config variable\n", + "`--NotebookApp.iopub_data_rate_limit`.\n" + ] + } + ], + "source": [ + " newfig()\n", + "plot_system(bikeshare)\n", + "decorate_bikeshare()\n", + "bikeshare.clock=0\n", + "run_steps(bikeshare, 60, 0.4, 0.2)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Solution goes here" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Solution goes here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "After the simulation, check the final value of `clock`." + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "60\n" + ] + } + ], + "source": [ + " print(bikeshare.clock)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise:** Now suppose we'd like to know how long it takes to run out of bikes at either location. Modify `move_bike` so the first time a student arrives at Olin and doesn't find a bike, it records the value of `clock` in a system variable.\n", + "\n", + "Hint: create a system variable named `t_first_empty` and initialize it to `-1` to indicate that it has not been set yet.\n", + "\n", + "Test your code by running a simulation for 60 minutes and checking the metrics." + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'system' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0msystem\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mt_first_empty\u001b[0m\u001b[1;33m=\u001b[0m \u001b[1;33m-\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[1;31mNameError\u001b[0m: name 'system' is not defined" + ] + } + ], + "source": [ + " system.t_first_empty= -1" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Solution goes here" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Solution goes here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "After the simulation, check the final value of `t_first_empty`." + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "ename": "AttributeError", + "evalue": "'System' object has no attribute 't_first_empty'", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)", + "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mbikeshare\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mt_first_empty\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[1;32mC:\\ProgramData\\Miniconda3\\lib\\site-packages\\pandas\\core\\generic.py\u001b[0m in \u001b[0;36m__getattr__\u001b[1;34m(self, name)\u001b[0m\n\u001b[0;32m 3079\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mname\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_info_axis\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 3080\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mname\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 3081\u001b[1;33m \u001b[1;32mreturn\u001b[0m \u001b[0mobject\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m__getattribute__\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mname\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 3082\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 3083\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0m__setattr__\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mname\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;31mAttributeError\u001b[0m: 'System' object has no attribute 't_first_empty'" + ] + } + ], + "source": [ + "print(bikeshare.t_first_empty)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Before we go on, let's put `step` and `move_bike` back the way we found them, so they don't break the examples below." + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def step(system, p1=0.5, p2=0.5):\n", + " if flip(p1):\n", + " bike_to_wellesley(system)\n", + " \n", + " if flip(p2):\n", + " bike_to_olin(system)\n", + "\n", + "def move_bike(system, n):\n", + " olin_temp = system.olin - n\n", + " if olin_temp < 0:\n", + " system.olin_empty += 1\n", + " return\n", + " \n", + " wellesley_temp = system.wellesley + n\n", + " if wellesley_temp < 0:\n", + " system.wellesley_empty += 1\n", + " return\n", + " \n", + " system.olin = olin_temp\n", + " system.wellesley = wellesley_temp" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Returning values" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here's a simple function that returns a value:" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def add_five(x):\n", + " return x + 5" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And here's how we call it." + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "8" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "y = add_five(3)\n", + "y" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you run a function on the last line of a cell, Jupyter displays the result:" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "10" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "add_five(5)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "But that can be a bad habit, because usually if you call a function and don't assign the result in a variable, the result gets discarded.\n", + "\n", + "In the following example, Jupyter shows the second result, but the first result just disappears." + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "10" + ] + }, + "execution_count": 40, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "add_five(3)\n", + "add_five(5)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "When you call a function that returns a variable, it is generally a good idea to assign the result to a variable." + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "8 10\n" + ] + } + ], + "source": [ + "y1 = add_five(3)\n", + "y2 = add_five(5)\n", + "\n", + "print(y1, y2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise:** Write a function called `make_system` that creates a `System` object with the system variables `olin=10` and `wellesley=2`, and then returns the new `System` object.\n", + "\n", + "Write a line of code that calls `make_system` and assigns the result to a variable." + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
value
olin10
wellesley2
\n", + "
" + ], + "text/plain": [ + "olin 10\n", + "wellesley 2\n", + "dtype: int64" + ] + }, + "execution_count": 42, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def make_system():\n", + " system = System(olin=10, wellesley=2)\n", + " return system\n", + "\n", + "system = make_system()\n", + "system" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Solution goes here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Running simulations" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Before we go on, I want to update `run_steps` so it doesn't always plot the results. The new version takes an additional parameter, `plot_flag`, to indicate whether we want to plot.\n", + "\n", + "\"flag\" is a conventional name for a boolean variable that indicates whether or not a condition is true.\n", + "\n", + "This version of `run_steps` works even if `num_steps` is not an integer. It uses the `int` function to round down. See https://docs.python.org/3/library/functions.html#int" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def run_steps(system, num_steps=1, p1=0.5, p2=0.5, plot_flag=True):\n", + " \"\"\"Simulate the given number of time steps.\n", + " \n", + " `num_steps` should be an integer; if not, it gets rounded down.\n", + " \n", + " system: bikeshare System object\n", + " num_steps: number of time steps\n", + " p1: probability of an Olin->Wellesley customer arrival\n", + " p2: probability of a Wellesley->Olin customer arrival\n", + " plot_flag: boolean, whether to plot\n", + " \"\"\"\n", + " for i in range(int(num_steps)):\n", + " step(system, p1, p2)\n", + " if plot_flag:\n", + " plot_system(system)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now when we run a simulation, we can choose not to plot the results:" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "bikeshare = System(olin=10, wellesley=2, \n", + " olin_empty=0, wellesley_empty=0)\n", + "run_steps(bikeshare, 60, 0.4, 0.2, plot_flag=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "But after the simulation, we can still read the metrics." + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "13" + ] + }, + "execution_count": 45, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bikeshare.olin_empty" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's wrap all that in a function." + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def run_simulation():\n", + " system = System(olin=10, wellesley=2, \n", + " olin_empty=0, wellesley_empty=0)\n", + " run_steps(system, 60, 0.4, 0.2, plot_flag=False)\n", + " return system" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And test it." + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "system = run_simulation()" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0 0\n" + ] + } + ], + "source": [ + "print(system.olin_empty, system.wellesley_empty)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If we generalize `run_simulation` to take `p1` and `p2`, we can use it to run simulations with a range of values for the parameters." + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def run_simulation(p1=0.4, p2=0.2):\n", + " bikeshare = System(olin=10, wellesley=2, \n", + " olin_empty=0, wellesley_empty=0)\n", + " run_steps(bikeshare, 60, p1, p2, plot_flag=False)\n", + " return bikeshare" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "When `p1` is small, we probably don't run out of bikes at Olin." + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0" + ] + }, + "execution_count": 50, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "system = run_simulation(p1=0.2)\n", + "system.olin_empty" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "When `p1` is large, we probably do." + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "24" + ] + }, + "execution_count": 51, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "system = run_simulation(p1=0.6)\n", + "system.olin_empty" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "**Exercise:** Write a version of `run_simulation` that takes all five model parameters as function parameters." + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0 0\n" + ] + } + ], + "source": [ + "def run_simulation(p1=0.4, p2=0.2, olin=10, wellesley=2, num_steps=60):\n", + " bikeshare = System(olin=olin, wellesley=wellesley, \n", + " olin_empty=0, wellesley_empty=0)\n", + " run_steps(bikeshare, num_steps, p1, p2, plot_flag=False)\n", + " return bikeshare\n", + "\n", + "system = run_simulation(p1=0.2, p2=0.4, olin=3, wellesley=9, num_steps=30)\n", + "print(system.olin_empty, system.wellesley_empty)" + ] + }, + { + "cell_type": "code", + "execution_count": 71, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Solution goes here" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "## More for loops" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`linspace` creates a NumPy array of equally spaced numbers." + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([ 0. , 0.25, 0.5 , 0.75, 1. ])" + ] + }, + "execution_count": 55, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "p1_array = linspace(start=0, stop=1, num=5)\n", + "p1_array" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can use an array in a `for` loop, like this:" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0.0\n", + "0.25\n", + "0.5\n", + "0.75\n", + "1.0\n" + ] + } + ], + "source": [ + "for p1 in p1_array:\n", + " print(p1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This will come in handy in the next section." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise:** The function `linspace` is part of NumPy. [You can read the documentation here](https://docs.scipy.org/doc/numpy/reference/generated/numpy.linspace.html).\n", + "\n", + "Use `linspace` to make an array of 10 equally spaced numbers from 1 to 10 (including both)." + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([ 1., 2., 3., 4., 5., 6., 7., 8., 9., 10.])" + ] + }, + "execution_count": 57, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "linspace(1,10,10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Exercise:** The `modsim` library provides a related function called `linrange`. You can view the documentation by running the following cell:" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Help on function linrange in module modsim:\n", + "\n", + "linrange(start=0, stop=None, step=1, **kwargs)\n", + " Returns an array of evenly-spaced values in the interval [start, stop].\n", + " \n", + " This function works best if the space between start and stop\n", + " is divisible by step; otherwise the results might be surprising.\n", + " \n", + " By default, the last value in the array is `stop` (at least approximately).\n", + " If you provide the keyword argument `endpoint=False`, the last value\n", + " in the array is `stop-step`. \n", + " \n", + " start: first value\n", + " stop: last value\n", + " step: space between values\n", + " \n", + " Also accepts the same keyword arguments as np.linspace. See\n", + " https://docs.scipy.org/doc/numpy/reference/generated/numpy.linspace.html\n", + " \n", + " returns: array or Quantity\n", + "\n" + ] + } + ], + "source": [ + "help(linrange)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Use `linrange` to make an array of numbers from 1 to 11 with a step size of 2." + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([ 1., 3., 5., 7., 9., 11.])" + ] + }, + "execution_count": 59, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "linrange(1,11,2)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "## Sweeping parameters" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The following example runs simulations with a range of values for `p1`; after each simulation, it prints the number of unhappy customers at the Olin station:" + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([ 0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1. ])" + ] + }, + "execution_count": 60, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "p1_array = linspace(0, 1, 11)\n", + "p1_array" + ] + }, + { + "cell_type": "code", + "execution_count": 61, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0.0 0\n", + "0.1 0\n", + "0.2 0\n", + "0.3 0\n", + "0.4 9\n", + "0.5 9\n", + "0.6 18\n", + "0.7 22\n", + "0.8 20\n", + "0.9 35\n", + "1.0 38\n" + ] + } + ], + "source": [ + "for p1 in p1_array:\n", + " system = run_simulation(p1=p1)\n", + " print(p1, system.olin_empty)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can do the same thing, but plotting the results instead of printing them.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "metadata": {}, + "outputs": [ + { + "data": { + "application/javascript": [ + "/* Put everything inside the global mpl namespace */\n", + "window.mpl = {};\n", + "\n", + "\n", + "mpl.get_websocket_type = function() {\n", + " if (typeof(WebSocket) !== 'undefined') {\n", + " return WebSocket;\n", + " } else if (typeof(MozWebSocket) !== 'undefined') {\n", + " return MozWebSocket;\n", + " } else {\n", + " alert('Your browser does not have WebSocket support.' +\n", + " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", + " 'Firefox 4 and 5 are also supported but you ' +\n", + " 'have to enable WebSockets in about:config.');\n", + " };\n", + "}\n", + "\n", + "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", + " this.id = figure_id;\n", + "\n", + " this.ws = websocket;\n", + "\n", + " this.supports_binary = (this.ws.binaryType != undefined);\n", + "\n", + " if (!this.supports_binary) {\n", + " var warnings = document.getElementById(\"mpl-warnings\");\n", + " if (warnings) {\n", + " warnings.style.display = 'block';\n", + " warnings.textContent = (\n", + " \"This browser does not support binary websocket messages. \" +\n", + " \"Performance may be slow.\");\n", + " }\n", + " }\n", + "\n", + " this.imageObj = new Image();\n", + "\n", + " this.context = undefined;\n", + " this.message = undefined;\n", + " this.canvas = undefined;\n", + " this.rubberband_canvas = undefined;\n", + " this.rubberband_context = undefined;\n", + " this.format_dropdown = undefined;\n", + "\n", + " this.image_mode = 'full';\n", + "\n", + " this.root = $('
');\n", + " this._root_extra_style(this.root)\n", + " this.root.attr('style', 'display: inline-block');\n", + "\n", + " $(parent_element).append(this.root);\n", + "\n", + " this._init_header(this);\n", + " this._init_canvas(this);\n", + " this._init_toolbar(this);\n", + "\n", + " var fig = this;\n", + "\n", + " this.waiting = false;\n", + "\n", + " this.ws.onopen = function () {\n", + " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", + " fig.send_message(\"send_image_mode\", {});\n", + " if (mpl.ratio != 1) {\n", + " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n", + " }\n", + " fig.send_message(\"refresh\", {});\n", + " }\n", + "\n", + " this.imageObj.onload = function() {\n", + " if (fig.image_mode == 'full') {\n", + " // Full images could contain transparency (where diff images\n", + " // almost always do), so we need to clear the canvas so that\n", + " // there is no ghosting.\n", + " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", + " }\n", + " fig.context.drawImage(fig.imageObj, 0, 0);\n", + " };\n", + "\n", + " this.imageObj.onunload = function() {\n", + " this.ws.close();\n", + " }\n", + "\n", + " this.ws.onmessage = this._make_on_message_function(this);\n", + "\n", + " this.ondownload = ondownload;\n", + "}\n", + "\n", + "mpl.figure.prototype._init_header = function() {\n", + " var titlebar = $(\n", + " '
');\n", + " var titletext = $(\n", + " '
');\n", + " titlebar.append(titletext)\n", + " this.root.append(titlebar);\n", + " this.header = titletext[0];\n", + "}\n", + "\n", + "\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._init_canvas = function() {\n", + " var fig = this;\n", + "\n", + " var canvas_div = $('
');\n", + "\n", + " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", + "\n", + " function canvas_keyboard_event(event) {\n", + " return fig.key_event(event, event['data']);\n", + " }\n", + "\n", + " canvas_div.keydown('key_press', canvas_keyboard_event);\n", + " canvas_div.keyup('key_release', canvas_keyboard_event);\n", + " this.canvas_div = canvas_div\n", + " this._canvas_extra_style(canvas_div)\n", + " this.root.append(canvas_div);\n", + "\n", + " var canvas = $('');\n", + " canvas.addClass('mpl-canvas');\n", + " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", + "\n", + " this.canvas = canvas[0];\n", + " this.context = canvas[0].getContext(\"2d\");\n", + "\n", + " var backingStore = this.context.backingStorePixelRatio ||\n", + "\tthis.context.webkitBackingStorePixelRatio ||\n", + "\tthis.context.mozBackingStorePixelRatio ||\n", + "\tthis.context.msBackingStorePixelRatio ||\n", + "\tthis.context.oBackingStorePixelRatio ||\n", + "\tthis.context.backingStorePixelRatio || 1;\n", + "\n", + " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n", + "\n", + " var rubberband = $('');\n", + " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", + "\n", + " var pass_mouse_events = true;\n", + "\n", + " canvas_div.resizable({\n", + " start: function(event, ui) {\n", + " pass_mouse_events = false;\n", + " },\n", + " resize: function(event, ui) {\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " stop: function(event, ui) {\n", + " pass_mouse_events = true;\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " });\n", + "\n", + " function mouse_event_fn(event) {\n", + " if (pass_mouse_events)\n", + " return fig.mouse_event(event, event['data']);\n", + " }\n", + "\n", + " rubberband.mousedown('button_press', mouse_event_fn);\n", + " rubberband.mouseup('button_release', mouse_event_fn);\n", + " // Throttle sequential mouse events to 1 every 20ms.\n", + " rubberband.mousemove('motion_notify', mouse_event_fn);\n", + "\n", + " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", + " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", + "\n", + " canvas_div.on(\"wheel\", function (event) {\n", + " event = event.originalEvent;\n", + " event['data'] = 'scroll'\n", + " if (event.deltaY < 0) {\n", + " event.step = 1;\n", + " } else {\n", + " event.step = -1;\n", + " }\n", + " mouse_event_fn(event);\n", + " });\n", + "\n", + " canvas_div.append(canvas);\n", + " canvas_div.append(rubberband);\n", + "\n", + " this.rubberband = rubberband;\n", + " this.rubberband_canvas = rubberband[0];\n", + " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", + " this.rubberband_context.strokeStyle = \"#000000\";\n", + "\n", + " this._resize_canvas = function(width, height) {\n", + " // Keep the size of the canvas, canvas container, and rubber band\n", + " // canvas in synch.\n", + " canvas_div.css('width', width)\n", + " canvas_div.css('height', height)\n", + "\n", + " canvas.attr('width', width * mpl.ratio);\n", + " canvas.attr('height', height * mpl.ratio);\n", + " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n", + "\n", + " rubberband.attr('width', width);\n", + " rubberband.attr('height', height);\n", + " }\n", + "\n", + " // Set the figure to an initial 600x600px, this will subsequently be updated\n", + " // upon first draw.\n", + " this._resize_canvas(600, 600);\n", + "\n", + " // Disable right mouse context menu.\n", + " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", + " return false;\n", + " });\n", + "\n", + " function set_focus () {\n", + " canvas.focus();\n", + " canvas_div.focus();\n", + " }\n", + "\n", + " window.setTimeout(set_focus, 100);\n", + "}\n", + "\n", + "mpl.figure.prototype._init_toolbar = function() {\n", + " var fig = this;\n", + "\n", + " var nav_element = $('
')\n", + " nav_element.attr('style', 'width: 100%');\n", + " this.root.append(nav_element);\n", + "\n", + " // Define a callback function for later on.\n", + " function toolbar_event(event) {\n", + " return fig.toolbar_button_onclick(event['data']);\n", + " }\n", + " function toolbar_mouse_event(event) {\n", + " return fig.toolbar_button_onmouseover(event['data']);\n", + " }\n", + "\n", + " for(var toolbar_ind in mpl.toolbar_items) {\n", + " var name = mpl.toolbar_items[toolbar_ind][0];\n", + " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", + " var image = mpl.toolbar_items[toolbar_ind][2];\n", + " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", + "\n", + " if (!name) {\n", + " // put a spacer in here.\n", + " continue;\n", + " }\n", + " var button = $('');\n", + " button.click(method_name, toolbar_event);\n", + " button.mouseover(tooltip, toolbar_mouse_event);\n", + " nav_element.append(button);\n", + " }\n", + "\n", + " // Add the status bar.\n", + " var status_bar = $('');\n", + " nav_element.append(status_bar);\n", + " this.message = status_bar[0];\n", + "\n", + " // Add the close button to the window.\n", + " var buttongrp = $('
');\n", + " var button = $('');\n", + " button.click(function (evt) { fig.handle_close(fig, {}); } );\n", + " button.mouseover('Stop Interaction', toolbar_mouse_event);\n", + " buttongrp.append(button);\n", + " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n", + " titlebar.prepend(buttongrp);\n", + "}\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(el){\n", + " var fig = this\n", + " el.on(\"remove\", function(){\n", + "\tfig.close_ws(fig, {});\n", + " });\n", + "}\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(el){\n", + " // this is important to make the div 'focusable\n", + " el.attr('tabindex', 0)\n", + " // reach out to IPython and tell the keyboard manager to turn it's self\n", + " // off when our div gets focus\n", + "\n", + " // location in version 3\n", + " if (IPython.notebook.keyboard_manager) {\n", + " IPython.notebook.keyboard_manager.register_events(el);\n", + " }\n", + " else {\n", + " // location in version 2\n", + " IPython.keyboard_manager.register_events(el);\n", + " }\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._key_event_extra = function(event, name) {\n", + " var manager = IPython.notebook.keyboard_manager;\n", + " if (!manager)\n", + " manager = IPython.keyboard_manager;\n", + "\n", + " // Check for shift+enter\n", + " if (event.shiftKey && event.which == 13) {\n", + " this.canvas_div.blur();\n", + " // select the cell after this one\n", + " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", + " IPython.notebook.select(index + 1);\n", + " }\n", + "}\n", + "\n", + "mpl.figure.prototype.handle_save = function(fig, msg) {\n", + " fig.ondownload(fig, null);\n", + "}\n", + "\n", + "\n", + "mpl.find_output_cell = function(html_output) {\n", + " // Return the cell and output element which can be found *uniquely* in the notebook.\n", + " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", + " // IPython event is triggered only after the cells have been serialised, which for\n", + " // our purposes (turning an active figure into a static one), is too late.\n", + " var cells = IPython.notebook.get_cells();\n", + " var ncells = cells.length;\n", + " for (var i=0; i= 3 moved mimebundle to data attribute of output\n", + " data = data.data;\n", + " }\n", + " if (data['text/html'] == html_output) {\n", + " return [cell, data, j];\n", + " }\n", + " }\n", + " }\n", + " }\n", + "}\n", + "\n", + "// Register the function which deals with the matplotlib target/channel.\n", + "// The kernel may be null if the page has been refreshed.\n", + "if (IPython.notebook.kernel != null) {\n", + " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", + "}\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "newfig()\n", + "p1_array = linspace(0, 1, 101)\n", + "parameter_sweep(p1_array)\n", + "decorate_bikeshare(xlabel='Arrival rate at Olin (p1 in customers/min)')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "**Exercise:** Write a function called `parameter_sweep2` that runs simulations with `p1=0.2` and a range of values for `p2`.\n", + "\n", + "Note: If you run `parameter_sweep2` a few times without calling `newfig`, you can plot multiple runs on the same axes, which will give you a sense of how much random variation there is from one run to the next. " + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def parameter_sweep2(p2_array):\n", + " for p2 in p2_array:\n", + " system = run_simulation(p1=0.2, p2=p2)\n", + " plot(p2, system.olin_empty, 'rs', label='Olin')\n", + " plot(p2, system.wellesley_empty, 'bo', label='Wellesley')" + ] + }, + { + "cell_type": "code", + "execution_count": 70, + "metadata": {}, + "outputs": [ + { + "data": { + "application/javascript": [ + "/* Put everything inside the global mpl namespace */\n", + "window.mpl = {};\n", + "\n", + "\n", + "mpl.get_websocket_type = function() {\n", + " if (typeof(WebSocket) !== 'undefined') {\n", + " return WebSocket;\n", + " } else if (typeof(MozWebSocket) !== 'undefined') {\n", + " return MozWebSocket;\n", + " } else {\n", + " alert('Your browser does not have WebSocket support.' +\n", + " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", + " 'Firefox 4 and 5 are also supported but you ' +\n", + " 'have to enable WebSockets in about:config.');\n", + " };\n", + "}\n", + "\n", + "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", + " this.id = figure_id;\n", + "\n", + " this.ws = websocket;\n", + "\n", + " this.supports_binary = (this.ws.binaryType != undefined);\n", + "\n", + " if (!this.supports_binary) {\n", + " var warnings = document.getElementById(\"mpl-warnings\");\n", + " if (warnings) {\n", + " warnings.style.display = 'block';\n", + " warnings.textContent = (\n", + " \"This browser does not support binary websocket messages. \" +\n", + " \"Performance may be slow.\");\n", + " }\n", + " }\n", + "\n", + " this.imageObj = new Image();\n", + "\n", + " this.context = undefined;\n", + " this.message = undefined;\n", + " this.canvas = undefined;\n", + " this.rubberband_canvas = undefined;\n", + " this.rubberband_context = undefined;\n", + " this.format_dropdown = undefined;\n", + "\n", + " this.image_mode = 'full';\n", + "\n", + " this.root = $('
');\n", + " this._root_extra_style(this.root)\n", + " this.root.attr('style', 'display: inline-block');\n", + "\n", + " $(parent_element).append(this.root);\n", + "\n", + " this._init_header(this);\n", + " this._init_canvas(this);\n", + " this._init_toolbar(this);\n", + "\n", + " var fig = this;\n", + "\n", + " this.waiting = false;\n", + "\n", + " this.ws.onopen = function () {\n", + " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", + " fig.send_message(\"send_image_mode\", {});\n", + " if (mpl.ratio != 1) {\n", + " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n", + " }\n", + " fig.send_message(\"refresh\", {});\n", + " }\n", + "\n", + " this.imageObj.onload = function() {\n", + " if (fig.image_mode == 'full') {\n", + " // Full images could contain transparency (where diff images\n", + " // almost always do), so we need to clear the canvas so that\n", + " // there is no ghosting.\n", + " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", + " }\n", + " fig.context.drawImage(fig.imageObj, 0, 0);\n", + " };\n", + "\n", + " this.imageObj.onunload = function() {\n", + " this.ws.close();\n", + " }\n", + "\n", + " this.ws.onmessage = this._make_on_message_function(this);\n", + "\n", + " this.ondownload = ondownload;\n", + "}\n", + "\n", + "mpl.figure.prototype._init_header = function() {\n", + " var titlebar = $(\n", + " '
');\n", + " var titletext = $(\n", + " '
');\n", + " titlebar.append(titletext)\n", + " this.root.append(titlebar);\n", + " this.header = titletext[0];\n", + "}\n", + "\n", + "\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._init_canvas = function() {\n", + " var fig = this;\n", + "\n", + " var canvas_div = $('
');\n", + "\n", + " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", + "\n", + " function canvas_keyboard_event(event) {\n", + " return fig.key_event(event, event['data']);\n", + " }\n", + "\n", + " canvas_div.keydown('key_press', canvas_keyboard_event);\n", + " canvas_div.keyup('key_release', canvas_keyboard_event);\n", + " this.canvas_div = canvas_div\n", + " this._canvas_extra_style(canvas_div)\n", + " this.root.append(canvas_div);\n", + "\n", + " var canvas = $('');\n", + " canvas.addClass('mpl-canvas');\n", + " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", + "\n", + " this.canvas = canvas[0];\n", + " this.context = canvas[0].getContext(\"2d\");\n", + "\n", + " var backingStore = this.context.backingStorePixelRatio ||\n", + "\tthis.context.webkitBackingStorePixelRatio ||\n", + "\tthis.context.mozBackingStorePixelRatio ||\n", + "\tthis.context.msBackingStorePixelRatio ||\n", + "\tthis.context.oBackingStorePixelRatio ||\n", + "\tthis.context.backingStorePixelRatio || 1;\n", + "\n", + " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n", + "\n", + " var rubberband = $('');\n", + " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", + "\n", + " var pass_mouse_events = true;\n", + "\n", + " canvas_div.resizable({\n", + " start: function(event, ui) {\n", + " pass_mouse_events = false;\n", + " },\n", + " resize: function(event, ui) {\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " stop: function(event, ui) {\n", + " pass_mouse_events = true;\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " });\n", + "\n", + " function mouse_event_fn(event) {\n", + " if (pass_mouse_events)\n", + " return fig.mouse_event(event, event['data']);\n", + " }\n", + "\n", + " rubberband.mousedown('button_press', mouse_event_fn);\n", + " rubberband.mouseup('button_release', mouse_event_fn);\n", + " // Throttle sequential mouse events to 1 every 20ms.\n", + " rubberband.mousemove('motion_notify', mouse_event_fn);\n", + "\n", + " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", + " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", + "\n", + " canvas_div.on(\"wheel\", function (event) {\n", + " event = event.originalEvent;\n", + " event['data'] = 'scroll'\n", + " if (event.deltaY < 0) {\n", + " event.step = 1;\n", + " } else {\n", + " event.step = -1;\n", + " }\n", + " mouse_event_fn(event);\n", + " });\n", + "\n", + " canvas_div.append(canvas);\n", + " canvas_div.append(rubberband);\n", + "\n", + " this.rubberband = rubberband;\n", + " this.rubberband_canvas = rubberband[0];\n", + " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", + " this.rubberband_context.strokeStyle = \"#000000\";\n", + "\n", + " this._resize_canvas = function(width, height) {\n", + " // Keep the size of the canvas, canvas container, and rubber band\n", + " // canvas in synch.\n", + " canvas_div.css('width', width)\n", + " canvas_div.css('height', height)\n", + "\n", + " canvas.attr('width', width * mpl.ratio);\n", + " canvas.attr('height', height * mpl.ratio);\n", + " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n", + "\n", + " rubberband.attr('width', width);\n", + " rubberband.attr('height', height);\n", + " }\n", + "\n", + " // Set the figure to an initial 600x600px, this will subsequently be updated\n", + " // upon first draw.\n", + " this._resize_canvas(600, 600);\n", + "\n", + " // Disable right mouse context menu.\n", + " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", + " return false;\n", + " });\n", + "\n", + " function set_focus () {\n", + " canvas.focus();\n", + " canvas_div.focus();\n", + " }\n", + "\n", + " window.setTimeout(set_focus, 100);\n", + "}\n", + "\n", + "mpl.figure.prototype._init_toolbar = function() {\n", + " var fig = this;\n", + "\n", + " var nav_element = $('
')\n", + " nav_element.attr('style', 'width: 100%');\n", + " this.root.append(nav_element);\n", + "\n", + " // Define a callback function for later on.\n", + " function toolbar_event(event) {\n", + " return fig.toolbar_button_onclick(event['data']);\n", + " }\n", + " function toolbar_mouse_event(event) {\n", + " return fig.toolbar_button_onmouseover(event['data']);\n", + " }\n", + "\n", + " for(var toolbar_ind in mpl.toolbar_items) {\n", + " var name = mpl.toolbar_items[toolbar_ind][0];\n", + " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", + " var image = mpl.toolbar_items[toolbar_ind][2];\n", + " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", + "\n", + " if (!name) {\n", + " // put a spacer in here.\n", + " continue;\n", + " }\n", + " var button = $('');\n", + " button.click(method_name, toolbar_event);\n", + " button.mouseover(tooltip, toolbar_mouse_event);\n", + " nav_element.append(button);\n", + " }\n", + "\n", + " // Add the status bar.\n", + " var status_bar = $('');\n", + " nav_element.append(status_bar);\n", + " this.message = status_bar[0];\n", + "\n", + " // Add the close button to the window.\n", + " var buttongrp = $('
');\n", + " var button = $('');\n", + " button.click(function (evt) { fig.handle_close(fig, {}); } );\n", + " button.mouseover('Stop Interaction', toolbar_mouse_event);\n", + " buttongrp.append(button);\n", + " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n", + " titlebar.prepend(buttongrp);\n", + "}\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(el){\n", + " var fig = this\n", + " el.on(\"remove\", function(){\n", + "\tfig.close_ws(fig, {});\n", + " });\n", + "}\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(el){\n", + " // this is important to make the div 'focusable\n", + " el.attr('tabindex', 0)\n", + " // reach out to IPython and tell the keyboard manager to turn it's self\n", + " // off when our div gets focus\n", + "\n", + " // location in version 3\n", + " if (IPython.notebook.keyboard_manager) {\n", + " IPython.notebook.keyboard_manager.register_events(el);\n", + " }\n", + " else {\n", + " // location in version 2\n", + " IPython.keyboard_manager.register_events(el);\n", + " }\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._key_event_extra = function(event, name) {\n", + " var manager = IPython.notebook.keyboard_manager;\n", + " if (!manager)\n", + " manager = IPython.keyboard_manager;\n", + "\n", + " // Check for shift+enter\n", + " if (event.shiftKey && event.which == 13) {\n", + " this.canvas_div.blur();\n", + " // select the cell after this one\n", + " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", + " IPython.notebook.select(index + 1);\n", + " }\n", + "}\n", + "\n", + "mpl.figure.prototype.handle_save = function(fig, msg) {\n", + " fig.ondownload(fig, null);\n", + "}\n", + "\n", + "\n", + "mpl.find_output_cell = function(html_output) {\n", + " // Return the cell and output element which can be found *uniquely* in the notebook.\n", + " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", + " // IPython event is triggered only after the cells have been serialised, which for\n", + " // our purposes (turning an active figure into a static one), is too late.\n", + " var cells = IPython.notebook.get_cells();\n", + " var ncells = cells.length;\n", + " for (var i=0; i= 3 moved mimebundle to data attribute of output\n", + " data = data.data;\n", + " }\n", + " if (data['text/html'] == html_output) {\n", + " return [cell, data, j];\n", + " }\n", + " }\n", + " }\n", + " }\n", + "}\n", + "\n", + "// Register the function which deals with the matplotlib target/channel.\n", + "// The kernel may be null if the page has been refreshed.\n", + "if (IPython.notebook.kernel != null) {\n", + " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", + "}\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "newfig()\n", + "num_steps_array = linrange(1, 101)\n", + "parameter_sweep3(num_steps_array)\n", + "decorate_bikeshare('Number of time steps (minutes)')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "**Exercise:** The code below runs a simulation with the same parameters 10 times and computes the average number of unhappy customers.\n", + "\n", + "1. Wrap this code in a function called `run_simulations` that takes `num_runs` as a parameter.\n", + "\n", + "2. Test `run_simulations`, and increase `num_runs` until the results are reasonably consistent from one run to the next.\n", + "\n", + "3. Generalize `run_simulations` so it also takes the initial value of `olin` as a parameter.\n", + "\n", + "4. Run the generalized version with `olin=12`. How much do the two extra bikes decrease the average number of unhappy customers.\n", + "\n", + "5. Make a plot that shows the average number of unhappy customers as a function of the initial number of bikes at Olin." + ] + }, + { + "cell_type": "code", + "execution_count": 75, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3.3999999999999999" + ] + }, + "execution_count": 75, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "num_runs = 10\n", + "total = 0\n", + "for i in range(num_runs):\n", + " system = run_simulation(p1=0.4, p2=0.2, olin=10, wellesley=2, num_steps=60)\n", + " total += system.olin_empty + system.wellesley_empty\n", + "total / num_runs" + ] + }, + { + "cell_type": "code", + "execution_count": 76, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def run_simulations(olin, num_runs=1000):\n", + " total = 0\n", + " for i in range(num_runs):\n", + " system = run_simulation(p1=0.4, p2=0.2, olin=olin, wellesley=2, num_steps=60)\n", + " total += system.olin_empty + system.wellesley_empty\n", + " return total / num_runs" + ] + }, + { + "cell_type": "code", + "execution_count": 77, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3.8119999999999998" + ] + }, + "execution_count": 77, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "run_simulations(olin=10)" + ] + }, + { + "cell_type": "code", + "execution_count": 78, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "2.4529999999999998" + ] + }, + "execution_count": 78, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "run_simulations(olin=12)" + ] + }, + { + "cell_type": "code", + "execution_count": 79, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2.0 11.022\n", + "4.0 9.06\n", + "6.0 6.818\n", + "8.0 5.101\n", + "10.0 3.658\n", + "12.0 2.284\n", + "14.0 1.357\n", + "16.0 0.783\n", + "18.0 0.357\n" + ] + } + ], + "source": [ + "for olin in linrange(2, 18, 2):\n", + " avg = run_simulations(olin=olin)\n", + " print(olin, avg)" + ] + }, + { + "cell_type": "code", + "execution_count": 81, + "metadata": {}, + "outputs": [ + { + "data": { + "application/javascript": [ + "/* Put everything inside the global mpl namespace */\n", + "window.mpl = {};\n", + "\n", + "\n", + "mpl.get_websocket_type = function() {\n", + " if (typeof(WebSocket) !== 'undefined') {\n", + " return WebSocket;\n", + " } else if (typeof(MozWebSocket) !== 'undefined') {\n", + " return MozWebSocket;\n", + " } else {\n", + " alert('Your browser does not have WebSocket support.' +\n", + " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", + " 'Firefox 4 and 5 are also supported but you ' +\n", + " 'have to enable WebSockets in about:config.');\n", + " };\n", + "}\n", + "\n", + "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", + " this.id = figure_id;\n", + "\n", + " this.ws = websocket;\n", + "\n", + " this.supports_binary = (this.ws.binaryType != undefined);\n", + "\n", + " if (!this.supports_binary) {\n", + " var warnings = document.getElementById(\"mpl-warnings\");\n", + " if (warnings) {\n", + " warnings.style.display = 'block';\n", + " warnings.textContent = (\n", + " \"This browser does not support binary websocket messages. \" +\n", + " \"Performance may be slow.\");\n", + " }\n", + " }\n", + "\n", + " this.imageObj = new Image();\n", + "\n", + " this.context = undefined;\n", + " this.message = undefined;\n", + " this.canvas = undefined;\n", + " this.rubberband_canvas = undefined;\n", + " this.rubberband_context = undefined;\n", + " this.format_dropdown = undefined;\n", + "\n", + " this.image_mode = 'full';\n", + "\n", + " this.root = $('
');\n", + " this._root_extra_style(this.root)\n", + " this.root.attr('style', 'display: inline-block');\n", + "\n", + " $(parent_element).append(this.root);\n", + "\n", + " this._init_header(this);\n", + " this._init_canvas(this);\n", + " this._init_toolbar(this);\n", + "\n", + " var fig = this;\n", + "\n", + " this.waiting = false;\n", + "\n", + " this.ws.onopen = function () {\n", + " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", + " fig.send_message(\"send_image_mode\", {});\n", + " if (mpl.ratio != 1) {\n", + " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n", + " }\n", + " fig.send_message(\"refresh\", {});\n", + " }\n", + "\n", + " this.imageObj.onload = function() {\n", + " if (fig.image_mode == 'full') {\n", + " // Full images could contain transparency (where diff images\n", + " // almost always do), so we need to clear the canvas so that\n", + " // there is no ghosting.\n", + " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", + " }\n", + " fig.context.drawImage(fig.imageObj, 0, 0);\n", + " };\n", + "\n", + " this.imageObj.onunload = function() {\n", + " this.ws.close();\n", + " }\n", + "\n", + " this.ws.onmessage = this._make_on_message_function(this);\n", + "\n", + " this.ondownload = ondownload;\n", + "}\n", + "\n", + "mpl.figure.prototype._init_header = function() {\n", + " var titlebar = $(\n", + " '
');\n", + " var titletext = $(\n", + " '
');\n", + " titlebar.append(titletext)\n", + " this.root.append(titlebar);\n", + " this.header = titletext[0];\n", + "}\n", + "\n", + "\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._init_canvas = function() {\n", + " var fig = this;\n", + "\n", + " var canvas_div = $('
');\n", + "\n", + " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", + "\n", + " function canvas_keyboard_event(event) {\n", + " return fig.key_event(event, event['data']);\n", + " }\n", + "\n", + " canvas_div.keydown('key_press', canvas_keyboard_event);\n", + " canvas_div.keyup('key_release', canvas_keyboard_event);\n", + " this.canvas_div = canvas_div\n", + " this._canvas_extra_style(canvas_div)\n", + " this.root.append(canvas_div);\n", + "\n", + " var canvas = $('');\n", + " canvas.addClass('mpl-canvas');\n", + " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", + "\n", + " this.canvas = canvas[0];\n", + " this.context = canvas[0].getContext(\"2d\");\n", + "\n", + " var backingStore = this.context.backingStorePixelRatio ||\n", + "\tthis.context.webkitBackingStorePixelRatio ||\n", + "\tthis.context.mozBackingStorePixelRatio ||\n", + "\tthis.context.msBackingStorePixelRatio ||\n", + "\tthis.context.oBackingStorePixelRatio ||\n", + "\tthis.context.backingStorePixelRatio || 1;\n", + "\n", + " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n", + "\n", + " var rubberband = $('');\n", + " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", + "\n", + " var pass_mouse_events = true;\n", + "\n", + " canvas_div.resizable({\n", + " start: function(event, ui) {\n", + " pass_mouse_events = false;\n", + " },\n", + " resize: function(event, ui) {\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " stop: function(event, ui) {\n", + " pass_mouse_events = true;\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " });\n", + "\n", + " function mouse_event_fn(event) {\n", + " if (pass_mouse_events)\n", + " return fig.mouse_event(event, event['data']);\n", + " }\n", + "\n", + " rubberband.mousedown('button_press', mouse_event_fn);\n", + " rubberband.mouseup('button_release', mouse_event_fn);\n", + " // Throttle sequential mouse events to 1 every 20ms.\n", + " rubberband.mousemove('motion_notify', mouse_event_fn);\n", + "\n", + " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", + " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", + "\n", + " canvas_div.on(\"wheel\", function (event) {\n", + " event = event.originalEvent;\n", + " event['data'] = 'scroll'\n", + " if (event.deltaY < 0) {\n", + " event.step = 1;\n", + " } else {\n", + " event.step = -1;\n", + " }\n", + " mouse_event_fn(event);\n", + " });\n", + "\n", + " canvas_div.append(canvas);\n", + " canvas_div.append(rubberband);\n", + "\n", + " this.rubberband = rubberband;\n", + " this.rubberband_canvas = rubberband[0];\n", + " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", + " this.rubberband_context.strokeStyle = \"#000000\";\n", + "\n", + " this._resize_canvas = function(width, height) {\n", + " // Keep the size of the canvas, canvas container, and rubber band\n", + " // canvas in synch.\n", + " canvas_div.css('width', width)\n", + " canvas_div.css('height', height)\n", + "\n", + " canvas.attr('width', width * mpl.ratio);\n", + " canvas.attr('height', height * mpl.ratio);\n", + " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n", + "\n", + " rubberband.attr('width', width);\n", + " rubberband.attr('height', height);\n", + " }\n", + "\n", + " // Set the figure to an initial 600x600px, this will subsequently be updated\n", + " // upon first draw.\n", + " this._resize_canvas(600, 600);\n", + "\n", + " // Disable right mouse context menu.\n", + " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", + " return false;\n", + " });\n", + "\n", + " function set_focus () {\n", + " canvas.focus();\n", + " canvas_div.focus();\n", + " }\n", + "\n", + " window.setTimeout(set_focus, 100);\n", + "}\n", + "\n", + "mpl.figure.prototype._init_toolbar = function() {\n", + " var fig = this;\n", + "\n", + " var nav_element = $('
')\n", + " nav_element.attr('style', 'width: 100%');\n", + " this.root.append(nav_element);\n", + "\n", + " // Define a callback function for later on.\n", + " function toolbar_event(event) {\n", + " return fig.toolbar_button_onclick(event['data']);\n", + " }\n", + " function toolbar_mouse_event(event) {\n", + " return fig.toolbar_button_onmouseover(event['data']);\n", + " }\n", + "\n", + " for(var toolbar_ind in mpl.toolbar_items) {\n", + " var name = mpl.toolbar_items[toolbar_ind][0];\n", + " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", + " var image = mpl.toolbar_items[toolbar_ind][2];\n", + " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", + "\n", + " if (!name) {\n", + " // put a spacer in here.\n", + " continue;\n", + " }\n", + " var button = $('');\n", + " button.click(method_name, toolbar_event);\n", + " button.mouseover(tooltip, toolbar_mouse_event);\n", + " nav_element.append(button);\n", + " }\n", + "\n", + " // Add the status bar.\n", + " var status_bar = $('');\n", + " nav_element.append(status_bar);\n", + " this.message = status_bar[0];\n", + "\n", + " // Add the close button to the window.\n", + " var buttongrp = $('
');\n", + " var button = $('');\n", + " button.click(function (evt) { fig.handle_close(fig, {}); } );\n", + " button.mouseover('Stop Interaction', toolbar_mouse_event);\n", + " buttongrp.append(button);\n", + " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n", + " titlebar.prepend(buttongrp);\n", + "}\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(el){\n", + " var fig = this\n", + " el.on(\"remove\", function(){\n", + "\tfig.close_ws(fig, {});\n", + " });\n", + "}\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(el){\n", + " // this is important to make the div 'focusable\n", + " el.attr('tabindex', 0)\n", + " // reach out to IPython and tell the keyboard manager to turn it's self\n", + " // off when our div gets focus\n", + "\n", + " // location in version 3\n", + " if (IPython.notebook.keyboard_manager) {\n", + " IPython.notebook.keyboard_manager.register_events(el);\n", + " }\n", + " else {\n", + " // location in version 2\n", + " IPython.keyboard_manager.register_events(el);\n", + " }\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._key_event_extra = function(event, name) {\n", + " var manager = IPython.notebook.keyboard_manager;\n", + " if (!manager)\n", + " manager = IPython.keyboard_manager;\n", + "\n", + " // Check for shift+enter\n", + " if (event.shiftKey && event.which == 13) {\n", + " this.canvas_div.blur();\n", + " // select the cell after this one\n", + " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", + " IPython.notebook.select(index + 1);\n", + " }\n", + "}\n", + "\n", + "mpl.figure.prototype.handle_save = function(fig, msg) {\n", + " fig.ondownload(fig, null);\n", + "}\n", + "\n", + "\n", + "mpl.find_output_cell = function(html_output) {\n", + " // Return the cell and output element which can be found *uniquely* in the notebook.\n", + " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", + " // IPython event is triggered only after the cells have been serialised, which for\n", + " // our purposes (turning an active figure into a static one), is too late.\n", + " var cells = IPython.notebook.get_cells();\n", + " var ncells = cells.length;\n", + " for (var i=0; i= 3 moved mimebundle to data attribute of output\n", + " data = data.data;\n", + " }\n", + " if (data['text/html'] == html_output) {\n", + " return [cell, data, j];\n", + " }\n", + " }\n", + " }\n", + " }\n", + "}\n", + "\n", + "// Register the function which deals with the matplotlib target/channel.\n", + "// The kernel may be null if the page has been refreshed.\n", + "if (IPython.notebook.kernel != null) {\n", + " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", + "}\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "newfig()\n", "plot(xs, label='x')\n", @@ -310,7 +1206,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 21, "metadata": { "collapsed": true }, @@ -322,9 +1218,799 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 22, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "application/javascript": [ + "/* Put everything inside the global mpl namespace */\n", + "window.mpl = {};\n", + "\n", + "\n", + "mpl.get_websocket_type = function() {\n", + " if (typeof(WebSocket) !== 'undefined') {\n", + " return WebSocket;\n", + " } else if (typeof(MozWebSocket) !== 'undefined') {\n", + " return MozWebSocket;\n", + " } else {\n", + " alert('Your browser does not have WebSocket support.' +\n", + " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", + " 'Firefox 4 and 5 are also supported but you ' +\n", + " 'have to enable WebSockets in about:config.');\n", + " };\n", + "}\n", + "\n", + "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", + " this.id = figure_id;\n", + "\n", + " this.ws = websocket;\n", + "\n", + " this.supports_binary = (this.ws.binaryType != undefined);\n", + "\n", + " if (!this.supports_binary) {\n", + " var warnings = document.getElementById(\"mpl-warnings\");\n", + " if (warnings) {\n", + " warnings.style.display = 'block';\n", + " warnings.textContent = (\n", + " \"This browser does not support binary websocket messages. \" +\n", + " \"Performance may be slow.\");\n", + " }\n", + " }\n", + "\n", + " this.imageObj = new Image();\n", + "\n", + " this.context = undefined;\n", + " this.message = undefined;\n", + " this.canvas = undefined;\n", + " this.rubberband_canvas = undefined;\n", + " this.rubberband_context = undefined;\n", + " this.format_dropdown = undefined;\n", + "\n", + " this.image_mode = 'full';\n", + "\n", + " this.root = $('
');\n", + " this._root_extra_style(this.root)\n", + " this.root.attr('style', 'display: inline-block');\n", + "\n", + " $(parent_element).append(this.root);\n", + "\n", + " this._init_header(this);\n", + " this._init_canvas(this);\n", + " this._init_toolbar(this);\n", + "\n", + " var fig = this;\n", + "\n", + " this.waiting = false;\n", + "\n", + " this.ws.onopen = function () {\n", + " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", + " fig.send_message(\"send_image_mode\", {});\n", + " if (mpl.ratio != 1) {\n", + " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n", + " }\n", + " fig.send_message(\"refresh\", {});\n", + " }\n", + "\n", + " this.imageObj.onload = function() {\n", + " if (fig.image_mode == 'full') {\n", + " // Full images could contain transparency (where diff images\n", + " // almost always do), so we need to clear the canvas so that\n", + " // there is no ghosting.\n", + " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", + " }\n", + " fig.context.drawImage(fig.imageObj, 0, 0);\n", + " };\n", + "\n", + " this.imageObj.onunload = function() {\n", + " this.ws.close();\n", + " }\n", + "\n", + " this.ws.onmessage = this._make_on_message_function(this);\n", + "\n", + " this.ondownload = ondownload;\n", + "}\n", + "\n", + "mpl.figure.prototype._init_header = function() {\n", + " var titlebar = $(\n", + " '
');\n", + " var titletext = $(\n", + " '
');\n", + " titlebar.append(titletext)\n", + " this.root.append(titlebar);\n", + " this.header = titletext[0];\n", + "}\n", + "\n", + "\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._init_canvas = function() {\n", + " var fig = this;\n", + "\n", + " var canvas_div = $('
');\n", + "\n", + " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", + "\n", + " function canvas_keyboard_event(event) {\n", + " return fig.key_event(event, event['data']);\n", + " }\n", + "\n", + " canvas_div.keydown('key_press', canvas_keyboard_event);\n", + " canvas_div.keyup('key_release', canvas_keyboard_event);\n", + " this.canvas_div = canvas_div\n", + " this._canvas_extra_style(canvas_div)\n", + " this.root.append(canvas_div);\n", + "\n", + " var canvas = $('');\n", + " canvas.addClass('mpl-canvas');\n", + " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", + "\n", + " this.canvas = canvas[0];\n", + " this.context = canvas[0].getContext(\"2d\");\n", + "\n", + " var backingStore = this.context.backingStorePixelRatio ||\n", + "\tthis.context.webkitBackingStorePixelRatio ||\n", + "\tthis.context.mozBackingStorePixelRatio ||\n", + "\tthis.context.msBackingStorePixelRatio ||\n", + "\tthis.context.oBackingStorePixelRatio ||\n", + "\tthis.context.backingStorePixelRatio || 1;\n", + "\n", + " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n", + "\n", + " var rubberband = $('');\n", + " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", + "\n", + " var pass_mouse_events = true;\n", + "\n", + " canvas_div.resizable({\n", + " start: function(event, ui) {\n", + " pass_mouse_events = false;\n", + " },\n", + " resize: function(event, ui) {\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " stop: function(event, ui) {\n", + " pass_mouse_events = true;\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " });\n", + "\n", + " function mouse_event_fn(event) {\n", + " if (pass_mouse_events)\n", + " return fig.mouse_event(event, event['data']);\n", + " }\n", + "\n", + " rubberband.mousedown('button_press', mouse_event_fn);\n", + " rubberband.mouseup('button_release', mouse_event_fn);\n", + " // Throttle sequential mouse events to 1 every 20ms.\n", + " rubberband.mousemove('motion_notify', mouse_event_fn);\n", + "\n", + " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", + " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", + "\n", + " canvas_div.on(\"wheel\", function (event) {\n", + " event = event.originalEvent;\n", + " event['data'] = 'scroll'\n", + " if (event.deltaY < 0) {\n", + " event.step = 1;\n", + " } else {\n", + " event.step = -1;\n", + " }\n", + " mouse_event_fn(event);\n", + " });\n", + "\n", + " canvas_div.append(canvas);\n", + " canvas_div.append(rubberband);\n", + "\n", + " this.rubberband = rubberband;\n", + " this.rubberband_canvas = rubberband[0];\n", + " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", + " this.rubberband_context.strokeStyle = \"#000000\";\n", + "\n", + " this._resize_canvas = function(width, height) {\n", + " // Keep the size of the canvas, canvas container, and rubber band\n", + " // canvas in synch.\n", + " canvas_div.css('width', width)\n", + " canvas_div.css('height', height)\n", + "\n", + " canvas.attr('width', width * mpl.ratio);\n", + " canvas.attr('height', height * mpl.ratio);\n", + " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n", + "\n", + " rubberband.attr('width', width);\n", + " rubberband.attr('height', height);\n", + " }\n", + "\n", + " // Set the figure to an initial 600x600px, this will subsequently be updated\n", + " // upon first draw.\n", + " this._resize_canvas(600, 600);\n", + "\n", + " // Disable right mouse context menu.\n", + " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", + " return false;\n", + " });\n", + "\n", + " function set_focus () {\n", + " canvas.focus();\n", + " canvas_div.focus();\n", + " }\n", + "\n", + " window.setTimeout(set_focus, 100);\n", + "}\n", + "\n", + "mpl.figure.prototype._init_toolbar = function() {\n", + " var fig = this;\n", + "\n", + " var nav_element = $('
')\n", + " nav_element.attr('style', 'width: 100%');\n", + " this.root.append(nav_element);\n", + "\n", + " // Define a callback function for later on.\n", + " function toolbar_event(event) {\n", + " return fig.toolbar_button_onclick(event['data']);\n", + " }\n", + " function toolbar_mouse_event(event) {\n", + " return fig.toolbar_button_onmouseover(event['data']);\n", + " }\n", + "\n", + " for(var toolbar_ind in mpl.toolbar_items) {\n", + " var name = mpl.toolbar_items[toolbar_ind][0];\n", + " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", + " var image = mpl.toolbar_items[toolbar_ind][2];\n", + " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", + "\n", + " if (!name) {\n", + " // put a spacer in here.\n", + " continue;\n", + " }\n", + " var button = $('');\n", + " button.click(method_name, toolbar_event);\n", + " button.mouseover(tooltip, toolbar_mouse_event);\n", + " nav_element.append(button);\n", + " }\n", + "\n", + " // Add the status bar.\n", + " var status_bar = $('');\n", + " nav_element.append(status_bar);\n", + " this.message = status_bar[0];\n", + "\n", + " // Add the close button to the window.\n", + " var buttongrp = $('
');\n", + " var button = $('');\n", + " button.click(function (evt) { fig.handle_close(fig, {}); } );\n", + " button.mouseover('Stop Interaction', toolbar_mouse_event);\n", + " buttongrp.append(button);\n", + " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n", + " titlebar.prepend(buttongrp);\n", + "}\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(el){\n", + " var fig = this\n", + " el.on(\"remove\", function(){\n", + "\tfig.close_ws(fig, {});\n", + " });\n", + "}\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(el){\n", + " // this is important to make the div 'focusable\n", + " el.attr('tabindex', 0)\n", + " // reach out to IPython and tell the keyboard manager to turn it's self\n", + " // off when our div gets focus\n", + "\n", + " // location in version 3\n", + " if (IPython.notebook.keyboard_manager) {\n", + " IPython.notebook.keyboard_manager.register_events(el);\n", + " }\n", + " else {\n", + " // location in version 2\n", + " IPython.keyboard_manager.register_events(el);\n", + " }\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._key_event_extra = function(event, name) {\n", + " var manager = IPython.notebook.keyboard_manager;\n", + " if (!manager)\n", + " manager = IPython.keyboard_manager;\n", + "\n", + " // Check for shift+enter\n", + " if (event.shiftKey && event.which == 13) {\n", + " this.canvas_div.blur();\n", + " // select the cell after this one\n", + " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", + " IPython.notebook.select(index + 1);\n", + " }\n", + "}\n", + "\n", + "mpl.figure.prototype.handle_save = function(fig, msg) {\n", + " fig.ondownload(fig, null);\n", + "}\n", + "\n", + "\n", + "mpl.find_output_cell = function(html_output) {\n", + " // Return the cell and output element which can be found *uniquely* in the notebook.\n", + " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", + " // IPython event is triggered only after the cells have been serialised, which for\n", + " // our purposes (turning an active figure into a static one), is too late.\n", + " var cells = IPython.notebook.get_cells();\n", + " var ncells = cells.length;\n", + " for (var i=0; i= 3 moved mimebundle to data attribute of output\n", + " data = data.data;\n", + " }\n", + " if (data['text/html'] == html_output) {\n", + " return [cell, data, j];\n", + " }\n", + " }\n", + " }\n", + " }\n", + "}\n", + "\n", + "// Register the function which deals with the matplotlib target/channel.\n", + "// The kernel may be null if the page has been refreshed.\n", + "if (IPython.notebook.kernel != null) {\n", + " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", + "}\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "newfig()\n", "plot(xs, ys, label='trajectory')\n", @@ -363,11 +2839,801 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 30, "metadata": { "scrolled": false }, - "outputs": [], + "outputs": [ + { + "data": { + "application/javascript": [ + "/* Put everything inside the global mpl namespace */\n", + "window.mpl = {};\n", + "\n", + "\n", + "mpl.get_websocket_type = function() {\n", + " if (typeof(WebSocket) !== 'undefined') {\n", + " return WebSocket;\n", + " } else if (typeof(MozWebSocket) !== 'undefined') {\n", + " return MozWebSocket;\n", + " } else {\n", + " alert('Your browser does not have WebSocket support.' +\n", + " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", + " 'Firefox 4 and 5 are also supported but you ' +\n", + " 'have to enable WebSockets in about:config.');\n", + " };\n", + "}\n", + "\n", + "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", + " this.id = figure_id;\n", + "\n", + " this.ws = websocket;\n", + "\n", + " this.supports_binary = (this.ws.binaryType != undefined);\n", + "\n", + " if (!this.supports_binary) {\n", + " var warnings = document.getElementById(\"mpl-warnings\");\n", + " if (warnings) {\n", + " warnings.style.display = 'block';\n", + " warnings.textContent = (\n", + " \"This browser does not support binary websocket messages. \" +\n", + " \"Performance may be slow.\");\n", + " }\n", + " }\n", + "\n", + " this.imageObj = new Image();\n", + "\n", + " this.context = undefined;\n", + " this.message = undefined;\n", + " this.canvas = undefined;\n", + " this.rubberband_canvas = undefined;\n", + " this.rubberband_context = undefined;\n", + " this.format_dropdown = undefined;\n", + "\n", + " this.image_mode = 'full';\n", + "\n", + " this.root = $('
');\n", + " this._root_extra_style(this.root)\n", + " this.root.attr('style', 'display: inline-block');\n", + "\n", + " $(parent_element).append(this.root);\n", + "\n", + " this._init_header(this);\n", + " this._init_canvas(this);\n", + " this._init_toolbar(this);\n", + "\n", + " var fig = this;\n", + "\n", + " this.waiting = false;\n", + "\n", + " this.ws.onopen = function () {\n", + " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", + " fig.send_message(\"send_image_mode\", {});\n", + " if (mpl.ratio != 1) {\n", + " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n", + " }\n", + " fig.send_message(\"refresh\", {});\n", + " }\n", + "\n", + " this.imageObj.onload = function() {\n", + " if (fig.image_mode == 'full') {\n", + " // Full images could contain transparency (where diff images\n", + " // almost always do), so we need to clear the canvas so that\n", + " // there is no ghosting.\n", + " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", + " }\n", + " fig.context.drawImage(fig.imageObj, 0, 0);\n", + " };\n", + "\n", + " this.imageObj.onunload = function() {\n", + " this.ws.close();\n", + " }\n", + "\n", + " this.ws.onmessage = this._make_on_message_function(this);\n", + "\n", + " this.ondownload = ondownload;\n", + "}\n", + "\n", + "mpl.figure.prototype._init_header = function() {\n", + " var titlebar = $(\n", + " '
');\n", + " var titletext = $(\n", + " '
');\n", + " titlebar.append(titletext)\n", + " this.root.append(titlebar);\n", + " this.header = titletext[0];\n", + "}\n", + "\n", + "\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._init_canvas = function() {\n", + " var fig = this;\n", + "\n", + " var canvas_div = $('
');\n", + "\n", + " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", + "\n", + " function canvas_keyboard_event(event) {\n", + " return fig.key_event(event, event['data']);\n", + " }\n", + "\n", + " canvas_div.keydown('key_press', canvas_keyboard_event);\n", + " canvas_div.keyup('key_release', canvas_keyboard_event);\n", + " this.canvas_div = canvas_div\n", + " this._canvas_extra_style(canvas_div)\n", + " this.root.append(canvas_div);\n", + "\n", + " var canvas = $('');\n", + " canvas.addClass('mpl-canvas');\n", + " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", + "\n", + " this.canvas = canvas[0];\n", + " this.context = canvas[0].getContext(\"2d\");\n", + "\n", + " var backingStore = this.context.backingStorePixelRatio ||\n", + "\tthis.context.webkitBackingStorePixelRatio ||\n", + "\tthis.context.mozBackingStorePixelRatio ||\n", + "\tthis.context.msBackingStorePixelRatio ||\n", + "\tthis.context.oBackingStorePixelRatio ||\n", + "\tthis.context.backingStorePixelRatio || 1;\n", + "\n", + " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n", + "\n", + " var rubberband = $('');\n", + " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", + "\n", + " var pass_mouse_events = true;\n", + "\n", + " canvas_div.resizable({\n", + " start: function(event, ui) {\n", + " pass_mouse_events = false;\n", + " },\n", + " resize: function(event, ui) {\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " stop: function(event, ui) {\n", + " pass_mouse_events = true;\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " });\n", + "\n", + " function mouse_event_fn(event) {\n", + " if (pass_mouse_events)\n", + " return fig.mouse_event(event, event['data']);\n", + " }\n", + "\n", + " rubberband.mousedown('button_press', mouse_event_fn);\n", + " rubberband.mouseup('button_release', mouse_event_fn);\n", + " // Throttle sequential mouse events to 1 every 20ms.\n", + " rubberband.mousemove('motion_notify', mouse_event_fn);\n", + "\n", + " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", + " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", + "\n", + " canvas_div.on(\"wheel\", function (event) {\n", + " event = event.originalEvent;\n", + " event['data'] = 'scroll'\n", + " if (event.deltaY < 0) {\n", + " event.step = 1;\n", + " } else {\n", + " event.step = -1;\n", + " }\n", + " mouse_event_fn(event);\n", + " });\n", + "\n", + " canvas_div.append(canvas);\n", + " canvas_div.append(rubberband);\n", + "\n", + " this.rubberband = rubberband;\n", + " this.rubberband_canvas = rubberband[0];\n", + " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", + " this.rubberband_context.strokeStyle = \"#000000\";\n", + "\n", + " this._resize_canvas = function(width, height) {\n", + " // Keep the size of the canvas, canvas container, and rubber band\n", + " // canvas in synch.\n", + " canvas_div.css('width', width)\n", + " canvas_div.css('height', height)\n", + "\n", + " canvas.attr('width', width * mpl.ratio);\n", + " canvas.attr('height', height * mpl.ratio);\n", + " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n", + "\n", + " rubberband.attr('width', width);\n", + " rubberband.attr('height', height);\n", + " }\n", + "\n", + " // Set the figure to an initial 600x600px, this will subsequently be updated\n", + " // upon first draw.\n", + " this._resize_canvas(600, 600);\n", + "\n", + " // Disable right mouse context menu.\n", + " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", + " return false;\n", + " });\n", + "\n", + " function set_focus () {\n", + " canvas.focus();\n", + " canvas_div.focus();\n", + " }\n", + "\n", + " window.setTimeout(set_focus, 100);\n", + "}\n", + "\n", + "mpl.figure.prototype._init_toolbar = function() {\n", + " var fig = this;\n", + "\n", + " var nav_element = $('
')\n", + " nav_element.attr('style', 'width: 100%');\n", + " this.root.append(nav_element);\n", + "\n", + " // Define a callback function for later on.\n", + " function toolbar_event(event) {\n", + " return fig.toolbar_button_onclick(event['data']);\n", + " }\n", + " function toolbar_mouse_event(event) {\n", + " return fig.toolbar_button_onmouseover(event['data']);\n", + " }\n", + "\n", + " for(var toolbar_ind in mpl.toolbar_items) {\n", + " var name = mpl.toolbar_items[toolbar_ind][0];\n", + " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", + " var image = mpl.toolbar_items[toolbar_ind][2];\n", + " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", + "\n", + " if (!name) {\n", + " // put a spacer in here.\n", + " continue;\n", + " }\n", + " var button = $('');\n", + " button.click(method_name, toolbar_event);\n", + " button.mouseover(tooltip, toolbar_mouse_event);\n", + " nav_element.append(button);\n", + " }\n", + "\n", + " // Add the status bar.\n", + " var status_bar = $('');\n", + " nav_element.append(status_bar);\n", + " this.message = status_bar[0];\n", + "\n", + " // Add the close button to the window.\n", + " var buttongrp = $('
');\n", + " var button = $('');\n", + " button.click(function (evt) { fig.handle_close(fig, {}); } );\n", + " button.mouseover('Stop Interaction', toolbar_mouse_event);\n", + " buttongrp.append(button);\n", + " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n", + " titlebar.prepend(buttongrp);\n", + "}\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(el){\n", + " var fig = this\n", + " el.on(\"remove\", function(){\n", + "\tfig.close_ws(fig, {});\n", + " });\n", + "}\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(el){\n", + " // this is important to make the div 'focusable\n", + " el.attr('tabindex', 0)\n", + " // reach out to IPython and tell the keyboard manager to turn it's self\n", + " // off when our div gets focus\n", + "\n", + " // location in version 3\n", + " if (IPython.notebook.keyboard_manager) {\n", + " IPython.notebook.keyboard_manager.register_events(el);\n", + " }\n", + " else {\n", + " // location in version 2\n", + " IPython.keyboard_manager.register_events(el);\n", + " }\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._key_event_extra = function(event, name) {\n", + " var manager = IPython.notebook.keyboard_manager;\n", + " if (!manager)\n", + " manager = IPython.keyboard_manager;\n", + "\n", + " // Check for shift+enter\n", + " if (event.shiftKey && event.which == 13) {\n", + " this.canvas_div.blur();\n", + " // select the cell after this one\n", + " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", + " IPython.notebook.select(index + 1);\n", + " }\n", + "}\n", + "\n", + "mpl.figure.prototype.handle_save = function(fig, msg) {\n", + " fig.ondownload(fig, null);\n", + "}\n", + "\n", + "\n", + "mpl.find_output_cell = function(html_output) {\n", + " // Return the cell and output element which can be found *uniquely* in the notebook.\n", + " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", + " // IPython event is triggered only after the cells have been serialised, which for\n", + " // our purposes (turning an active figure into a static one), is too late.\n", + " var cells = IPython.notebook.get_cells();\n", + " var ncells = cells.length;\n", + " for (var i=0; i= 3 moved mimebundle to data attribute of output\n", + " data = data.data;\n", + " }\n", + " if (data['text/html'] == html_output) {\n", + " return [cell, data, j];\n", + " }\n", + " }\n", + " }\n", + " }\n", + "}\n", + "\n", + "// Register the function which deals with the matplotlib target/channel.\n", + "// The kernel may be null if the page has been refreshed.\n", + "if (IPython.notebook.kernel != null) {\n", + " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", + "}\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "animate2d(system.results.x, system.results.y)" ]