如何运用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)

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

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

# 提取投篮数据

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


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

In [4]: shot_df = pd.DataFrame(shots,columns=essay-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()



请注意,上述图表歪曲了数据。 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()


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


画出篮球场

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


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



利用这些维度,我们可以将它们转换成适用于我们图表的尺寸,并使用 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()




绘制投篮图

下面让我们根据球场的数据来绘制投篮图。以下有两种方式可以调整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()


让我们将投篮图上的篮圈移至顶部,与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()


让我们用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()



获取选手头像

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

In [12]: import urllib.request

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

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

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

"201935.png")

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

harden_pic =plt.imread(pic[0])


#绘制图像

plt.imshow(harden_pic)

plt.show()


现在要在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()


另一个用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()


修改:根据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()


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


原文发布时间为:2015-08-18

本文来自云栖社区合作伙伴“大数据文摘”,了解相关信息可以关注“BigDataDigest”微信公众号

相关文章
|
3月前
|
Python
以下是一些常用的图表类型及其Python代码示例,使用Matplotlib和Seaborn库。
以下是一些常用的图表类型及其Python代码示例,使用Matplotlib和Seaborn库。
|
10天前
|
数据可视化 Python
以下是一些常用的图表类型及其Python代码示例,使用Matplotlib和Seaborn库。
通过这些思维导图和分析说明表,您可以更直观地理解和选择适合的数据可视化图表类型,帮助更有效地展示和分析数据。
50 8
|
1月前
|
数据可视化 JavaScript 前端开发
Python中交互式Matplotlib图表
【10月更文挑战第20天】Matplotlib 是 Python 中最常用的绘图库之一,但默认生成的图表是静态的。通过结合 mpld3 库,可以轻松创建交互式图表,提升数据可视化效果。本文介绍了如何使用 mpld3 在 Python 中创建交互式散点图、折线图和直方图,并提供了详细的代码示例和安装方法。通过添加插件,可以实现缩放、平移和鼠标悬停显示数据标签等交互功能。希望本文能帮助读者掌握这一强大工具。
70 5
|
2月前
|
数据可视化 数据挖掘 Python
Seaborn 库创建吸引人的统计图表
【10月更文挑战第11天】本文介绍了如何使用 Seaborn 库创建多种统计图表,包括散点图、箱线图、直方图、线性回归图、热力图等。通过具体示例和代码,展示了 Seaborn 在数据可视化中的强大功能和灵活性,帮助读者更好地理解和应用这一工具。
46 3
|
3月前
|
数据可视化 Python
Python中的数据可视化:使用Matplotlib绘制图表
【9月更文挑战第11天】在这篇文章中,我们将探索如何使用Python的Matplotlib库来创建各种数据可视化。我们将从基本的折线图开始,然后逐步介绍如何添加更多的功能和样式,以使您的图表更具吸引力和信息量。无论您是数据科学家、分析师还是任何需要将数据转化为视觉形式的专业人士,这篇文章都将为您提供一个坚实的起点。让我们一起潜入数据的海洋,用视觉的力量揭示其背后的故事。
62 16
|
3月前
|
数据挖掘 数据处理 Python
python如何高效处理excel图表案例分享
python如何高效处理excel图表案例分享
50 2
|
4月前
|
数据可视化 物联网 区块链
探索Python中的数据可视化:使用Matplotlib和Seaborn绘制图表探索未来:区块链、物联网与虚拟现实的融合趋势与应用前景
【8月更文挑战第30天】本文旨在引导读者通过Python编程语言,利用Matplotlib和Seaborn库,轻松掌握数据可视化技术。文章以浅显易懂的语言,结合实用的代码示例,从基础的图表绘制到高级定制功能,逐步深入讲解如何在数据分析中运用这些工具。无论你是编程新手还是希望提升可视化技能的开发者,都能在这篇文章中找到有价值的信息,让你的数据“活”起来。
|
3月前
|
数据可视化 数据挖掘 数据处理
Seaborn——让图表更美观、更智能
Seaborn——让图表更美观、更智能
58 0
|
4月前
|
机器学习/深度学习 数据可视化 数据挖掘
Python中的数据可视化:使用Matplotlib库绘制图表
【8月更文挑战第30天】数据可视化是数据科学和分析的关键组成部分,它帮助我们以直观的方式理解数据。在Python中,Matplotlib是一个广泛使用的绘图库,提供了丰富的功能来创建各种类型的图表。本文将介绍如何使用Matplotlib库进行数据可视化,包括安装、基本概念、绘制不同类型的图表以及自定义图表样式。我们将通过实际代码示例来演示如何应用这些知识,使读者能够轻松地在自己的项目中实现数据可视化。
|
4月前
|
数据可视化 Python
Python的Matplotlib库创建动态图表
【8月更文挑战第19天】Matplotlib是Python中广泛使用的数据可视化库,擅长生成静态图表如折线图、散点图等。本文介绍如何利用其创建动态图表,通过动画展示数据变化,加深对数据的理解。文章涵盖动态折线图、散点图、柱状图、饼图及热力图的制作方法,包括开启交互模式、更新数据和重绘图表等关键步骤,帮助读者掌握Matplotlib动态图表的实用技巧。
68 0
下一篇
DataWorks