import numpy as np
import matplotlib.pyplot as plt
import math as m
import json
import python_files.space as sp
from python_files.data_extracter import json_extracter
import pandas as pd
data,events=json_extracter('data/match1_1_4.json')
In the notebook 1_Introduction_to_space_occupation, we introduced metrics to compute visualization of space occupation and we visually compared our two metrics $\delta_d$ and $\delta_t$. Now we want to go further than just qualitative aspect.
To evaluate quantitatively how a team occupy the court, we integrate functions $\delta_d(x,y)$ and $\delta_t(x,y)$ on the basketball court.
def teams_occupation(events,event_id,mom_id,n=50,p=94):
event=events[event_id]
moment=event['moments'][mom_id]
moment1=moment
moment2=event['moments'][mom_id+1]
# separation of ball, team1 and team2 and calculation of the speed
mom_infos=sp.players_ball_speed_position(moment1,moment2)
DELTA_D=0
for i in range(n):
for j in range(p):
b=np.array([j,i]) # point d'arrivée
dmin_1=np.inf
for player in mom_infos['team1'].keys():
a=mom_infos['team1'][player]['xy']
d=sp.distance(a,b)
if d<dmin_1:
dmin_1=d
dmin_2=np.inf
for player in mom_infos['team2'].keys():
a=mom_infos['team2'][player]['xy']
d=sp.distance(a,b)
if d<dmin_2:
dmin_2=d
DELTA_D+=dmin_1-dmin_2
return(DELTA_D)
def teams_occupation_inertia(events,event_id,mom_id,n=50,p=94):
event=events[event_id]
moment=event['moments'][mom_id]
moment1=moment
moment2=event['moments'][mom_id+1]
# separation of ball, team1 and team2 and calculation of the speed
mom_infos=sp.players_ball_speed_position(moment1,moment2)
DELTA_T=0
for i in range(n):
for j in range(p):
b=np.array([j,i]) # point d'arrivée
tmin_1=np.inf
for player in mom_infos['team1'].keys():
a=mom_infos['team1'][player]['xy']
v=mom_infos['team1'][player]['v']
t=sp.time_to_point(a,b,v)
if t<tmin_1:
tmin_1=t
tmin_2=np.inf
for player in mom_infos['team2'].keys():
a=mom_infos['team2'][player]['xy']
v=mom_infos['team2'][player]['v']
t=sp.time_to_point(a,b,v)
if t<tmin_2:
tmin_2=t
DELTA_T+=tmin_1-tmin_2
return(DELTA_T)
def running_mean(x, N):
cumsum = np.cumsum(np.insert(x, 0, 0))
return (cumsum[N:] - cumsum[:-N]) / N
def court_evolution(events,event_id):
event=events[event_id]
moments=event['moments']
times=[0 for i in range(len(moments)-1)]
list_DELTA_D=[0 for i in range(len(moments)-1)]
list_DELTA_T=[0 for i in range(len(moments)-1)]
for mom_id in range(len(moments)-1):
if mom_id%10==0:
print(mom_id)
dt=moments[mom_id][2]-moments[mom_id+1][2]
if mom_id==0:
times[mom_id]=dt
else :
times[mom_id]=times[mom_id-1]+dt
if sp.test_moment(moments[mom_id]) and sp.test_moment(moments[mom_id+1]):
list_DELTA_D[mom_id]=teams_occupation(events,event_id,mom_id)
list_DELTA_T[mom_id]=teams_occupation_inertia(events,event_id,mom_id)
else:
list_DELTA_D[mom_id]=list_DELTA_D[mom_id-1]
list_DELTA_T[mom_id]=list_DELTA_T[mom_id-1]
fig, ax1 = plt.subplots(1,1,figsize=(4.5,3))
ax2 = ax1.twinx()
ax1.plot(times, list_DELTA_D, 'r-')
ax2.plot(times[:-2], running_mean(list_DELTA_T,3), 'b-')
ax1.set_xlabel('times [s]')
ax1.set_ylabel(r'$\sum(\delta_{space}(x,y))(t)$ [feets]', color='r')
ax2.set_ylabel(r'$\sum(\delta_{time}(x,y))(t)$ [s]', color='b')
plt.show()
plt.plot
court_evolution(events,50)
0 10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 170 180 190 200 210 220 230 240 250 260 270 280 290 300 310 320
We can see that both metrics reveal the same trend but with a delay in the time. The red curve seems to be late (about 1s). We will study this remark in the Study of the delay section.
Now we want to focus on individual space behaviour. Particularly, we would like to know how a player's freespace evolve during the game. Instead of computing the integrale of $\delta_d(x,y)$ and $\delta_t(x,y)$ around the player, we will look at the distance of the closest opponent (or the time it takes for the closest opponent to join the player). This amounts to calculating $\delta_d^*=\delta_d(x_{player},y_{player})$ and $\delta_t^*=\delta_t(x_{player},y_{player})$.
def player_freespace(events,event_id,mom_id,player_id):
event=events[event_id]
moment=event['moments'][mom_id]
delta_d=sp.distance_closest_opponent(moment,player_id)
return(delta_d)
def player_freetime(events,event_id,mom_id,player_id):
event=events[event_id]
moment1=event['moments'][mom_id]
moment2=event['moments'][mom_id+1]
delta_t=sp.time_closest_opponent(moment1,moment2,player_id)
return(delta_t)
def player_freespace_evolution(events,event_id,player_id):
event=events[event_id]
moments=event['moments']
start=0
dt=moments[start][2]-moments[start+1][2]
while dt<=0 and start<(len(moments)-1):
start+=1
dt=moments[start][2]-moments[start+1][2]
print(start)
times=[0 for i in range(len(moments)-1)]
list_delta_d=[0 for i in range(len(moments)-1)]
list_delta_t=[0 for i in range(len(moments)-1)]
for mom_id in range(start,len(moments)-1):
dt=moments[mom_id][2]-moments[mom_id+1][2]
if mom_id==0:
times[mom_id]=dt
else :
times[mom_id]=times[mom_id-1]+dt
if sp.test_moment(moments[mom_id]) and sp.test_moment(moments[mom_id+1]):
list_delta_d[mom_id]=player_freespace(events,event_id,mom_id,player_id)
list_delta_t[mom_id]=player_freetime(events,event_id,mom_id,player_id)
else:
list_delta_d[mom_id]=list_delta_d[mom_id-1]
list_delta_t[mom_id]=list_delta_t[mom_id-1]
fig, ax1 = plt.subplots(1,1,figsize=(6,4))
ax2 = ax1.twinx()
ax1.plot(times[start:], list_delta_d[start:], 'r-')
ax2.plot(times[start:-2], running_mean(list_delta_t[start:],3), 'b-')
ax1.set_xlabel('times [s]',fontsize='large')
ax1.set_ylabel(r'$\delta_{space}^*(t)$ [feets]', color='r',fontsize='large')
ax2.set_ylabel(r'$\delta_{time}^*(t)$ [s]', color='b',fontsize='large')
plt.show()
plt.plot
Let's see which player are present on the court at that time :
def players_description(event):
print('home : ',event['home']['name'],'\n')
print(event['home']['players'],'\n')
print('visitor : ',event['visitor']['name'],'\n')
print(event['visitor']['players'])
def players_on_the_court(events,event_id):
event=events[event_id]
moments=event['moments']
mom_id=140
moment=moments[mom_id][5]
print(moment)
sp.print_court_teams_occupation(events,event_id,mom_id,player_info=True)
players_on_the_court(events,50)
[[-1, -1, 52.6259, 31.22923, 4.03216], [1610612764, 2400, 72.29266, 17.02516, 0.0], [1610612764, 2403, 77.91741, 37.50651, 0.0], [1610612764, 202322, 82.03219, 8.25018, 0.0], [1610612764, 203078, 54.97599, 49.75136, 0.0], [1610612764, 203490, 52.6547, 30.742, 0.0], [1610612759, 1938, 60.31959, 31.13308, 0.0], [1610612759, 2564, 73.95654, 18.9506, 0.0], [1610612759, 200746, 79.01342, 36.17024, 0.0], [1610612759, 201988, 82.72768, 9.45229, 0.0], [1610612759, 202695, 59.62278, 43.0901, 0.0]]
We see that the player who has the ball is the player 10 with the ID 202695. Let's see which player he is.
players_description(events[50])
home : Washington Wizards [{'lastname': 'Gooden', 'firstname': 'Drew', 'playerid': 2400, 'jersey': '90', 'position': 'F'}, {'lastname': 'Hilario', 'firstname': 'Nene', 'playerid': 2403, 'jersey': '42', 'position': 'F-C'}, {'lastname': 'Humphries', 'firstname': 'Kris', 'playerid': 2743, 'jersey': '43', 'position': 'F'}, {'lastname': 'Gortat', 'firstname': 'Marcin', 'playerid': 101162, 'jersey': '13', 'position': 'C'}, {'lastname': 'Dudley', 'firstname': 'Jared', 'playerid': 201162, 'jersey': '1', 'position': 'G-F'}, {'lastname': 'Sessions', 'firstname': 'Ramon', 'playerid': 201196, 'jersey': '7', 'position': 'G'}, {'lastname': 'Blair', 'firstname': 'DeJuan', 'playerid': 201971, 'jersey': '45', 'position': 'C-F'}, {'lastname': 'Temple', 'firstname': 'Garrett', 'playerid': 202066, 'jersey': '17', 'position': 'G'}, {'lastname': 'Wall', 'firstname': 'John', 'playerid': 202322, 'jersey': '2', 'position': 'G'}, {'lastname': 'Neal', 'firstname': 'Gary', 'playerid': 202390, 'jersey': '14', 'position': 'G'}, {'lastname': 'Beal', 'firstname': 'Bradley', 'playerid': 203078, 'jersey': '3', 'position': 'G'}, {'lastname': 'Porter', 'firstname': 'Otto', 'playerid': 203490, 'jersey': '22', 'position': 'F'}, {'lastname': 'Oubre', 'firstname': 'Kelly', 'playerid': 1626162, 'jersey': '12', 'position': 'F'}] visitor : San Antonio Spurs [{'lastname': 'Duncan', 'firstname': 'Tim', 'playerid': 1495, 'jersey': '21', 'position': 'C-F'}, {'lastname': 'Ginobili', 'firstname': 'Manu', 'playerid': 1938, 'jersey': '20', 'position': 'G'}, {'lastname': 'Parker', 'firstname': 'Tony', 'playerid': 2225, 'jersey': '9', 'position': 'G'}, {'lastname': 'Butler', 'firstname': 'Rasual', 'playerid': 2446, 'jersey': '18', 'position': 'F'}, {'lastname': 'West', 'firstname': 'David', 'playerid': 2561, 'jersey': '30', 'position': 'F'}, {'lastname': 'Diaw', 'firstname': 'Boris', 'playerid': 2564, 'jersey': '33', 'position': 'C-F'}, {'lastname': 'Aldridge', 'firstname': 'LaMarcus', 'playerid': 200746, 'jersey': '12', 'position': 'F'}, {'lastname': 'Green', 'firstname': 'Danny', 'playerid': 201980, 'jersey': '14', 'position': 'G-F'}, {'lastname': 'Mills', 'firstname': 'Patty', 'playerid': 201988, 'jersey': '8', 'position': 'G'}, {'lastname': 'Leonard', 'firstname': 'Kawhi', 'playerid': 202695, 'jersey': '2', 'position': 'F'}, {'lastname': 'McCallum', 'firstname': 'Ray', 'playerid': 203492, 'jersey': '3', 'position': 'G'}, {'lastname': 'Anderson', 'firstname': 'Kyle', 'playerid': 203937, 'jersey': '1', 'position': 'F'}, {'lastname': 'Marjanovic', 'firstname': 'Boban', 'playerid': 1626246, 'jersey': '40', 'position': 'C'}]
It's Kawhi Leonard. Let's see his freespace evolution during this action
player_freespace_evolution(events,50,202695)
125
As for teams occupation, comparing player's freespace (distance to his closest opponent) and player's freetime (time needed for his closest opponent to reach him) reveals a delay close to 0.3-0.5s. We are going to quantify these delays in the following section.
Firstly, as occupation-map generated with $\delta_t$ seems to lag occupation-map generated with $\delta_t$, let's draw these shifted maps for a few moments to see if they fit better.
data,events=json_extracter('data/game1.json')
plt.figure(1)
plt.title('Space occupation taking intertia into account')
sp.print_court_teams_occupation_inertia(events,0,25)
plt.figure(2)
plt.title('Previous space occpuation')
sp.print_court_teams_occupation(events,0,25,value=True)
plt.figure(3)
plt.title('Previous space occpuation')
sp.print_court_teams_occupation(events,0,40,value=True)
Description of these 3 different plots :
We see that occupation-map 3 best fits with 1 than 2 as expected with our precedent remark. Let's quantify this delay. To do so, we calculate the correlation between the occupation-map generated with $\delta_{space}$ and the occupation-map generated with $\delta_{time}$. Moreover, as force is the factor that can change in our study, we calculate the correlation for different forces and then we look the evolution of the correlation in function of forces. The calculation of the correlation is available in the folder python_files and is called lag_study.py.
import pandas as pd
lags=pd.read_csv('data/total_df_final.csv',sep = ',',index_col=[0,1,2])
lags.dropna(inplace=True)
lags.head(10)
R | tau | rho | time | |||
---|---|---|---|---|---|---|
Unnamed: 0.1 | Unnamed: 2 | |||||
1 | 2 | 0 | 0.063110 | 77 | 0.379596 | 20.47 |
1 | 0.064491 | 77 | 0.379596 | 20.47 | ||
2 | 0.065823 | 77 | 0.379596 | 20.47 | ||
3 | 0.067178 | 77 | 0.379596 | 20.47 | ||
4 | 0.068361 | 77 | 0.379596 | 20.47 | ||
5 | 0.069243 | 77 | 0.379596 | 20.47 | ||
6 | 0.070035 | 77 | 0.379596 | 20.47 | ||
7 | 0.070769 | 77 | 0.379596 | 20.47 | ||
8 | 0.071682 | 77 | 0.379596 | 20.47 | ||
9 | 0.072152 | 77 | 0.379596 | 20.47 |
Time of the study
First we look at the correlation max function of the force.
df=lags[['rho','time']].max(level=(0,1))
df.head(10)
df.loc[1]['time'].sum()
593.77
rho_mean=df[['rho']].mean(level=(0))
rho_mean.plot()
<matplotlib.axes._subplots.AxesSubplot at 0x121a65748>
Let's drop too big values of f to see more details. Let's also plot the deviation
fig, ax = plt.subplots()
rho_mean=df.drop([50,100,1000])[['rho']].mean(level=(0))
rho_std=df.drop([50,100,1000])[['rho']].std(level=(0))
rho_mean.plot(yerr=rho_std, ax=ax)
plt.xlabel('forces per unit of mass')
plt.ylabel('maximum of correlation')
<matplotlib.text.Text at 0x11dcb12e8>
Let's make an average for each force weighed by the time of the sequence.
import numpy as np
def weighted(row, cols, w="time"):
return (np.average(row[cols], weights=row[w]))
rho_mean_w=df.drop([50,100,1000]).groupby(level=0).apply(weighted, cols='rho', w='time')
fig, ax = plt.subplots()
rho_mean.plot(yerr=rho_std, ax=ax, color='b', label='mean')
rho_mean_w.plot(ax=ax, color='r', label='weighted mean')
plt.xlabel('forces per unit of mass')
plt.ylabel('maximum of correlation')
plt.legend()
<matplotlib.legend.Legend at 0x11dabe400>
We can see that there are little differences when weighted the mean.
fig, ax = plt.subplots()
rho_mean.plot(yerr=rho_std, ax=ax, legend=False)
x=np.arange(1,12,1)
x2=np.arange(5,31,1)
y=0.095783*x+0.143866
y2=1+0*x2
plt.xlabel('force N/kg')
plt.ylabel(r'$<\rho_{max}$>')
plt.ylim(top=1)
(0.082357099357977248, 1)
It seems that for 10N/kg, the increase decreases.
df=lags[['tau','time']].max(level=(0,1))
df['tau']=df['tau']*0.04
fig, ax = plt.subplots()
tau_mean=df[['tau']].mean(level=(0))
tau_mean.plot(ax=ax)
plt.xlabel('force N/kg')
plt.ylabel(r'$\tau [s]$')
plt.legend()
<matplotlib.legend.Legend at 0x11e3fc908>
fig, ax = plt.subplots()
tau_mean=df.drop([50,100,1000])[['tau']].mean(level=(0))
tau_std=df.drop([50,100,1000])[['tau']].std(level=(0))
tau_mean.plot(yerr=tau_std, ax=ax)
plt.xlabel('force N/kg')
plt.ylabel(r'$\tau [s]$')
plt.legend()
<matplotlib.legend.Legend at 0x11cfe22b0>
tau_mean_w=df.drop([50,100,1000]).groupby(level=0).apply(weighted, cols='tau', w='time')
fig, ax = plt.subplots()
tau_mean.plot(yerr=tau_std, ax=ax, color='b', label='mean')
tau_mean_w.plot(ax=ax, color='r', label='weighted mean')
plt.xlabel('force N/kg')
plt.ylabel(r'$\tau [s]$')
plt.legend()
<matplotlib.legend.Legend at 0x12af61f60>
fig, ax = plt.subplots()
Rho=lags[['R']].mean(level=(0,2))
ind=[1,2,5,10,15,30,50,100]
for i in ind:
time=lags.loc[(1,2)].index*0.04
plt.plot(time,Rho.loc[i],label=str(i))
plt.legend()
bbox_props = dict(boxstyle="larrow,pad=0.5",fc='None')
plt.text(1.7, 0.15, "Force increase", ha="center", va="center", rotation=-45,
size=10,
bbox=bbox_props)
plt.xlabel(r'$\tau$ [s]')
plt.ylabel(r'$<\rho(\tau)$>')
/Users/gabin/anaconda/lib/python3.6/site-packages/ipykernel_launcher.py:5: PerformanceWarning: indexing past lexsort depth may impact performance. """
<matplotlib.text.Text at 0x121aeeb38>
df=lags[['tau','time']].max(level=(0,1))
tau_mean=df[['tau']].mean(level=(0))
tau_mean.loc[10]
tau 33.030303 Name: 10, dtype: float64
Let's test visually the result : for a force of 10N/kg, the delay is closed to 33 moments, it means that if we want to test visually we have to shift distance court of 33 moments. Let's test as we did precedently by generating the following figures :
plt.figure(1)
plt.title('Previous space occpuation')
sp.print_court_teams_occupation(events,0,25,value=True)
plt.figure(2)
plt.title('Space occupation taking intertia into account')
sp.print_court_teams_occupation_inertia(events,0,25)
plt.figure(3)
plt.title('Previous space occpuation')
sp.print_court_teams_occupation(events,0,58,value=True)
Let's look at the delay between $\delta_{space}^*$ (distance to the closest opponent) and $\delta_{time}^*$ (time needed by the closest opponent to join shooter's position) calculating the correlation between both metrics 3 seconds before 3-point shots (see 4_Free_space_and_3-points_efficiency for more details).
import pickle
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
#dico=pickle.load(open('data/Shots','rb'))
df=pd.read_csv('data/df_plot_mean.csv',index_col=[0])
/Users/gabin/opt/anaconda3/lib/python3.7/site-packages/numpy/lib/arraysetops.py:568: FutureWarning: elementwise comparison failed; returning scalar instead, but in the future will perform elementwise comparison mask |= (ar1 == a)
df=df.query('Time>-3. and Time<0.8')
def aggregating_04(row):
number=row['Time']
q=number//0.04
if abs(round((q*0.04-number),2))<=0.02:
return(q*0.04)
else :
return((q+1)*0.04)
df['Time']=df.apply(aggregating_04,axis=1)
df2=df.groupby('Time').mean()
df2=df2.sort_index()
df2
D | T | Time_to_shoot | Shot result | player_id | x_ball | y_ball | z_ball | x_shooter | y_shooter | quarter | clock | Match_id | shot_id | btpl | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Time | |||||||||||||||
-3.00 | 10.366918 | 0.813007 | -1.749647 | 0.344728 | 232271.581949 | 46.752533 | 24.903003 | 3.556769 | 46.882882 | 25.333581 | 2.562460 | 340.494706 | 322.750319 | 14565.437859 | True |
-2.96 | 10.416046 | 0.814531 | -1.732531 | 0.349235 | 227207.539811 | 46.723435 | 24.882112 | 3.536729 | 46.874698 | 25.097832 | 2.536603 | 345.973889 | 322.458231 | 14554.550227 | True |
-2.92 | 10.438107 | 0.815225 | -1.733182 | 0.348754 | 227041.804875 | 46.677801 | 24.866675 | 3.527409 | 46.838773 | 25.089884 | 2.536625 | 345.936536 | 322.901007 | 14574.930481 | True |
-2.88 | 10.479872 | 0.816914 | -1.733758 | 0.348460 | 227010.133094 | 46.745345 | 24.864986 | 3.525486 | 46.903535 | 25.085358 | 2.538725 | 345.494022 | 322.511191 | 14556.944602 | True |
-2.84 | 10.517742 | 0.818556 | -1.733243 | 0.348720 | 227073.348310 | 46.700358 | 24.857652 | 3.522707 | 46.842717 | 25.058195 | 2.537748 | 345.426979 | 322.623708 | 14562.123502 | True |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
0.64 | 3.975171 | 0.564119 | -1.823955 | 0.347666 | 228079.644382 | 46.806190 | 25.057423 | 15.478861 | 46.915478 | 25.072045 | 2.537042 | 346.294921 | 323.238309 | 14590.396028 | True |
0.68 | 4.035244 | 0.572019 | -1.823386 | 0.347538 | 228225.080245 | 46.785424 | 25.051417 | 15.511513 | 46.915326 | 25.069470 | 2.537897 | 346.316165 | 323.187276 | 14588.351039 | True |
0.72 | 4.116920 | 0.579561 | -1.823484 | 0.347510 | 228294.056948 | 46.784660 | 25.047413 | 15.494501 | 46.913842 | 25.065668 | 2.538669 | 346.295889 | 323.231331 | 14590.433180 | True |
0.76 | 4.210021 | 0.587075 | -1.821663 | 0.347493 | 228058.044993 | 46.784112 | 25.046060 | 15.428982 | 46.923403 | 25.066747 | 2.538198 | 346.471467 | 323.117087 | 14585.196643 | True |
0.80 | 4.324504 | 0.597612 | -1.880885 | 0.349565 | 247503.360696 | 47.186133 | 25.013298 | 15.441838 | 47.217408 | 25.013236 | 2.508290 | 342.004899 | 324.644870 | 14655.135652 | True |
96 rows × 15 columns
def autocorrel(x,y,N,i,M):
#print(M)
C = np.zeros(N)
for k in range(i,M):
for n in range(N):
C[n] += x[k]*y[k-n]
#print(C)
return C/M
def tau(df):
times=list(df.index)
times=np.sort(times)
b,c=0,0
Ns=len(df2['D'].values)
x=df2['D'].values.copy()
y=df2['T'].values.copy()
N=50
a=autocorrel(x-np.mean(x),y-np.mean(y),N,N,Ns)
for k in range(len(x)):
x[k]=(x[k]-np.mean(x))*(x[k]-np.mean(x))
for k in range(len(y)):
y[k]=(y[k]-np.mean(y))*(y[k]-np.mean(y))
b=np.sqrt(np.mean(x))
c=np.sqrt(np.mean(y))
a=a/(b*c)
maxa=max(a)
abscisses=[0.04*k for k in range(N)]
for k in range(len(a)):
if a[k]==maxa:
tau_max=k*0.04
print('valeur max atteinte pour tau=',k*0.04)
plt.plot(abscisses,a)
plt.vlines(tau_max, ymin=-1,ymax=maxa, linestyle="dashed", color='black')
plt.ylim(bottom=-0.15,top=0.28)
plt.xlabel(r'$\tau$ [s]')
plt.ylabel(r'$<\rho(\tau)$>')
tau(df2)
0.2655698251546643 0.26497265786834706 valeur max atteinte pour tau= 0.28
fig,ax=plt.subplots(2,1)
t=df2.index
x=df2['D'].values.copy()
y=df2['T'].values.copy()
ax[0].plot(t,x)
ax[1].plot(t,y)
[<matplotlib.lines.Line2D at 0x829bf7750>]
We see that before a 3-point shot, there is a delay of 0.32s between $<\delta_{space}^*>$ and $<\delta_{time}^*>$. This value is little but in basketball dynamics it is an important amount of time. Indeed, for example, it takes 0.5 on average for a player to attempt a shot.