1. 首页
  2. 数据分析

如何运用Python绘制NBA投篮图表

大数据文章作品,欢迎转发到朋友圈,转载请后台留言申请授权!

翻译|丁雪 丁一 席雄芬

校对|姚佳灵

我在本文中将介绍如何获取一个选手的投篮数据并通过matplotlib seaborn制成图表。

In [1]: %matplotlib inline

import requests

importmatplotlib.pyplot as plt

import pandas aspd

import seabornas sns

获取数据

stats.nba.com获取的数据是非常简单的。虽然NBA没有提供公共的API ,我们实际上可以通过requests 库来访问NBAstats.nba.com所使用的APIGreg Reda的这篇博客(http://www.gregreda.com/2015/02/15/web-scraping-finding-the-api/)详细讲解了如何访问这个API(或者找到与此类似的任何网页的API )。我们将使用下面程序中提到的网址来获得James Harden的投篮图表数据。

In [2]:shot_chart_url ='http://stats.nba.com/stats/shotchartdetail?CFID=33&CFPAR'

'AMS=2014-15&ContextFilter=&ContextMeasure=FGA&DateFrom=&D'

'ateTo=&GameID=&GameSegment=&LastNGames=0&LeagueID=00&Loca'

'tion=&MeasureType=Base&Month=0&OpponentTeamID=0&Outcome=&'

'PaceAdjust=N&PerMode=PerGame&Period=0&PlayerID=201935&Plu'

'sMinus=N&Position=&Rank=N&RookieYear=&Season=2014-15&Seas'

'onSegment=&SeasonType=Regular+Season&TeamID=0&VsConferenc'

'e=&VsDivision=&mode=Advanced&showDetails=0&showShots=1&sh'

'owZones=0'

上述网址提供给我们的JSON文件包含了我们想要的数据。还要注意的是这个链接包含了用于访问数据的各种API参数。在这个链接中PlayerID参数设置为201935 ,这是James HardenPlayerID

现在让我们用requests来获取我们想要的数据。

In [3]: #获得包含数据的网页

response =requests.get(shot_chart_url)

# 提取用于作为我们表格中列的名称的题头

headers =response.json()['resultSets'][0]['headers']

# 提取投篮数据

shots =response.json()['resultSets'][0]['rowSet']

用提取的投篮数据制作一个 pandas DataFrame

In [4]: shot_df = pd.DataFrame(shots,columns=headers)

# 查看数据表的题头以及所有列

fromIPython.display import display

withpd.option_context('display.max_columns', None):

display(shot_df.head())

以上投篮数据包含了所有的James Harden2014-15赛季常规赛期间的出手投篮。我们需要的数据在LOC_XLOC_Y 里面。这些坐标值对应每一次出手投篮,然后我们可以把这些坐标绘制到一组表示篮球场的轴上。

绘制投篮数据图

让我们只是快速输出数据来看看它的样子。

In [5]: sns.set_style("white")

sns.set_color_codes()

plt.figure(figsize=(12,11))

plt.scatter(shot_df.LOC_X,shot_df.LOC_Y)

plt.show()

如何运用Python绘制NBA投篮图表

请注意,上述图表歪曲了数据。 x轴的值是实际对应值的倒数。让我们只绘制从右侧的投篮图来看看这个问题。

In [6]: right =shot_df[shot_df.SHOT_ZONE_AREA == "Right Side(R)"]

plt.figure(figsize=(12,11))

plt.scatter(right.LOC_X,right.LOC_Y)

plt.xlim(-300,300)

plt.ylim(-100,500)

plt.show()

如何运用Python绘制NBA投篮图表

图上我们可以看到的投篮数据是“右侧”的投篮,而观众的右侧实际上是篮筐的左侧。这是在创建我们最后投篮图时需要注意修改的。

画出篮球场

首先我们需要弄清楚如何在我们的图表中绘制篮球场。通过查看输出的第一个投篮图和数据,我们可以大致估算出篮筐的中心位于原点。我们还可以估计每10个单位在xy轴上表示一英尺。我们可以通过看在DataFrame里的第一个观察值验证证这一点。这次上篮是从右侧底角3点,与LOC_X 226值处距离22英尺。所以这次投篮大约是在离篮筐22.6英尺处发生的。现在我们知道了这一点,就可以在图中画出篮球场了。

篮球场的尺寸可以从下面的图里找到。

如何运用Python绘制NBA投篮图表如何运用Python绘制NBA投篮图表

利用这些维度,我们可以将它们转换成适用于我们图表的尺寸,并使用 Matplotlib Patches画出来。我们将使用圆形,矩形和圆弧来绘制篮球场。现在来创建我们绘制篮球场的方程。

注:虽然可以到使用Lines2D绘制线条,我发现使用Rectangles更方便(没有高度或宽度)。

修正( 201584日):我在绘制外场线和半场弧时犯了一个错误。外场线高度从不正确的442.5改为470。中心球场圆弧的中心的y值从395改到422.5 。图表中的ylim值从( 395 -47.5 )改变为( 422.5 -47.5 )。

In [7]: from matplotlib.patches importCircle, Rectangle, Arc

defdraw_court(ax=None, color='black', lw=2, outer_lines=False):

# 如果没有可绘制的坐标值,则使用现有值

if ax is None:

ax = plt.gca()

# 绘制NBA篮球场的各个部分

# 绘制篮筐

# 篮筐直径18英寸,所以半径为9英寸

# 也就是我们系统里面相应的的7.5

hoop =Circle((0, 0), radius=7.5, linewidth=lw, color=color, fill=False)

# 绘制篮板

backboard =Rectangle((-30, -7.5), 60, -1, linewidth=lw, color=color)

# 场地线

# 绘制外场场地线, =16ft, =19ft

outer_box = Rectangle((-80, -47.5), 160,190, linewidth=lw, color=color,

fill=False)

#绘制内场场地线, =12ft, =19ft

inner_box= Rectangle((-60, -47.5), 120, 190, linewidth=lw, color=color,

fill=False)

# 绘制罚球弧顶部

top_free_throw= Arc((0, 142.5), 120, 120, theta1=0, theta2=180,

linewidth=lw,color=color, fill=False)

# 绘制发球弧底部

bottom_free_throw= Arc((0, 142.5), 120, 120, theta1=180, theta2=0,

linewidth=lw,color=color, linestyle='dashed')

# 限制区,是一个以篮筐为中心,半径为4ft的弧

restricted = Arc((0, 0), 80, 80, theta1=0,theta2=180, linewidth=lw,

color=color)

# Three pointline

# 三分线

# Create theside 3pt lines, they are 14ft long before they begin to arc

# 绘制两边的三分线,它们有14ft 长,之后开始成弧形

corner_three_a = Rectangle((-220, -47.5),0, 140, linewidth=lw,

color=color)

corner_three_b = Rectangle((220, -47.5), 0,140, linewidth=lw, color=color)

# 3pt arc -center of arc will be the hoop, arc is 23'9" away from hoop

# 三分线弧形部分 以篮筐为中心 半径为 23'9" 的弧

# I just playedaround with the theta values until they lined up with the threes

# 我仅仅通过调整 theta值让它们与两边衔接上

three_arc = Arc((0, 0), 475, 475,theta1=22, theta2=158, linewidth=lw,

color=color)

# 场中心

center_outer_arc = Arc((0, 422.5), 120,120, theta1=180, theta2=0,

linewidth=lw,color=color)

center_inner_arc = Arc((0, 422.5), 40, 40,theta1=180, theta2=0,

linewidth=lw,color=color)

# 列出轴上要画的球场的元素

court_elements = [hoop, backboard,outer_box, inner_box, top_free_throw,

bottom_free_throw,restricted, corner_three_a,

corner_three_b,three_arc, center_outer_arc,

center_inner_arc]

if outer_lines:

# 画出半场线,底线和边线

outer_lines = Rectangle((-250, -47.5),500, 470, linewidth=lw,

color=color,fill=False) court_elements.append(outer_lines)

# 把球场部分元素加到轴上

for element in court_elements:

ax.add_patch(element)

return ax

让我们来画出球场吧!

In [8]:plt.figure(figsize=(12,11))

draw_court(outer_lines=True)

plt.xlim(-300,300)

plt.ylim(-100,500)

plt.show()

如何运用Python绘制NBA投篮图表

绘制投篮图

下面让我们根据球场的数据来绘制投篮图。以下有两种方式可以调整x值:一种是把LOC_X的负倒数传入plt.scatter;另一种是把降序的值传入plt.xlim。我们的选择是后者。

In [9]:plt.figure(figsize=(12,11))

plt.scatter(shot_df.LOC_X, shot_df.LOC_Y)

draw_court(outer_lines=True)

#值沿轴从左到右降序排列

plt.xlim(300,-300)

plt.show()

如何运用Python绘制NBA投篮图表

让我们将投篮图上的篮圈移至顶部,与stats.nba.com上随着镜头与统计图表的方向一致。通过从y轴底部到顶部的降序排列的y值,我们实现这个操作。当我们这样做了,便不再需要来调整我们图上的x值。

In [10]: plt.figure(figsize=(12,11))

plt.scatter(shot_df.LOC_X,shot_df.LOC_Y)

draw_court()

#把图的范围调整为半场

plt.xlim(-250,250)

# 沿 y轴从底部到顶部,t值降序排列

# 设置顶部为篮筐的位置

plt.ylim(422.5,-47.5)

#除去轴刻度标签

# plt.tick_参数(标签底部=, 标签左边=False)

plt.show()

如何运用Python绘制NBA投篮图表

让我们用seabornjointplot来绘制几幅投篮图

In [11]:# 创建jointplot

joint_shot_chart= sns.jointplot(shot_df.LOC_X, shot_df.LOC_Y, stat_func=None,

kind='scatter', space=0, alpha=0.5)

joint_shot_chart.fig.set_size_inches(12,11)

# 合成的投篮图有三个轴,第一个命名为ax_joint

# 是我们绘制场地和调整设置的轴

ax =joint_shot_chart.ax_joint

draw_court(ax)

#调整轴范围以便定位投篮图的方向

# 绘制半场图,设置顶部为篮筐的位置

ax.set_xlim(-250,250)

ax.set_ylim(422.5,-47.5)

#除去轴标签和刻度线

ax.set_xlabel('')

ax.set_ylabel('')

ax.tick_params(labelbottom='off',labelleft='off')

#添加标题

ax.set_title('JamesHarden FGA n2014-15 Reg. Season',

y=1.2, fontsize=18)

#添加数据来源与作者

ax.text(-250,445,'DataSource: stats.nba.com'

'nAuthor: Savvas Tjortjoglou(savvastjortjoglou.com)', fontsize=12)

plt.show()

如何运用Python绘制NBA投篮图表

获取选手头像

stats.nba.com网站上获取Jame Harden的头像,放在我们的图里。他的头像是这个:在http://stats.nba.com/media/players/230×185/201935.png,我们可以通过url.requests中的urlretrieve来为我们获取头像

In [12]: import urllib.request

#第一个参数为头像的链接

#第二个参数是我们想要获取的头像

pic =urllib.request.urlretrieve("http://stats.nba.com/media/players/230×185/201935.png",

"201935.png")

#urlretrieve以元组的形式返回我们需要的头像,imread函数以多维数组形式读取图像,这样matplotlib可以绘制图像。

harden_pic =plt.imread(pic[0])

#绘制图像

plt.imshow(harden_pic)

plt.show()

如何运用Python绘制NBA投篮图表

现在要在jointplot上绘制Harden的脸,我们将从matplotlib.Offset导入OffsetImageOffsetImage可以使头像出现在图的右上角。现在,让我们像刚才一样绘制投篮图,但是这次我们将先绘制KDE合成图,最后才添加头像。

In [13]: from matplotlib.offsetboximport OffsetImage

#绘制jointplot

#获取主KDE图的色图

#注意:我们可以从cmap中提取一种颜色用于图的边框和顶轴

cmap=plt.cm.YlOrRd_r

#n_levels 为主KDE图设置轮廓线的数量

joint_shot_chart= sns.jointplot(shot_df.LOC_X, shot_df.LOC_Y, stat_func=None,

kind='kde',space=0, color=cmap(0.1),

cmap=cmap,n_levels=50)

joint_shot_chart.fig.set_size_inches(12,11)

#一张合成图有3个轴,第一个是ax_joint,即球场线,也用于调整其它一些设置

ax =joint_shot_chart.ax_joint

draw_court(ax)

#调整轴的范围和方向角来绘制半场,

ax.set_xlim(-250,250)

ax.set_ylim(422.5,-47.5)

#除去轴标签和刻度线

ax.set_xlabel('')

ax.set_ylabel('')

ax.tick_params(labelbottom='off',labelleft='off')

#添加标题

ax.set_title('JamesHarden FGA n2014-15 Reg. Season',

y=1.2, fontsize=18)

#添加数据源和作者信息

ax.text(-250,445,'DataSource: stats.nba.com'

'nAuthor: Savvas Tjortjoglou(savvastjortjoglou.com)',

fontsize=12)

#在右上角添加Harden的照片

#首先上传头像,然后设置头像缩放比例

img =OffsetImage(harden_pic, zoom=0.6)

#把(xy)元组作为坐标信息,传入set_offset函数

#把图放置在你设想的地方

img.set_offset((625,621))

#添加头像

ax.add_artist(img)

plt.show()

如何运用Python绘制NBA投篮图表

另一个用hexbins绘制的合成图

In [14]:#绘制合成图

cmap=plt.cm.gist_heat_r

joint_shot_chart= sns.jointplot(shot_df.LOC_X, shot_df.LOC_Y, stat_func=None,

kind='hex',space=0, color=cmap(.2), cmap=cmap)

joint_shot_chart.fig.set_size_inches(12,11)

#合成图有3个轴,第一个轴是ax_joint,即球场线

ax =joint_shot_chart.ax_joint

draw_court(ax)

#调整轴的范围和方向角来绘制半场

ax.set_xlim(-250,250)

ax.set_ylim(422.5,-47.5)

# 除去轴标签和刻度线

ax.set_xlabel('')

ax.set_ylabel('')

ax.tick_params(labelbottom='off',labelleft='off')

# 添加标题

ax.set_title('FGA2014-15 Reg. Season', y=1.2, fontsize=14)

#添加数据源和作者信息

ax.text(-250,445,'DataSource: stats.nba.com'

'nAuthor: Savvas Tjortjoglou',fontsize=12)

# Harden的照片放在右上角

img =OffsetImage(harden_pic, zoom=0.6)

img.set_offset((625,621))

ax.add_artist(img)

plt.show()

如何运用Python绘制NBA投篮图表

修改:根据Ogi010的建议,使用matplotlib包中翠绿色(Viridis)色图重新创建KDE画板

In [15]:#导入含翠绿色色图

from option_dimport test_cm as viridis

#设置翠绿色的色图

plt.register_cmap(cmap=viridis)

cmap =plt.get_cmap(viridis.name)

#n_levels设置主KDE图的轮廓线数量

joint_shot_chart= sns.jointplot(shot_df.LOC_X, shot_df.LOC_Y, stat_func=None,

kind='kde',space=0, color=cmap(0.1),

cmap=cmap,n_levels=50)

joint_shot_chart.fig.set_size_inches(12,11)

#合成图有3个轴,第一个轴是ax_joint,即球场线,也用来调整其它设置

ax =joint_shot_chart.ax_joint

draw_court(ax,color="white", lw=1)

#调整轴的范围和方向角来绘制半场

ax.set_xlim(-250,250)

ax.set_ylim(422.5,-47.5)

#除去轴标签和刻度

ax.set_xlabel('')

ax.set_ylabel('')

ax.tick_params(labelbottom='off',labelleft='off')

#添加标题

ax.set_title('JamesHarden FGA n2014-15 Reg. Season',

y=1.2, fontsize=18)

#添加数据源和作者信息

ax.text(-250,445,'DataSource: stats.nba.com'

'nAuthor: Savvas Tjortjoglou',fontsize=12)

#在右上角添加Harden的头像

#首先上传头像,然后调整头像大小以适合合成图

img =OffsetImage(harden_pic, zoom=0.6)

#将(xy)元组作为坐标信息传入set_offset函数

# to place theplot where you want, I just played around

#把图像放置在你设想的位置

img.set_offset((625,621))

#添加头像

ax.add_artist(img)

plt.show()

如何运用Python绘制NBA投篮图表

In [16]: importsys

print('Python version:', sys.version_info)

import IPython

print('IPython version:', IPython.__version__)

print('Requests verstion', requests.__version__)

print('Urllib.requests version', urllib.request.__version__)

import matplotlib as mpl

print('Matplotlib version:', mpl.__version__)

print('Seaborn version:', sns.__version__)

print('Pandas version:', pd.__version__)

Python version: sys.version_info(major=3, minor=4, micro=3,releaselevel='final', serial=0)

IPython version:3.2.0

Requestsverstion 2.7.0

Urllib.requestsversion 3.4

Matplotlibversion: 1.4.3

Seaborn version:0.6.0

Pandas version:0.16.2

素材来源:

http://savvastjortjoglou.com

大数据文摘译者简介

有意联系译者的朋友,请给“大数据文摘”后台留言,附自我介绍及微信ID,谢谢。
华中师大情报学专业硕士,研究方向为用户心理与行为。关注大数据发展,毕业后想从事互联网用户体验或咨询方面相关的工作。
杜克药理系博士在读,对生物信息学和相关的大数据挖掘很感兴趣。
席雄芬
京邮电大学无线信号处理专业研究生在读,主要研究图信号处理,对基于社交网络的图数据挖掘感兴趣,希望借助此平台能认识更多的从事大数据方面的人,结交更多的志同道合者。
姚佳灵
家庭主妇,对数据分析和处理很感兴趣,正在努力学习中,希望能和大家多交流。

如何运用Python绘制NBA投篮图表

大数据文摘精彩文章:

回复金融看【金融与商业】专栏历史期刊文章

回复可视化感受技术与艺术的完美结合

回复安全 关于泄密、黑客、攻防的新鲜案例

回复算法 既涨知识又有趣的人和事

回复谷歌 看其在大数据领域的举措

回复院士 看众多院士如何讲大数据

回复隐私 看看在大数据时代还有多少隐私

回复医疗 查看医疗领域文章6篇

回复征信 大数据征信专题四篇

回复大国“大数据国家档案”之美国等12国

回复体育 大数据在网球、NBA等应用案例

长按指纹,即可关注“大数据文摘”

专注大数据,每日有分享

覆盖千万读者的WeMedia联盟成员之一

原文始发于微信公众号(PPV课数据科学社区):如何运用Python绘制NBA投篮图表

原创文章,作者:ppvke,如若转载,请注明出处:http://www.ppvke.com/archives/18898

联系我们

4000-51-9191

在线咨询:点击这里给我发消息

工作时间:周一至周五,9:30-18:30,节假日休息