T0 = -4.4 # the clip starts with everyone set in the shotgun formation
def philly_special():
"""Every body keyframed by hand: (t, d, w) waypoints, t in seconds from the snap."""
off = line5() + [O("QB", "QB", -4.2, 0.0, "Q"), O("RB", "RB", -4.3, 1.9, "R"),
O("Z", "WR", LINE_D, -7.4, "Z"), O("Y", "TE", -2.6, -7.4, "Y"),
O("U", "TE", -1.6, -5.4, "U"), O("X", "WR", LINE_D, 12.0, "X")]
dfn = [D("LE", "DE", 0.8, -4.4, "E"), D("LT_", "DT", 0.8, -0.9, "T"), D("RT_", "DT", 0.8, 0.9, "T"),
D("RE", "DE", 0.8, 4.4, "E"), D("MIKE", "LB", 2.3, -1.4, "M"), D("WILL", "LB", 2.2, 3.3, "W"),
D("LCB", "CB", 1.8, -9.0, "CB"), D("NB", "NB", 2.8, -6.4, "$"), D("SS", "SS", 4.2, -3.4, "SS"),
D("RCB", "CB", 1.6, 12.0, "CB"), D("FS", "FS", 6.4, 1.2, "FS")]
p = Play(off, dfn, los=opp(1), to_go=1)
T = {
# Foles: shotgun, then (after Clement's motion) walks up behind the right tackle and is set from -1.6,
# more than the full second the rules require after a shift; at the snap he waits, then drifts right
"QB": [(-3.0, -4.2, 0.0), (-1.6, -1.9, 3.9), (0.7, -1.9, 3.9), (1.2, -1.0, 5.3), (1.9, 1.4, 5.7),
(2.5, 2.7, 5.9)],
# Clement: motions from beside Foles to directly behind him, then takes the direct snap and runs left
"RB": [(-4.0, -4.3, 1.9), (-3.2, -6.0, 0.0), (0.0, -6.0, 0.0), (0.35, -5.9, -0.5), (0.7, -6.0, -2.0),
(1.0, -6.0, -3.4), (1.6, -5.6, -6.4), (2.2, -5.2, -7.6)],
# Burton: drops back from behind Smith and comes across DEEPER than Clement, so the pitch goes backward
"Y": [(0.0, -2.6, -7.4), (0.5, -4.6, -6.6), (1.0, -7.4, -4.2), (1.3, -7.5, -1.6), (1.7, -7.0, 1.2),
(2.0, -6.3, 3.2), (2.6, -5.9, 4.0)],
# Smith: across the end zone as the second option; Ertz seals the left end; Jeffery takes his corner deep
"Z": [(0.0, LINE_D, -7.4), (0.6, 1.6, -6.6), (1.3, 4.4, -3.0), (2.0, 5.6, 0.0), (2.6, 5.9, 1.4)],
"U": [(0.0, -1.6, -5.4), (0.5, -0.5, -5.3)],
"X": [(0.0, LINE_D, 12.0), (0.8, 3.4, 11.6), (1.6, 7.4, 9.8), (2.6, 8.6, 8.4)],
"LT": [(0.0, LINE_D, -3.2), (0.4, -0.5, -3.2)], "LG": [(0.0, LINE_D, -1.6), (0.4, -0.5, -1.6)],
"C": [(0.0, LINE_D, 0.0), (0.4, -0.5, 0.0)], "RG": [(0.0, LINE_D, 1.6), (0.4, -0.5, 1.6)],
"RT": [(0.0, LINE_D, 3.2), (0.4, -0.5, 3.2)],
# the defense: everyone near the ball flows left with the run; the right end rushes upfield past
# Foles toward the ball; the backside players lose Foles
"LE": [(0.0, 0.8, -4.4), (0.5, 0.9, -4.9)],
"LT_": [(0.0, 0.8, -0.9), (0.4, 0.75, -0.9)], "RT_": [(0.0, 0.8, 0.9), (0.4, 0.75, 0.9)],
"RE": [(0.0, 0.8, 4.4), (0.6, 0.0, 5.6), (1.1, -2.6, 7.6), (2.0, -4.6, 6.8), (2.6, -5.0, 5.8)],
"MIKE": [(0.0, 2.3, -1.4), (0.8, 2.0, -3.4), (1.3, 1.9, -3.6), (2.0, 1.8, -2.0), (2.6, 2.2, -0.2)],
"WILL": [(0.0, 2.2, 3.3), (0.7, 1.9, 1.8), (1.4, 2.1, 1.0), (2.0, 2.0, 1.3), (2.6, 2.0, 1.6)],
"LCB": [(0.0, 1.8, -9.0), (0.6, 3.4, -8.4), (1.3, 3.0, -4.4), (2.0, 4.2, -1.4), (2.6, 4.6, -0.2)],
"NB": [(0.0, 2.8, -6.4), (0.7, 1.2, -8.4), (1.2, 0.4, -8.2), (1.9, 1.4, -6.6), (2.6, 2.3, -5.2)],
"SS": [(0.0, 4.2, -3.4), (0.7, 4.6, -5.2), (1.3, 4.6, -5.6), (1.9, 3.8, -3.6), (2.6, 3.4, -2.0)],
"RCB": [(0.0, 1.6, 12.0), (0.8, 3.6, 13.2), (1.6, 7.4, 11.4), (2.6, 8.8, 10.0)],
"FS": [(0.0, 6.4, 1.2), (0.8, 6.2, 0.0), (1.6, 6.2, 1.0), (2.6, 5.8, 3.0)],
}
set_tracks(p, {k: ease([(T0, p.players[k].d, p.players[k].w)] + v) for k, v in T.items()}, t_first=T0)
return p
BALL_OFF = np.array([-0.55, 0.95]) # the ball is drawn beside the carrier, never on his letter
T_PITCH, T_CATCH_PITCH, T_THROW, T_CATCH = 1.0, 1.15, 2.0, 2.55
def ps_ball_at(p, t):
"""Where the ball is: on the ground at the snap, then to Clement, Burton and Foles in turn."""
if t <= 0.0:
return np.array([0.0, 0.0])
if t < 0.35:
return (p.position("RB", 0.35) + BALL_OFF) * t / 0.35
if t < T_PITCH:
return p.position("RB", t) + BALL_OFF
if t < T_CATCH_PITCH:
a, b = p.position("RB", T_PITCH) + BALL_OFF, p.position("Y", T_CATCH_PITCH) + BALL_OFF
return a + (b - a) * (t - T_PITCH) / (T_CATCH_PITCH - T_PITCH)
if t < T_THROW:
return p.position("Y", t) + BALL_OFF
if t < T_CATCH:
a, b = p.position("Y", T_THROW) + BALL_OFF, p.position("QB", T_CATCH) + BALL_OFF
return a + (b - a) * (t - T_THROW) / (T_CATCH - T_THROW)
return p.position("QB", t) + BALL_OFF
def ghost(fld, p, d, w, letter):
"""A dashed outline where a player started before the snap."""
x, y = P(fld, p, d, w)
r = 0.62
fld.ax.add_patch(Ellipse((float(x), float(y)), 2 * r, 2 * r, fc="none", ec=style.OFFENSE, lw=1.0,
ls=(0, (2, 1.5)), zorder=3))
fld.ax.text(float(x), float(y), letter, ha="center", va="center", fontsize=6.0, color=style.OFFENSE,
fontweight="bold", zorder=3)
def ps_deco(t, fld, p):
"""End-zone label; before the snap the shotgun spots and the dashed pre-snap moves; after it, the
ball, the backward pitch and the throw (brown dashes)."""
say(fld, p, 10.2, -4.5, "END ZONE", color=style.INK_2, fontsize=6.4, box=False)
if t <= 0.0:
for k, a, b in (("RB", -4.0, -3.2), ("QB", -3.0, -1.6)):
q = p.players[k]
ghost(fld, p, q.d, q.w, q.label)
if t > a:
pts = np.array([p.position(k, tt) for tt in np.linspace(a, min(t, b), 20)])
xs, ys = P(fld, p, pts[:, 0], pts[:, 1])
fld.ax.plot(xs, ys, color=style.OFFENSE, lw=1.3, ls=(0, (3, 2)), zorder=4)
return # before the snap the ball is under the center's hand
if T_PITCH < t < 1.8:
a, b = p.position("RB", T_PITCH) + BALL_OFF, p.position("Y", T_CATCH_PITCH) + BALL_OFF
branch(fld, p, [tuple(a), tuple(b)], color=style.BALL, lw=1.4, dash=(0, (2, 1.5)), z=9)
if True:
point_to(fld, p, (-8.9, -6.6), tuple((a + b) / 2), "pitch goes backward,\nso Burton may throw",
color=style.INK_2, fontsize=6.2)
if t > T_THROW:
a = p.position("Y", T_THROW) + BALL_OFF
ts = np.linspace(T_THROW, min(t, T_CATCH), 12)
b = np.array([ps_ball_at(p, tt) for tt in ts])
xs, ys = P(fld, p, np.r_[a[0], b[:, 0]], np.r_[a[1], b[:, 1]])
fld.ax.plot(xs, ys, color=style.BALL, lw=1.4, ls=(0, (2, 1.5)), zorder=9)
bd, bw = ps_ball_at(p, t)
x, y = P(fld, p, bd, bw)
fld.ax.add_patch(Ellipse((float(x), float(y)), 0.95, 0.6, fc=style.BALL, ec="white", lw=0.6, zorder=12))
PS = philly_special()
PS_T = [-1.0, 0.6, 1.45, 2.6]
PS_N = ["Foles has walked up from the shotgun\nand is set behind the right tackle.",
"Direct snap to Clement, who runs\nleft. The defense flows with him.",
"Clement pitches back to Burton. The\nend (E) rushes past Foles to the ball.",
"Burton throws to Foles, alone in\nthe end zone. Touchdown."]
PS_LAT, PS_WIN = (-12.5, 15.5), (-11.0, 12.0)
PS_LEG = [Line2D([], [], color=style.OFFENSE, lw=1.3, ls=(0, (3, 2)), label="move before the snap"),
Line2D([], [], marker="o", ls="", ms=8, mfc="none", mec=style.OFFENSE, label="where he started"),
Line2D([], [], color=style.OFFENSE, lw=1.0, alpha=0.5, label="path since the snap"),
Line2D([], [], marker="o", ls="", ms=6, mfc=style.BALL, mec="white", label="the ball"),
Line2D([], [], color=style.BALL, lw=1.4, ls=(0, (2, 1.5)), label="pitch or pass"),
LEGEND["ring"]]
if PDF:
fig = strip_grid(PS, PS_T, PS_N, PS_LAT, PS_WIN, rings=(("QB", style.THIRD),), deco=ps_deco, ltg=False,
mr=0.62)
fig.legend(handles=PS_LEG, loc="upper center", bbox_to_anchor=(0.5, 0.0), ncol=3, fontsize=7,
frameon=False, handlelength=2.0, columnspacing=1.4)
plt.show()
else:
video(PS, PS_LAT, PS_WIN, 2.9, rings=(("QB", style.THIRD),), t_start=T0, deco=ps_deco, ltg=False, mr=0.62,
notes=["Shotgun. Clement motions from beside Foles to behind him.",
"Foles walks up behind the right tackle, as if changing the play, and sets."] + PS_N[1:],
times=[T0, -3.0, 0.6, 1.05, 2.0])