the ABSeas- altair, bokeh and seaborn

Posted on Sat 15 April 2017 in Projects

In JupyterLab locally, everything is interactive

(static site generator Pelican disables interactivity once this post is pushed to Github :( )

Altair is cool and all, but damn that's a lot of lines. Kind of prefer matplotlib, but I guess interactivity comes at a cost.

In [42]:
import pandas as pd
import numpy as np
from bokeh.models import GMapPlot, GMapOptions, ColumnDataSource, Circle, Range1d, PanTool, WheelZoomTool, ResetTool, SaveTool
from bokeh.plotting import figure, output_file, show
from bokeh.io import show, output_notebook
from bokeh.embed import file_html
output_notebook()
import altair as alt
import seaborn as sns
import matplotlib.pyplot as plt
Loading BokehJS ...
In [43]:
df_lap1 = pd.read_csv('unpublished/zipped_csv/saita_natTT_lap1.csv')
df_lap2 = pd.read_csv('unpublished/zipped_csv/saita_natTT_lap2.csv')
df_lap3 = pd.read_csv('unpublished/zipped_csv/saita_natTT_lap3.csv')

frames = [df_lap1, df_lap2, df_lap3]
df_all = pd.concat(frames, keys=['lap1','lap2','lap3'])
In [44]:
df_lap3.head()
Out[44]:
elapsed_time distance latitude longitude altitude l_r_balance power cadence speed heartrate ... leg_range_log_left leg_range_log_right pedaling_delay_log_left pedaling_delay_log_right waist_angle_log_center waist_d_rot_y_center waist_d_rot_z_center torso_angle_log_center torso_d_rot_y_center torso_d_rot_z_center
0 2158 25599.0 36.985397 136.79150 47 NaN 341 87 12.74 NaN ... NaN NaN 9.4 7.5 49.3 9.2 4.5 11.8 7.3 8.4
1 2159 25616.0 36.985508 136.79149 47 NaN 331 87 12.72 NaN ... NaN NaN 4.8 3.6 47.5 8.1 5.2 11.1 7.7 8.7
2 2160 25624.0 36.985620 136.79144 47 NaN 299 87 12.67 NaN ... NaN NaN 30.7 46.0 44.9 6.6 4.3 10.5 7.1 8.7
3 2161 25637.0 36.985725 136.79141 47 NaN 297 87 12.72 NaN ... NaN NaN 30.7 18.2 48.2 7.3 5.0 10.0 7.9 6.7
4 2162 25649.0 36.985847 136.79140 47 NaN 376 87 12.79 NaN ... NaN NaN 26.1 47.5 49.5 6.2 5.5 12.8 7.2 6.0

5 rows × 24 columns

In [45]:
df_all.loc['lap1'].head()
Out[45]:
elapsed_time distance latitude longitude altitude l_r_balance power cadence speed heartrate ... leg_range_log_left leg_range_log_right pedaling_delay_log_left pedaling_delay_log_right waist_angle_log_center waist_d_rot_y_center waist_d_rot_z_center torso_angle_log_center torso_d_rot_y_center torso_d_rot_z_center
0 2 NaN 36.985600 136.79163 41 NaN NaN NaN 0.00 NaN ... NaN NaN NaN NaN 57.9 3.2 0.7 28.0 2.0 2.2
1 3 0.0 36.985603 136.79161 41 NaN NaN NaN 0.00 NaN ... NaN NaN NaN NaN 52.1 6.8 2.0 19.8 1.4 1.7
2 4 NaN 36.985607 136.79160 41 NaN NaN NaN 0.01 NaN ... NaN NaN NaN NaN 49.3 4.6 2.7 18.2 1.0 2.7
3 5 3.0 36.985622 136.79156 41 NaN NaN NaN 4.09 NaN ... NaN NaN NaN NaN 54.7 8.3 4.6 20.9 4.4 10.1
4 6 7.0 36.985695 136.79149 41 NaN 462.0 32.0 5.56 NaN ... NaN NaN 7.2 7.5 54.4 24.1 7.6 21.2 4.1 14.4

5 rows × 24 columns

In [36]:
data = df_all
In [37]:
data.loc['lap3'].reset_index().iloc[2:].head()
Out[37]:
index elapsed_time distance latitude longitude altitude l_r_balance power cadence speed ... leg_range_log_left leg_range_log_right pedaling_delay_log_left pedaling_delay_log_right waist_angle_log_center waist_d_rot_y_center waist_d_rot_z_center torso_angle_log_center torso_d_rot_y_center torso_d_rot_z_center
2 2 2160 25624.0 36.985620 136.79144 47 NaN 299.0 87.0 12.67 ... NaN NaN 30.7 46.0 44.9 6.6 4.3 10.5 7.1 8.7
3 3 2161 25637.0 36.985725 136.79141 47 NaN 297.0 87.0 12.72 ... NaN NaN 30.7 18.2 48.2 7.3 5.0 10.0 7.9 6.7
4 4 2162 25649.0 36.985847 136.79140 47 NaN 376.0 87.0 12.79 ... NaN NaN 26.1 47.5 49.5 6.2 5.5 12.8 7.2 6.0
5 5 2163 25662.0 36.985970 136.79137 47 NaN 397.0 88.0 12.85 ... NaN NaN 26.9 18.5 50.1 5.7 5.5 12.1 7.1 7.0
6 6 2164 25674.0 36.986084 136.79135 47 NaN 376.0 88.0 12.88 ... NaN NaN 41.0 36.8 49.2 8.6 6.7 11.1 6.8 8.7

5 rows × 25 columns

In [38]:
mid_lat = data['latitude'].min()+((data['latitude'].max()-data['latitude'].min())/2)
mid_lon = data['longitude'].min()+((data['longitude'].max()-data['longitude'].min())/2)
    
map_options = GMapOptions(lat=mid_lat, lng=mid_lon, map_type="roadmap", zoom=13)
activitymap = GMapPlot(x_range=Range1d(), y_range=Range1d(), map_options=map_options)
activitymap.api_key = "AIzaSyBcIU6DrIyKGVxKJHbL8lgm0YMyj7UEAvU"
source = ColumnDataSource(data=data)
circle = Circle(x="longitude", y="latitude", size=3)
activitymap.add_glyph(source, circle)
activitymap.add_tools(PanTool(), WheelZoomTool(), ResetTool(), SaveTool())

output_file("example.html")
In [39]:
show(activitymap)
.. raw:: html :file: ../../output/posts/altair-bokeh-seaborn/example.html
In [10]:
data.loc['lap1'].describe()
Out[10]:
elapsed_time distance latitude longitude altitude l_r_balance power cadence speed heartrate ... leg_range_log_left leg_range_log_right pedaling_delay_log_left pedaling_delay_log_right waist_angle_log_center waist_d_rot_y_center waist_d_rot_z_center torso_angle_log_center torso_d_rot_y_center torso_d_rot_z_center
count 1089.000000 1084.000000 1029.000000 1029.000000 1089.000000 0.0 1085.000000 1085.000000 1089.000000 0.0 ... 0.0 0.0 1053.000000 1052.000000 1089.000000 1089.000000 1089.000000 1089.000000 1089.000000 1089.000000
mean 546.000000 6334.341328 36.972665 136.786747 56.335170 NaN 317.294009 90.710599 11.788586 NaN ... NaN NaN 26.319943 26.667110 47.528099 7.521579 6.352617 12.239853 5.769054 6.750964
std 314.511526 3645.353290 0.013729 0.004625 9.786539 NaN 78.066683 14.369887 2.288189 NaN ... NaN NaN 10.833275 12.244778 2.794049 3.895105 2.023782 4.152572 2.154695 1.788248
min 2.000000 0.000000 36.953403 136.774750 41.000000 NaN 0.000000 0.000000 0.000000 NaN ... NaN NaN 0.000000 0.000000 40.800000 0.800000 0.600000 5.000000 1.000000 0.400000
25% 274.000000 3300.750000 36.958946 136.783370 47.000000 NaN 296.000000 89.000000 10.850000 NaN ... NaN NaN 19.300000 19.275000 46.100000 5.900000 5.300000 9.900000 4.000000 5.800000
50% 546.000000 6242.500000 36.970646 136.787870 56.000000 NaN 326.000000 94.000000 12.270000 NaN ... NaN NaN 28.500000 29.700000 47.000000 7.000000 6.200000 11.200000 5.700000 6.700000
75% 818.000000 9398.000000 36.984734 136.790560 65.000000 NaN 354.000000 97.000000 12.900000 NaN ... NaN NaN 33.800000 35.300000 48.600000 8.000000 7.300000 13.000000 7.300000 7.600000
max 1090.000000 12820.000000 36.998150 136.793520 73.000000 NaN 606.000000 110.000000 17.520000 NaN ... NaN NaN 48.700000 51.200000 66.100000 30.600000 13.900000 36.800000 11.500000 14.400000

8 rows × 24 columns

In [11]:
data.drop(['l_r_balance','heartrate','leg_range_log_left','leg_range_log_right'], axis=1).corr(method='pearson').style.background_gradient(cmap='bwr').set_precision(2)
Out[11]:
elapsed_time distance latitude longitude altitude power cadence speed ankling_log_left ankling_log_right foot_range_log_left foot_range_log_right pedaling_delay_log_left pedaling_delay_log_right waist_angle_log_center waist_d_rot_y_center waist_d_rot_z_center torso_angle_log_center torso_d_rot_y_center torso_d_rot_z_center
elapsed_time 1 1 -0.2 0.027 0.14 0.036 -0.083 0.087 0.029 -0.017 -0.28 -0.066 -0.041 -0.016 0.25 -0.029 0.065 0.08 0.12 0.34
distance 1 1 -0.19 0.03 0.13 0.036 -0.082 0.083 0.03 -0.016 -0.28 -0.065 -0.041 -0.017 0.25 -0.03 0.062 0.082 0.12 0.34
latitude -0.2 -0.19 1 0.5 -0.73 0.085 0.14 0.13 -0.047 -0.049 0.17 -0.042 0.025 0.02 -0.099 -0.1 -0.13 -0.22 -0.0086 0.058
longitude 0.027 0.03 0.5 1 -0.23 0.2 0.19 0.1 -0.069 -0.0054 0.038 -0.033 -0.023 -0.036 -0.094 -0.033 -0.091 -0.25 0.0077 0.18
altitude 0.14 0.13 -0.73 -0.23 1 -0.032 -0.1 -0.24 0.031 0.067 -0.24 -0.025 -0.062 -0.076 0.065 0.11 0.15 0.14 0.099 0.1
power 0.036 0.036 0.085 0.2 -0.032 1 0.47 -0.41 -0.27 -0.21 0.19 -0.015 -0.0045 -0.12 0.17 0.36 0.44 -0.14 0.41 0.62
cadence -0.083 -0.082 0.14 0.19 -0.1 0.47 1 0.24 -0.00017 -0.023 0.2 0.42 0.18 0.21 -0.27 -0.069 0.18 -0.46 0.13 0.14
speed 0.087 0.083 0.13 0.1 -0.24 -0.41 0.24 1 0.11 0.088 0.043 0.16 0.081 0.19 -0.48 -0.38 -0.46 -0.46 -0.38 -0.42
ankling_log_left 0.029 0.03 -0.047 -0.069 0.031 -0.27 -0.00017 0.11 1 0.13 -0.16 -0.038 -0.025 -0.004 -0.13 -0.018 -0.015 0.061 -0.095 -0.11
ankling_log_right -0.017 -0.016 -0.049 -0.0054 0.067 -0.21 -0.023 0.088 0.13 1 -0.16 0.061 -0.085 0.025 -0.15 -0.021 -0.039 -0.0097 -0.073 -0.056
foot_range_log_left -0.28 -0.28 0.17 0.038 -0.24 0.19 0.2 0.043 -0.16 -0.16 1 0.041 0.18 0.075 -0.16 -0.01 0.009 -0.31 -0.027 -0.12
foot_range_log_right -0.066 -0.065 -0.042 -0.033 -0.025 -0.015 0.42 0.16 -0.038 0.061 0.041 1 0.076 0.14 0.057 -0.28 -0.019 -0.072 0.035 -0.16
pedaling_delay_log_left -0.041 -0.041 0.025 -0.023 -0.062 -0.0045 0.18 0.081 -0.025 -0.085 0.18 0.076 1 0.11 0.0058 -0.15 -0.046 -0.089 0.02 -0.073
pedaling_delay_log_right -0.016 -0.017 0.02 -0.036 -0.076 -0.12 0.21 0.19 -0.004 0.025 0.075 0.14 0.11 1 -0.038 -0.19 -0.1 -0.09 -0.046 -0.16
waist_angle_log_center 0.25 0.25 -0.099 -0.094 0.065 0.17 -0.27 -0.48 -0.13 -0.15 -0.16 0.057 0.0058 -0.038 1 -0.2 0.022 0.61 0.33 0.16
waist_d_rot_y_center -0.029 -0.03 -0.1 -0.033 0.11 0.36 -0.069 -0.38 -0.018 -0.021 -0.01 -0.28 -0.15 -0.19 -0.2 1 0.59 0.068 -0.0062 0.34
waist_d_rot_z_center 0.065 0.062 -0.13 -0.091 0.15 0.44 0.18 -0.46 -0.015 -0.039 0.009 -0.019 -0.046 -0.1 0.022 0.59 1 0.13 0.22 0.35
torso_angle_log_center 0.08 0.082 -0.22 -0.25 0.14 -0.14 -0.46 -0.46 0.061 -0.0097 -0.31 -0.072 -0.089 -0.09 0.61 0.068 0.13 1 0.11 -0.013
torso_d_rot_y_center 0.12 0.12 -0.0086 0.0077 0.099 0.41 0.13 -0.38 -0.095 -0.073 -0.027 0.035 0.02 -0.046 0.33 -0.0062 0.22 0.11 1 0.48
torso_d_rot_z_center 0.34 0.34 0.058 0.18 0.1 0.62 0.14 -0.42 -0.11 -0.056 -0.12 -0.16 -0.073 -0.16 0.16 0.34 0.35 -0.013 0.48 1
In [12]:
yscale = alt.Scale(domain=(35, 65))

points_left = alt.Chart(data.loc['lap1'], width=650, height=100).mark_circle(opacity=0.3, color='red').encode(
    alt.X('elapsed_time',
          scale=alt.Scale(domain=[0, 3250]),
          axis=alt.Axis(title='')
         ),
    alt.Y('foot_range_log_left',
          scale=yscale,
          axis=alt.Axis(title='Lap 1'),
         ),
).properties(title='Foot Angular Range (Left in Red, Right in Blue)')

points_right = alt.Chart(data.loc['lap1'], width=650, height=100).mark_circle(opacity=0.3, color='blue').encode(
    alt.X('elapsed_time',
          scale=alt.Scale(domain=[0, 3250])),
    alt.Y('foot_range_log_right', scale=yscale),
)

hist_left = alt.Chart(data.loc['lap1'], height=100).mark_area(clip=True, opacity=.3, interpolate='step', color='red').encode(
    alt.Y('foot_range_log_left:Q',
          bin=alt.Bin(maxbins=60, extent=yscale.domain),
          stack=None,
          axis=alt.Axis(title=''),
          scale=alt.Scale(domain=[40,60])
         ),
    alt.X('count()', stack=None, scale=alt.Scale(domain=[0, 100]), axis=alt.Axis(title='')
         ),
).properties(width=150)

hist_right = alt.Chart(data.loc['lap1'], height=100).mark_area(clip=True, opacity=.3, interpolate='step', color='blue').encode(
    alt.Y('foot_range_log_right:Q',
          bin=alt.Bin(maxbins=60, extent=yscale.domain),
          stack=None,
          axis=alt.Axis(title=''),
          scale=alt.Scale(domain=[40,60])
         ),
    alt.X('count()', stack=None, scale=alt.Scale(domain=[0, 100])),
).properties(width=150)

hist_left_rule = alt.Chart(data.loc['lap1']).mark_rule(color='red').encode(
    y='mean(foot_range_log_left):Q',
    size=alt.value(2)
)

hist_right_rule = alt.Chart(data.loc['lap1']).mark_rule(color='blue').encode(
    y='mean(foot_range_log_right):Q',
    size=alt.value(2)
)


lap1 = ((points_left + points_right) | (hist_left + hist_right + hist_left_rule + hist_right_rule))
In [13]:
yscale = alt.Scale(domain=(35, 65))

points_left = alt.Chart(data.loc['lap2'], width=650, height=100).mark_circle(opacity=0.3, color='red').encode(
    alt.X('elapsed_time',
          scale=alt.Scale(domain=[0, 3250]),
          axis=alt.Axis(title=''),
         ),
    alt.Y('foot_range_log_left',
          scale=yscale,
          axis=alt.Axis(title='Lap 2'),
         ),
)

points_right = alt.Chart(data.loc['lap2'], width=650, height=100).mark_circle(opacity=0.3, color='blue').encode(
    alt.X('elapsed_time',
          scale=alt.Scale(domain=[0, 3250]),
          axis=alt.Axis(title='')
         ),
    alt.Y('foot_range_log_right', scale=yscale),
)

hist_left = alt.Chart(data.loc['lap2'], height=100).mark_area(clip=True, opacity=.3, interpolate='step', color='red').encode(
    alt.Y('foot_range_log_left:Q',
          bin=alt.Bin(maxbins=60, extent=yscale.domain),
          stack=None,
          axis=alt.Axis(title=''),
          scale=alt.Scale(domain=[40,60])
         ),
    alt.X('count()', stack=None, scale=alt.Scale(domain=[0, 100]), axis=alt.Axis(title='')
         ),
).properties(width=150)

hist_right = alt.Chart(data.loc['lap2'], height=100).mark_area(clip=True, opacity=.3, interpolate='step', color='blue').encode(
    alt.Y('foot_range_log_right:Q',
          bin=alt.Bin(maxbins=60, extent=yscale.domain),
          stack=None,
          axis=alt.Axis(title=''),
          scale=alt.Scale(domain=[40,60])
         ),
    alt.X('count()', stack=None, scale=alt.Scale(domain=[0, 100])),
).properties(width=150)

hist_left_rule = alt.Chart(data.loc['lap2']).mark_rule(color='red').encode(
    y='mean(foot_range_log_left):Q',
    size=alt.value(2)
)

hist_right_rule = alt.Chart(data.loc['lap2']).mark_rule(color='blue').encode(
    y='mean(foot_range_log_right):Q',
    size=alt.value(2)
)


lap2 = ((points_left + points_right) | (hist_left + hist_right + hist_left_rule + hist_right_rule))
In [14]:
yscale = alt.Scale(domain=(35, 65))

points_left = alt.Chart(data.loc['lap3'], width=650, height=100).mark_circle(opacity=0.3, color='red').encode(
    alt.X('elapsed_time',
          scale=alt.Scale(domain=[0, 3250]),
          axis=alt.Axis(title='Elapsed Time (s)'),
         ),
    alt.Y('foot_range_log_left',
          scale=yscale,
          axis=alt.Axis(title='Lap 3'),
         ),
)

points_right = alt.Chart(data.loc['lap3'], width=650, height=100).mark_circle(opacity=0.3, color='blue').encode(
    alt.X('elapsed_time',
          scale=alt.Scale(domain=[0, 3250])),
    alt.Y('foot_range_log_right', scale=yscale),
)

hist_left = alt.Chart(data.loc['lap3']).mark_area(clip=True, opacity=.3, interpolate='step', color='red').encode(
    alt.Y('foot_range_log_left:Q',
          bin=alt.Bin(maxbins=60, extent=yscale.domain),
          stack=None,
          axis=alt.Axis(title=''),
          scale=alt.Scale(domain=[40,60])
         ),
    alt.X('count()', stack=None, scale=alt.Scale(domain=[0, 100])),
).properties(width=150)

hist_right = alt.Chart(data.loc['lap3']).mark_area(clip=True, opacity=.3, interpolate='step', color='blue').encode(
    alt.Y('foot_range_log_right:Q',
          bin=alt.Bin(maxbins=60, extent=yscale.domain),
          stack=None,
          axis=alt.Axis(title=''),
          scale=alt.Scale(domain=[40,60])
         ),
    alt.X('count()', stack=None, scale=alt.Scale(domain=[0, 100])),
).properties(width=150)

hist_left_rule = alt.Chart(data.loc['lap3'], height=100).mark_rule(color='red').encode(
    y='mean(foot_range_log_left):Q',
    size=alt.value(2)
)

hist_right_rule = alt.Chart(data.loc['lap3'], height=100).mark_rule(color='blue').encode(
    y='mean(foot_range_log_right):Q',
    size=alt.value(2)
)


lap3 = ((points_left + points_right) | (hist_left + hist_right + hist_left_rule + hist_right_rule))
In [15]:
(lap1 & lap2 & lap3)
Out[15]:
In [16]:
yscale = alt.Scale(domain=(0, 40))

DSS1points_left = alt.Chart(data.loc['lap1'], width=650, height=100).mark_circle(opacity=0.3, color='red').encode(
    alt.X('elapsed_time',
          scale=alt.Scale(domain=[0, 3250]),
          axis=alt.Axis(title='')
         ),
    alt.Y('ankling_log_left',
          scale=yscale,
          axis=alt.Axis(title='Lap 1'),
         ),
).properties(title='DSS')

DSS1points_right = alt.Chart(data.loc['lap1'], width=650, height=100).mark_circle(opacity=0.3, color='blue').encode(
    alt.X('elapsed_time',
          scale=alt.Scale(domain=[0, 3250])),
    alt.Y('ankling_log_right', scale=yscale),
)

DSS1hist_left = alt.Chart(data.loc['lap1'], height=100).mark_area(clip=True, opacity=.3, interpolate='step', color='red').encode(
    alt.Y('ankling_log_left:Q',
          bin=alt.Bin(maxbins=30, extent=yscale.domain),
          stack=None,
          axis=alt.Axis(title=''),
          scale=alt.Scale(domain=[0,40])
         ),
    alt.X('count()', stack=None, scale=alt.Scale(domain=[0, 30]), axis=alt.Axis(title='')
         ),
).properties(width=150)

DSS1hist_right = alt.Chart(data.loc['lap1'], height=100).mark_area(clip=True, opacity=.3, interpolate='step', color='blue').encode(
    alt.Y('ankling_log_right:Q',
          bin=alt.Bin(maxbins=30, extent=yscale.domain),
          stack=None,
          axis=alt.Axis(title=''),
          scale=alt.Scale(domain=[0,40])
         ),
    alt.X('count()', stack=None, scale=alt.Scale(domain=[0, 30])),
).properties(width=150)

DSS1hist_left_rule = alt.Chart(data.loc['lap1']).mark_rule(color='red').encode(
    y='mean(ankling_log_left):Q',
    size=alt.value(2)
)

DSS1hist_right_rule = alt.Chart(data.loc['lap1']).mark_rule(color='blue').encode(
    y='mean(ankling_log_right):Q',
    size=alt.value(2)
)


DSSlap1 = ((DSS1points_left + DSS1points_right) | (DSS1hist_left + DSS1hist_right + DSS1hist_left_rule + DSS1hist_right_rule))
In [17]:
yscale = alt.Scale(domain=(0, 40))

DSS2points_left = alt.Chart(data.loc['lap2'], width=650, height=100).mark_circle(opacity=0.3, color='red').encode(
    alt.X('elapsed_time',
          scale=alt.Scale(domain=[0, 3250]),
          axis=alt.Axis(title='')
         ),
    alt.Y('ankling_log_left',
          scale=yscale,
          axis=alt.Axis(title='Lap 2'),
         ),
)

DSS2points_right = alt.Chart(data.loc['lap2'], width=650, height=100).mark_circle(opacity=0.3, color='blue').encode(
    alt.X('elapsed_time',
          scale=alt.Scale(domain=[0, 3250])),
    alt.Y('ankling_log_right', scale=yscale),
)

DSS2hist_left = alt.Chart(data.loc['lap2'], height=100).mark_area(clip=True, opacity=.3, interpolate='step', color='red').encode(
    alt.Y('ankling_log_left:Q',
          bin=alt.Bin(maxbins=30, extent=yscale.domain),
          stack=None,
          axis=alt.Axis(title=''),
          scale=alt.Scale(domain=[0,40])
         ),
    alt.X('count()', stack=None, scale=alt.Scale(domain=[0, 30]), axis=alt.Axis(title='')
         ),
).properties(width=150)

DSS2hist_right = alt.Chart(data.loc['lap2'], height=100).mark_area(clip=True, opacity=.3, interpolate='step', color='blue').encode(
    alt.Y('ankling_log_right:Q',
          bin=alt.Bin(maxbins=30, extent=yscale.domain),
          stack=None,
          axis=alt.Axis(title=''),
          scale=alt.Scale(domain=[0,40])
         ),
    alt.X('count()', stack=None, scale=alt.Scale(domain=[0, 30])),
).properties(width=150)

DSS2hist_left_rule = alt.Chart(data.loc['lap2']).mark_rule(color='red').encode(
    y='mean(ankling_log_left):Q',
    size=alt.value(2)
)

DSS2hist_right_rule = alt.Chart(data.loc['lap2']).mark_rule(color='blue').encode(
    y='mean(ankling_log_right):Q',
    size=alt.value(2)
)


DSSlap2 = ((DSS2points_left + DSS2points_right) | (DSS2hist_left + DSS2hist_right + DSS2hist_left_rule + DSS2hist_right_rule))
In [18]:
yscale = alt.Scale(domain=(0, 40))

DSS3points_left = alt.Chart(data.loc['lap3'], width=650, height=100).mark_circle(opacity=0.3, color='red').encode(
    alt.X('elapsed_time',
          scale=alt.Scale(domain=[0, 3250]),
          axis=alt.Axis(title='')
         ),
    alt.Y('ankling_log_left',
          scale=yscale,
          axis=alt.Axis(title='Lap 3'),
         ),
)

DSS3points_right = alt.Chart(data.loc['lap3'], width=650, height=100).mark_circle(opacity=0.3, color='blue').encode(
    alt.X('elapsed_time',
          scale=alt.Scale(domain=[0, 3250])),
    alt.Y('ankling_log_right', scale=yscale),
)

DSS3hist_left = alt.Chart(data.loc['lap3'], height=100).mark_area(clip=True, opacity=.3, interpolate='step', color='red').encode(
    alt.Y('ankling_log_left:Q',
          bin=alt.Bin(maxbins=30, extent=yscale.domain),
          stack=None,
          axis=alt.Axis(title=''),
          scale=alt.Scale(domain=[0,40])
         ),
    alt.X('count()', stack=None, scale=alt.Scale(domain=[0, 30]), axis=alt.Axis(title='')
         ),
).properties(width=150)

DSS3hist_right = alt.Chart(data.loc['lap3'], height=100).mark_area(clip=True, opacity=.3, interpolate='step', color='blue').encode(
    alt.Y('ankling_log_right:Q',
          bin=alt.Bin(maxbins=30, extent=yscale.domain),
          stack=None,
          axis=alt.Axis(title=''),
          scale=alt.Scale(domain=[0,40])
         ),
    alt.X('count()', stack=None, scale=alt.Scale(domain=[0, 30])),
).properties(width=150)

DSS3hist_left_rule = alt.Chart(data.loc['lap3']).mark_rule(color='red').encode(
    y='mean(ankling_log_left):Q',
    size=alt.value(2)
)

DSS3hist_right_rule = alt.Chart(data.loc['lap3']).mark_rule(color='blue').encode(
    y='mean(ankling_log_right):Q',
    size=alt.value(2)
)


DSSlap3 = ((DSS3points_left + DSS3points_right) | (DSS3hist_left + DSS3hist_right + DSS3hist_left_rule + DSS3hist_right_rule))
In [19]:
(DSSlap1 & DSSlap2 & DSSlap3)
Out[19]:
In [20]:
lap = [1, 2, 3]
yleft = [data.loc['lap1']['ankling_log_left'].mean(), data.loc['lap2']['ankling_log_left'].mean(), data.loc['lap3']['ankling_log_left'].mean()]
yright = [data.loc['lap1']['ankling_log_right'].mean(), data.loc['lap2']['ankling_log_right'].mean(), data.loc['lap3']['ankling_log_right'].mean()]

# set up data frame
meandata = pd.DataFrame({'lap':lap, 'yleft':yleft, 'yright':yright})

# generate the points
pointsleft = alt.Chart(meandata).mark_line().encode(
    alt.X('lap:Q',
          scale=alt.Scale(domain=(0,4)),
          axis=alt.Axis(title='lap')
         ),
    alt.Y('yleft',
            scale=alt.Scale(zero=False, domain=(0.5, 1)),
            axis=alt.Axis(title='mean DSS')
           ),
    color=alt.value('red')
)

# generate the point
pointsright = alt.Chart(meandata).mark_line().encode(
    alt.X('lap:Q',
          scale=alt.Scale(domain=(0,4)),
          axis=alt.Axis(title='lap')
         ),
    alt.Y('yright',
            scale=alt.Scale(zero=False, domain=(0.5, 1)),
         ),
    color=alt.value('blue')
).properties(title='mean DSS for left (red) and right (blue)')

(pointsleft + pointsright)
Out[20]:
In [21]:
altitude = alt.Chart(data.loc['lap3'], width=900).mark_area(color='lightgrey').encode(
    alt.X('elapsed_time',
        axis=alt.Axis(title='Elapsed Time (s)'),
    ),
    alt.Y('altitude',
          scale=alt.Scale(domain=[0, 200]),
          axis=alt.Axis(title='', ticks=False, labels=False, grid=False)
         ),
)

power = alt.Chart(data.loc['lap3'], width=900).mark_line().encode(
    alt.X('elapsed_time',
        axis=alt.Axis(title='Elapsed Time (s)'),
    ),
    alt.Y('power',
          scale=alt.Scale(domain=[0, 500]),
          axis=alt.Axis(title='', ticks=False, labels=False, grid=False)
         ),
    color=alt.value('red')  
)

cadence = alt.Chart(data.loc['lap3'], width=900).mark_line().encode(
    alt.X('elapsed_time',
        axis=alt.Axis(title='Elapsed Time (s)'),
    ),
    alt.Y('cadence',
          scale=alt.Scale(domain=[60, 120]),
          axis=alt.Axis(title='', ticks=False, labels=False, grid=False)
         ),
    color=alt.value('lightblue')    
)

speed = alt.Chart(data.loc['lap3'], width=900).mark_line().encode(
    alt.X('elapsed_time',
        axis=alt.Axis(title='Elapsed Time (s)'),
    ),
    alt.Y('speed',
          scale=alt.Scale(domain=[0, 20]),
          axis=alt.Axis(title='', ticks=False, labels=False, grid=False)
         ),
    color=alt.value('green')    
)

# Create a selection that chooses the nearest point & selects based on x-value
nearest = alt.selection(type='single', nearest=True, on='mouseover',
                        fields=['elapsed_time'], empty='none')

# Transparent selectors across the chart. This is what tells us
# the x-value of the cursor
selectors = altitude.mark_point().encode(
    x='elapsed_time',
    opacity=alt.value(0),
).add_selection(
    nearest
)

# Draw points on the line, and highlight based on selection
speedpoints = speed.mark_point().encode(
    opacity=alt.condition(nearest, alt.value(1), alt.value(0))
)
cadencepoints = cadence.mark_point().encode(
    opacity=alt.condition(nearest, alt.value(1), alt.value(0))
)
powerpoints = power.mark_point().encode(
    opacity=alt.condition(nearest, alt.value(1), alt.value(0))
)


# Draw text labels near the points, and highlight based on selection
speedtext = speed.mark_text(align='left', dx=5, dy=-5, fontSize=14, fontWeight='bold').encode(
    text=alt.condition(nearest, 'speed', alt.value(' '))
)
cadencetext = cadence.mark_text(align='left', dx=5, dy=-5, fontSize=14, fontWeight='bold').encode(
    text=alt.condition(nearest,'cadence', alt.value(' '))
)
powertext = power.mark_text(align='left', dx=5, dy=-5, fontSize=14, fontWeight='bold').encode(
    text=alt.condition(nearest,'power', alt.value(' '))
)

# Draw a rule at the location of the selection
rules = altitude.mark_rule(color='grey').encode(
    x='elapsed_time',
).transform_filter(
    nearest
)

alt.layer(
    altitude,
    power,
    cadence,
    speed,
    selectors,
    powerpoints,
    cadencepoints,
    speedpoints,
    powertext,
    cadencetext,
    speedtext,
    rules,
    data=data.loc['lap3']
).resolve_scale(
    y='independent'
).interactive(bind_y=False)
Out[21]:
In [22]:
altitude1 = alt.Chart(data.loc['lap1'], width=900).mark_area(color='lightgrey').encode(
    alt.X('elapsed_time',
          axis=alt.Axis(title='Elapsed time (s)'),
    ),
    alt.Y('altitude',
          scale=alt.Scale(domain=[0, 150]),
          axis=alt.Axis(title='Altitude (m)', ticks=False, labels=False, grid=False)
         ),
)

altitude2 = alt.Chart(data.loc['lap2'], width=900).mark_area(color='lightgrey').encode(
    alt.X('elapsed_time',
#           axis=alt.Axis(title='Elapsed lap time (s)'),
    ),
    alt.Y('altitude',
          scale=alt.Scale(domain=[0, 150]),
          axis=alt.Axis(title='', ticks=False, labels=False, grid=False)
         ),
)

altitude3 = alt.Chart(data.loc['lap3'], width=900).mark_area(color='lightgrey').encode(
    alt.X('elapsed_time',
#           axis=alt.Axis(title='Elapsed lap time (s)'),
    ),
    alt.Y('altitude',
          scale=alt.Scale(domain=[0, 150]),
          axis=alt.Axis(title='', ticks=False, labels=False, grid=False)
         ),
)

speed1 = alt.Chart(data.loc['lap1'], width=900).mark_line().encode(
    alt.X('elapsed_time',
    ),
    alt.Y('speed',
          scale=alt.Scale(domain=[0, 18]),
          axis=alt.Axis(title='Speed (m/s)')
         ),
    color=alt.value('green')    
)

speed2 = alt.Chart(data.loc['lap2'], width=900).mark_line().encode(
    alt.X('elapsed_time',
#         axis=alt.Axis(title='Elapsed Time (s)'),
    ),
    alt.Y('speed',
          scale=alt.Scale(domain=[0, 18]),
          axis=alt.Axis(title='', ticks=False, labels=False, grid=False)
         ),
    color=alt.value('orange')    
)

speed3 = alt.Chart(data.loc['lap3'], width=900).mark_line().encode(
    alt.X('elapsed_time',
#         axis=alt.Axis(title='Elapsed Time (s)'),
    ),
    alt.Y('speed',
          scale=alt.Scale(domain=[0, 18]),
          axis=alt.Axis(title='', ticks=False, labels=False, grid=False)
         ),
    color=alt.value('blue')    
)


# Create a selection that chooses the nearest point & selects based on x-value
nearest = alt.selection(type='single', nearest=True, on='mouseover',
                        fields=['elapsed_time'], empty='none')

# Transparent selectors across the chart. This is what tells us
# the x-value of the cursor
selectors = altitude.mark_point().encode(
    x='elapsed_time',
    opacity=alt.value(0),
).add_selection(
    nearest
)

# Draw points on the line, and highlight based on selection
speedpoints1 = speed1.mark_point().encode(
    opacity=alt.condition(nearest, alt.value(1), alt.value(0))
)
speedpoints2 = speed2.mark_point().encode(
    opacity=alt.condition(nearest, alt.value(1), alt.value(0))
)
speedpoints3 = speed3.mark_point().encode(
    opacity=alt.condition(nearest, alt.value(1), alt.value(0))
)



# Draw text labels near the points, and highlight based on selection
speedtext1 = speed1.mark_text(align='left', dx=5, dy=-5, fontSize=12, fontWeight='bold').encode(
    text=alt.condition(nearest, 'speed', alt.value(' '))
)
speedtext2 = speed2.mark_text(align='left', dx=5, dy=-5, fontSize=12, fontWeight='bold').encode(
    text=alt.condition(nearest, 'speed', alt.value(' '))
)
speedtext3 = speed3.mark_text(align='left', dx=5, dy=-5, fontSize=12, fontWeight='bold').encode(
    text=alt.condition(nearest, 'speed', alt.value(' '))
)


# Draw a rule at the location of the selection
rules = altitude.mark_rule(color='grey').encode(
    x='elapsed_time',
).transform_filter(
    nearest
)

alt.layer(
    altitude1,
    altitude2,
    altitude3,
    speed1,
    speed2,
    speed3,
#     selectors,
#     speedpoints1,
#     speedpoints2,
#     speedpoints3,
#     speedtext1,
#     speedtext2,
#     speedtext3,
#     rules,
#     data=data.loc['lap1']
).resolve_scale(
    y='independent'
).interactive(bind_y=False)
Out[22]:
In [23]:
altitude = alt.Chart(data.loc['lap1'].reset_index(), width=900).mark_area(color='lightgrey').encode(
    alt.X('index',
          axis=alt.Axis(title='Elapsed lap time (s)'),
    ),
    alt.Y('altitude',
          scale=alt.Scale(domain=[0, 150]),
          axis=alt.Axis(title='Altitude (m)')
         ),
)

torso1 = alt.Chart(data.loc['lap1'].reset_index(), width=900).mark_line().encode(
    alt.X('index',
    ),
    alt.Y('torso_angle_log_center',
          scale=alt.Scale(domain=[0, 40]),
#           axis=alt.Axis(title='Torso Angle (deg)')
         ),
    color=alt.value('yellow')    
)

torso2 = alt.Chart(data.loc['lap2'].reset_index(), width=900).mark_line().encode(
    alt.X('index',
    ),
    alt.Y('torso_angle_log_center',
          scale=alt.Scale(domain=[0, 40]),
         ),
    color=alt.value('orange')    
)

torso3 = alt.Chart(data.loc['lap3'].reset_index(), width=900).mark_line().encode(
    alt.X('index',
    ),
    alt.Y('torso_angle_log_center',
          scale=alt.Scale(domain=[0, 40]),
         ),
    color=alt.value('red')    
)

alt.layer(
    altitude,
    torso1,
    torso2,
    torso3
).resolve_scale(
    y='independent'
).interactive(bind_y=False)
Out[23]:
In [24]:
xtitle='FAR Left for Q1'
ytitle='FAR Right for Q1'
xscl=[0,55]
yscl=[0,55]

farq11 = alt.Chart(data.loc['lap1'], height=300, width=300).mark_rect().encode(
    alt.X('pedaling_delay_log_left:Q',
          bin=alt.Bin(maxbins=40),
          scale=alt.Scale(domain=xscl),
          axis=alt.Axis(title=xtitle)
         ),
    alt.Y('pedaling_delay_log_right:Q',
          bin=alt.Bin(maxbins=40),
          scale=alt.Scale(domain=xscl),
          axis=alt.Axis(title=ytitle)
         ),
    alt.Color('power:Q', scale=alt.Scale(domain=[0, 600], scheme='greenblue'))
).properties(title='Lap 1')

farq12 = alt.Chart(data.loc['lap2'], height=300, width=300).mark_rect().encode(
    alt.X('pedaling_delay_log_left:Q',
          bin=alt.Bin(maxbins=40),
          scale=alt.Scale(domain=xscl),
          axis=alt.Axis(title=xtitle)
         ),
    alt.Y('pedaling_delay_log_right:Q',
          bin=alt.Bin(maxbins=40),
          scale=alt.Scale(domain=yscl),
          axis=alt.Axis(title=ytitle)
         ),
    alt.Color('power:Q', scale=alt.Scale(domain=[0, 600], scheme='greenblue'))
).properties(title='Lap 2')

farq13 = alt.Chart(data.loc['lap3'], height=300, width=300).mark_rect().encode(
    alt.X('pedaling_delay_log_left:Q',
          bin=alt.Bin(maxbins=40),
          scale=alt.Scale(domain=xscl),
          axis=alt.Axis(title=xtitle)
         ),
    alt.Y('pedaling_delay_log_right:Q',
          bin=alt.Bin(maxbins=40),
          scale=alt.Scale(domain=yscl),
          axis=alt.Axis(title=ytitle)
         ),
    alt.Color('power:Q', scale=alt.Scale(domain=[0, 600], scheme='greenblue'))
).properties(title='Lap 3')

farq11xmean = alt.Chart(data.loc['lap1']).mark_rule(color='red').encode(
    x='mean(pedaling_delay_log_left):Q',
    size=alt.value(1)
)

farq11ymean = alt.Chart(data.loc['lap1']).mark_rule(color='red').encode(
    y='mean(pedaling_delay_log_right):Q',
    size=alt.value(1)
)

farq12xmean = alt.Chart(data.loc['lap2']).mark_rule(color='red').encode(
    x='mean(pedaling_delay_log_left):Q',
    size=alt.value(1)
)

farq12ymean = alt.Chart(data.loc['lap2']).mark_rule(color='red').encode(
    y='mean(pedaling_delay_log_right):Q',
    size=alt.value(1)
)

farq13xmean = alt.Chart(data.loc['lap3']).mark_rule(color='red').encode(
    x='mean(pedaling_delay_log_left):Q',
    size=alt.value(1)
)

farq13ymean = alt.Chart(data.loc['lap3']).mark_rule(color='red').encode(
    y='mean(pedaling_delay_log_right):Q',
    size=alt.value(1)
)

(farq11 + farq11xmean + farq11ymean) | (farq12 + farq12xmean + farq12ymean) | (farq13 + farq13xmean + farq13ymean)
Out[24]:
In [25]:
mb=100
xtitle='FAR Left'
ytitle='FAR right'

foot1 = alt.Chart(data.loc['lap1'], height=300, width=300).mark_rect().encode(
    alt.X('foot_range_log_left',
          bin=alt.Bin(maxbins=mb),
          scale=alt.Scale(domain=[30, 70]),
          axis=alt.Axis(title=xtitle)
         ),
    alt.Y('foot_range_log_right',
          bin=alt.Bin(maxbins=mb),
          scale=alt.Scale(domain=[30, 70]),
          axis=alt.Axis(title=ytitle)
         ),
    alt.Color('power:Q', scale=alt.Scale(domain=[0, 600], scheme='greenblue'))
).properties(title='Lap 1')

foot2 = alt.Chart(data.loc['lap2'], height=300, width=300).mark_rect().encode(
    alt.X('foot_range_log_left',
          bin=alt.Bin(maxbins=mb),
          scale=alt.Scale(domain=[30, 70]),
          axis=alt.Axis(title=xtitle)
         ),
    alt.Y('foot_range_log_right',
          bin=alt.Bin(maxbins=mb),
          scale=alt.Scale(domain=[30, 70]),
          axis=alt.Axis(title=ytitle)
         ),
    alt.Color('power:Q', scale=alt.Scale(domain=[0, 600], scheme='greenblue'))
).properties(title='Lap 2')

foot3 = alt.Chart(data.loc['lap3'], height=300, width=300).mark_rect().encode(
    alt.X('foot_range_log_left',
          bin=alt.Bin(maxbins=mb),
          scale=alt.Scale(domain=[30, 70]),
          axis=alt.Axis(title=xtitle)
         ),
    alt.Y('foot_range_log_right',
          bin=alt.Bin(maxbins=mb),
          scale=alt.Scale(domain=[30, 70]),
          axis=alt.Axis(title=ytitle)
         ),
    alt.Color('power:Q', scale=alt.Scale(domain=[0, 600], scheme='greenblue'))
).properties(title='Lap 3')

foot1xmean = alt.Chart(data.loc['lap1']).mark_rule(color='red').encode(
    x='mean(foot_range_log_left):Q',
    size=alt.value(1)
)

foot1ymean = alt.Chart(data.loc['lap1']).mark_rule(color='red').encode(
    y='mean(foot_range_log_right):Q',
    size=alt.value(1)
)

foot2xmean = alt.Chart(data.loc['lap2']).mark_rule(color='red').encode(
    x='mean(foot_range_log_left):Q',
    size=alt.value(1)
)

foot2ymean = alt.Chart(data.loc['lap2']).mark_rule(color='red').encode(
    y='mean(foot_range_log_right):Q',
    size=alt.value(1)
)

foot3xmean = alt.Chart(data.loc['lap3']).mark_rule(color='red').encode(
    x='mean(foot_range_log_left):Q',
    size=alt.value(1)
)

foot3ymean = alt.Chart(data.loc['lap3']).mark_rule(color='red').encode(
    y='mean(foot_range_log_right):Q',
    size=alt.value(1)
)

(foot1 + foot1xmean + foot1ymean) | (foot2 + foot2xmean + foot2ymean) | (foot3 + foot3xmean + foot3ymean)
Out[25]:

Angle

Average Pelvic angle increases from 47.5 to 49.5 from Lap 1 to Lap 3

In [26]:
yscl=[3, 37]
xscl=[38, 67]
xtitle='Pelvic Angle'
ytitle='Torso Angle'

ang1=alt.Chart(data.loc['lap1'], height=300, width=300).mark_rect().encode(
    alt.X('waist_angle_log_center:Q',
          bin=alt.Bin(maxbins=40),
          scale=alt.Scale(domain=xscl),
          axis=alt.Axis(title=xtitle)
         ),
    alt.Y('torso_angle_log_center:Q',
          bin=alt.Bin(maxbins=40),
          scale=alt.Scale(domain=yscl),
          axis=alt.Axis(title=ytitle)
         ),
    alt.Color('power:Q', scale=alt.Scale(domain=[0, 600], scheme='greenblue'))
).properties(title='Lap 1')

ang2=alt.Chart(data.loc['lap2'], height=300, width=300).mark_rect().encode(
    alt.X('waist_angle_log_center:Q',
          bin=alt.Bin(maxbins=40),
          scale=alt.Scale(domain=xscl),
          axis=alt.Axis(title=xtitle)
         ),
    alt.Y('torso_angle_log_center:Q',
          bin=alt.Bin(maxbins=40),
          scale=alt.Scale(domain=yscl),
          axis=alt.Axis(title=ytitle)
         ),
    alt.Color('power:Q', scale=alt.Scale(domain=[0, 600], scheme='greenblue'))
).properties(title='Lap 2')

ang3=alt.Chart(data.loc['lap3'], height=300, width=300).mark_rect().encode(
    alt.X('waist_angle_log_center:Q',
          bin=alt.Bin(maxbins=40),
          scale=alt.Scale(domain=xscl),
          axis=alt.Axis(title=xtitle)
         ),
    alt.Y('torso_angle_log_center:Q',
          bin=alt.Bin(maxbins=40),
          scale=alt.Scale(domain=yscl),
          axis=alt.Axis(title=ytitle)
         ),
    alt.Color('power:Q', scale=alt.Scale(domain=[0, 600], scheme='greenblue'))
).properties(title='Lap 3')

ang1xmean = alt.Chart(data.loc['lap1']).mark_rule(color='red').encode(
    x='mean(waist_angle_log_center):Q',
    size=alt.value(1)
)

ang1ymean = alt.Chart(data.loc['lap1']).mark_rule(color='red').encode(
    y='mean(torso_angle_log_center):Q',
    size=alt.value(1)
)

ang2xmean = alt.Chart(data.loc['lap2']).mark_rule(color='red').encode(
    x='mean(waist_angle_log_center):Q',
    size=alt.value(1)
)

ang2ymean = alt.Chart(data.loc['lap2']).mark_rule(color='red').encode(
    y='mean(torso_angle_log_center):Q',
    size=alt.value(1)
)

ang3xmean = alt.Chart(data.loc['lap3']).mark_rule(color='red').encode(
    x='mean(waist_angle_log_center):Q',
    size=alt.value(1)
)

ang3ymean = alt.Chart(data.loc['lap3']).mark_rule(color='red').encode(
    y='mean(torso_angle_log_center):Q',
    size=alt.value(1)
)

(ang1 + ang1xmean + ang1ymean) | (ang2 + ang2xmean + ang2ymean) | (ang3 + ang3xmean + ang3ymean)
Out[26]:
In [28]:
f, (ax1, ax2, ax3) = plt.subplots(1, 3)
sns.violinplot(y=data.loc['lap1']['waist_angle_log_center'], ax=ax1, scale="count", inner="quartile", color="red").set_title("Lap 1")
sns.violinplot(y=data.loc['lap2']['waist_angle_log_center'], ax=ax2, scale="count", inner="quartile", color="skyblue").set_title("Lap 2")
sns.violinplot(y=data.loc['lap3']['waist_angle_log_center'], ax=ax3, scale="count", inner="quartile", color="lightgreen").set_title("Lap 3")
plt.tight_layout()
In [29]:
f, (ax1, ax2, ax3) = plt.subplots(1, 3)
sns.violinplot(y=data.loc['lap1']['torso_angle_log_center'], ax=ax1, scale="count", inner="quartile", color="red").set_title("Lap 1")
sns.violinplot(y=data.loc['lap2']['torso_angle_log_center'], ax=ax2, scale="count", inner="quartile", color="skyblue").set_title("Lap 2")
sns.violinplot(y=data.loc['lap3']['torso_angle_log_center'], ax=ax3, scale="count", inner="quartile", color="lightgreen").set_title("Lap 3")
plt.tight_layout()

Rotation

Red lines indicate the lap-averaged rotation.

Generation of high power requires more and more Torso rotation as the ride progresses and fatigue sets in.

The trend in Pelvic rotation is less pronounced.

In [30]:
xscl=[0, 35]
yscl=[0, 20]
xtitle='Pelvic Rotation'
ytitle='Torso Rotation'

rot1 = alt.Chart(data.loc['lap1'], height=300, width=300).mark_rect().encode(
    alt.X('waist_d_rot_y_center',
          bin=alt.Bin(maxbins=40),
          scale=alt.Scale(domain=xscl),
          axis=alt.Axis(title=xtitle)
         ),
    alt.Y('torso_d_rot_y_center',
          bin=alt.Bin(maxbins=40),
          scale=alt.Scale(domain=yscl),
          axis=alt.Axis(title=ytitle)
         ),
    alt.Color('power:Q', scale=alt.Scale(domain=[0, 600], scheme='greenblue'))
).properties(title='Lap 1')

rot2 = alt.Chart(data.loc['lap2'], height=300, width=300).mark_rect().encode(
    alt.X('waist_d_rot_y_center',
          bin=alt.Bin(maxbins=40),
          scale=alt.Scale(domain=xscl),
          axis=alt.Axis(title=xtitle)
         ),
    alt.Y('torso_d_rot_y_center',
          bin=alt.Bin(maxbins=40),
          scale=alt.Scale(domain=yscl),
          axis=alt.Axis(title=ytitle)
         ),
    alt.Color('power:Q', scale=alt.Scale(domain=[0, 600], scheme='greenblue'))
).properties(title='Lap 2')

rot3 = alt.Chart(data.loc['lap3'], height=300, width=300).mark_rect().encode(
    alt.X('waist_d_rot_y_center',
          bin=alt.Bin(maxbins=40),
          scale=alt.Scale(domain=xscl),
          axis=alt.Axis(title=xtitle)
         ),
    alt.Y('torso_d_rot_y_center',
          bin=alt.Bin(maxbins=40),
          scale=alt.Scale(domain=yscl),
          axis=alt.Axis(title=ytitle)
         ),
    alt.Color('power:Q', scale=alt.Scale(domain=[0, 600], scheme='greenblue'))
).properties(title='Lap 3')

rot1xmean = alt.Chart(data.loc['lap1']).mark_rule(color='red').encode(
    x='mean(waist_d_rot_y_center):Q',
    size=alt.value(1)
)

rot1ymean = alt.Chart(data.loc['lap1']).mark_rule(color='red').encode(
    y='mean(torso_d_rot_y_center):Q',
    size=alt.value(1)
)

rot2xmean = alt.Chart(data.loc['lap2']).mark_rule(color='red').encode(
    x='mean(waist_d_rot_y_center):Q',
    size=alt.value(1)
)

rot2ymean = alt.Chart(data.loc['lap2']).mark_rule(color='red').encode(
    y='mean(torso_d_rot_y_center):Q',
    size=alt.value(1)
)

rot3xmean = alt.Chart(data.loc['lap3']).mark_rule(color='red').encode(
    x='mean(waist_d_rot_y_center):Q',
    size=alt.value(1)
)

rot3ymean = alt.Chart(data.loc['lap3']).mark_rule(color='red').encode(
    y='mean(torso_d_rot_y_center):Q',
    size=alt.value(1)
)

(rot1 + rot1xmean + rot1ymean) | (rot2 + rot2xmean + rot2ymean) | (rot3 + rot3xmean + rot3ymean)
Out[30]:

Rock

Increased average Torso and Pelvic Rock throughout the ride, as fatigue builds up

In [31]:
xscl=[0, 20]
yscl=[0, 20]
xtitle='Pelvic Rock'
ytitle='Torso Rock'

roc1 = alt.Chart(data.loc['lap1'], height=300, width=300).mark_rect().encode(
    alt.X('waist_d_rot_z_center',
          bin=alt.Bin(maxbins=40),
          scale=alt.Scale(domain=xscl),
          axis=alt.Axis(title=xtitle)
         ),
    alt.Y('torso_d_rot_z_center',
          bin=alt.Bin(maxbins=40),
          scale=alt.Scale(domain=yscl),
          axis=alt.Axis(title=ytitle)
         ),
    alt.Color('power:Q', scale=alt.Scale(domain=[0, 600], scheme='greenblue'))
).properties(title='Lap 1')

roc2 = alt.Chart(data.loc['lap2'], height=300, width=300).mark_rect().encode(
    alt.X('waist_d_rot_z_center',
          bin=alt.Bin(maxbins=40),
          scale=alt.Scale(domain=xscl),
          axis=alt.Axis(title=xtitle)
         ),
    alt.Y('torso_d_rot_z_center',
          bin=alt.Bin(maxbins=40),
          scale=alt.Scale(domain=yscl),
          axis=alt.Axis(title=ytitle)
         ),
    alt.Color('power:Q', scale=alt.Scale(domain=[0, 600], scheme='greenblue'))
).properties(title='Lap 2')

roc3 = alt.Chart(data.loc['lap3'], height=300, width=300).mark_rect().encode(
    alt.X('waist_d_rot_z_center',
          bin=alt.Bin(maxbins=40),
          scale=alt.Scale(domain=xscl),
          axis=alt.Axis(title=xtitle)
         ),
    alt.Y('torso_d_rot_z_center',
          bin=alt.Bin(maxbins=40),
          scale=alt.Scale(domain=yscl),
          axis=alt.Axis(title=ytitle)
         ),
    alt.Color('power:Q', scale=alt.Scale(domain=[0, 600], scheme='greenblue'))
).properties(title='Lap 3')

roc1xmean = alt.Chart(data.loc['lap1']).mark_rule(color='red').encode(
    x='mean(waist_d_rot_z_center):Q',
    size=alt.value(1)
)

roc1ymean = alt.Chart(data.loc['lap1']).mark_rule(color='red').encode(
    y='mean(torso_d_rot_z_center):Q',
    size=alt.value(1)
)

roc2xmean = alt.Chart(data.loc['lap2']).mark_rule(color='red').encode(
    x='mean(waist_d_rot_z_center):Q',
    size=alt.value(1)
)

roc2ymean = alt.Chart(data.loc['lap2']).mark_rule(color='red').encode(
    y='mean(torso_d_rot_z_center):Q',
    size=alt.value(1)
)

roc3xmean = alt.Chart(data.loc['lap3']).mark_rule(color='red').encode(
    x='mean(waist_d_rot_z_center):Q',
    size=alt.value(1)
)

roc3ymean = alt.Chart(data.loc['lap3']).mark_rule(color='red').encode(
    y='mean(torso_d_rot_z_center):Q',
    size=alt.value(1)
)

(roc1 + roc1xmean + roc1ymean) | (roc2 + roc2xmean + roc2ymean) | (roc3 + roc3xmean + roc3ymean)
Out[31]: