【科技与狠活】如何利用Python绘制足球场

news2024/9/21 12:23:30

卡塔尔世界杯赛程近半,朋友圈都在晒中奖的体育彩票,而我在搬砖🧱。

今天我将介绍如何使用Python Matplotlib创建一个足球场,本文设计球场尺寸为105×68。

首先导入所需的依赖包:

import pandas as pd
import numpy as np

import matplotlib.pyplot as plt
from matplotlib.patches import Arc

其实看似复杂的足球场一旦将其分解成各个组成部分,就不是什么特别复杂的事情了。足球场只是线条和形状的集合,下面我将一步步实现其包含的各个元素并在最后将它们全部封装在一个函数中。

首先,设置一些会频繁用到的全局变量。

# 足球场的边界长宽
x_min = 0
x_max = 105
y_min = 0
y_max = 68

line_color = "grey"
line_thickness = 1.5
background = "w" # w表示white
point_size = 20

arc_angle = 0
first = 0
second = 1

接下来创建列表pitch_x、pitch_y标记球场上各个元素的坐标。

pitch_x = [0,5.8,11.5,17,50,83,88.5,94.2,100] # pitch x markings

"""
[goal line, six yard box, penalty spot, edge of box,
 halfway line, edge of box, penalty spot, six yard box, goal line]
"""

pitch_y = [0, 21.1, 36.6, 50, 63.2, 78.9, 100]

"""
[sideline, edge of box, six yard box, centre of pitch,
 six yard box, edge of box, sideline ]
"""

goal_y = [45.2, 54.8] # goal posts

上述定义的x、y为100x100, 需要对球场进行同比例转换为105x68,当然球场元素坐标也会同比例变化:

x_conversion = 105 / 100
y_conversion = 68 / 100

pitch_x = [item * x_conversion for item in pitch_x]
pitch_y = [item * y_conversion for item in pitch_y]
goal_y = [item * y_conversion for item in goal_y]

现在已经对元素的点坐标进行了转换,下面就可以通过 x 和 y 坐标列表来绘制足球场的各个元素了。例如,这是如何绘制球场边线的代码:

lx1 = [x_min, x_max, x_max, x_min, x_min]
ly1 = [y_min, y_min, y_max, y_max, y_min]

fig, ax = plt.subplots(figsize=(11,7))
ax.axis("off")
ax.plot(lx1,ly1, color=line_color, lw=line_thickness, zorder=-1)

plt.tight_layout()
plt.show()

下面可以遍历每个元素的标记并将它们绘制成对应的球场元素。

# side and goal lines
lx1 = [x_min, x_max, x_max, x_min, x_min]
ly1 = [y_min, y_min, y_max, y_max, y_min]

ax.plot(lx1, ly1, color=line_color, lw=line_thickness, zorder=-1)

# outer boxed
lx2 = [x_max, pitch_x[5], pitch_x[5], x_max]
ly2 = [pitch_y[1], pitch_y[1], pitch_y[5], pitch_y[5]]

ax.plot(lx2, ly2, color=line_color, lw=line_thickness, zorder=-1)

lx3 = [0, pitch_x[3], pitch_x[3], 0]
ly3 = [pitch_y[1], pitch_y[1], pitch_y[5], pitch_y[5]]

ax.plot(lx3, ly3, color=line_color, lw=line_thickness, zorder=-1)

# .....

当然这不是最好的方法,因为这意味着如果我想绘制垂直方向足球场,我需要调整每一项数据。与其一一绘制,不如构建坐标列表并将它们添加到主列表中:

# side and goal lines
lx1 = [x_min, x_max, x_max, x_min, x_min]
ly1 = [y_min, y_min, y_max, y_max, y_min]

# outer boxed
lx2 = [x_max, pitch_x[5], pitch_x[5], x_max]
ly2 = [pitch_y[1], pitch_y[1], pitch_y[5], pitch_y[5]]

lx3 = [0, pitch_x[3], pitch_x[3], 0]
ly3 = [pitch_y[1], pitch_y[1], pitch_y[5], pitch_y[5]]

# goals
lx4 = [x_max, x_max+2, x_max+2, x_max]
ly4 = [goal_y[0], goal_y[0], goal_y[1], goal_y[1]]

lx5 = [0, -2, -2, 0]
ly5 = [goal_y[0], goal_y[0], goal_y[1], goal_y[1]]

# 6 yard boxes
lx6 = [x_max, pitch_x[7], pitch_x[7], x_max]
ly6 = [pitch_y[2], pitch_y[2], pitch_y[4], pitch_y[4]]

lx7 = [0, pitch_x[1], pitch_x[1], 0]
ly7 = [pitch_y[2], pitch_y[2], pitch_y[4], pitch_y[4]]

# Halfway line, penalty spots, and kickoff spot
lx8 = [pitch_x[4], pitch_x[4]]
ly8 = [0, y_max]

lines = [
    [lx1, ly1],
    [lx2, ly2],
    [lx3, ly3],
    [lx4, ly4],
    [lx5, ly5],
    [lx6, ly6],
    [lx7, ly7],
    [lx8, ly8],
    ]

通过循环遍历lines列表来绘制上面的图:

fig, ax = plt.subplots(figsize=(11,7))
ax.axis("off") 

for line in lines:
    ax.plot(line[0], line[1],
            color=line_color,
            lw=line_thickness,
            zorder=-1)

plt.tight_layout()
plt.show()

这样绘图代码看起来更清晰,以同样的方式绘制开球点和罚球点:

points = [
    [pitch_x[6], pitch_y[3]],
    [pitch_x[2], pitch_y[3]],
    [pitch_x[4], pitch_y[3]]
    ]

然后遍历绘图代码中的点:

fig, ax = plt.subplots(figsize=(11,7))
ax.axis("off")

for line in lines:
    ax.plot(line[0], line[1],
            color=line_color,
            lw=line_thickness,
            zorder=-1)

for point in points:
    ax.scatter(point[0], point[1],
               color=line_color,
               s=point_size,
               zorder=-1)

plt.tight_layout()
plt.show()

在每个"box"上添加中心圆。

circle_points = [pitch_x[4], pitch_y[3]]
arc_points1 = [pitch_x[6], pitch_y[3]]
arc_points2 = [pitch_x[2], pitch_y[3]]
fig, ax = plt.subplots(figsize=(11,7))
ax.axis("off")
for line in lines:
    ax.plot(line[0], line[1],
            color=line_color,
            lw=line_thickness,
            zorder=-1)

for point in points:
    ax.scatter(point[0], point[1],
               color=line_color,
               s=point_size,
               zorder=-1)

circle = plt.Circle((circle_points[0], circle_points[1]),
                     x_max * 0.088,
                     lw=line_thickness,
                     color=line_color,
                     fill=False,
                     zorder=-1)

ax.add_artist(circle)

arc1 = Arc((arc_points1[0], arc_points1[1]),
           height=x_max * 0.088 * 2,
           width=x_max * 0.088 * 2,
           angle=arc_angle,
           theta1=128.75,
           theta2=231.25,
           color=line_color,
           lw=line_thickness,
           zorder=-1)

ax.add_artist(arc1)

arc2 = Arc((arc_points2[0], arc_points2[1]),
           height=x_max * 0.088 * 2,
           width=x_max * 0.088 * 2,
           angle=arc_angle,
           theta1=308.75,
           theta2=51.25,
           color=line_color,
           lw=line_thickness,
           zorder=-1)

ax.add_artist(arc2)

ax.set_aspect("equal") 
plt.tight_layout()
plt.show()

这就是创建足球场的整个过程!然而,这还没有结束。我添加了几个变量并调整了代码以绘制逻辑更加灵活。

fig, ax = plt.subplots(figsize=(11,7))
ax.axis("off")

for line in lines:
    ax.plot(line[first], line[second],
            color=line_color,
            lw=line_thickness,
            zorder=-1)

for point in points:
    ax.scatter(point[first], point[second],
               color=line_color,
               s=point_size,
               zorder=-1)

circle = plt.Circle((circle_points[first], circle_points[second]),
                     x_max * 0.088,
                     lw=line_thickness,
                     color=line_color,
                     fill=False,
                     zorder=-1)

ax.add_artist(circle)

arc1 = Arc((arc_points1[first], arc_points1[second]),
           height=x_max * 0.088 * 2,
           width=x_max * 0.088 * 2,
           angle=arc_angle,
           theta1=128.75,
           theta2=231.25,
           color=line_color,
           lw=line_thickness,
           zorder=-1)

ax.add_artist(arc1)

arc2 = Arc((arc_points2[first], arc_points2[second]),
           height=x_max * 0.088 * 2,
           width=x_max * 0.088 * 2,
           angle=arc_angle,
           theta1=308.75,
           theta2=51.25,
           color=line_color,
           lw=line_thickness,
           zorder=-1)

ax.add_artist(arc2)

ax.set_aspect("equal")
plt.tight_layout()
plt.show()

还记得文章开头设置的几个变量吧:arc_angle = 0、first = 0 和 second = 1。通过将这些设置为变量而不是硬编码,我们可以修改这几个变量为first = 1、second = 0和arc_angle = 90,这样就可以绘制一个垂直方向的足球场了。

first = 1
second = 0
arc_angle = 90

fig, ax = plt.subplots(figsize=(7,11))
ax.axis("off")

for line in lines:
    ax.plot(line[first], line[second],
            color=line_color,
            lw=line_thickness,
            zorder=-1)

for point in points:
    ax.scatter(point[first], point[second],
               color=line_color,
               s=point_size,
               zorder=-1)

circle = plt.Circle((circle_points[first], circle_points[second]),
                     x_max * 0.088,
                     lw=line_thickness,
                     color=line_color,
                     fill=False,
                     zorder=-1)

ax.add_artist(circle)

arc1 = Arc((arc_points1[first], arc_points1[second]),
           height=x_max * 0.088 * 2,
           width=x_max * 0.088 * 2,
           angle=arc_angle,
           theta1=128.75,
           theta2=231.25,
           color=line_color,
           lw=line_thickness,
           zorder=-1)

ax.add_artist(arc1)

arc2 = Arc((arc_points2[first], arc_points2[second]),
           height=x_max * 0.088 * 2,
           width=x_max * 0.088 * 2,
           angle=arc_angle,
           theta1=308.75,
           theta2=51.25,
           color=line_color,
           lw=line_thickness,
           zorder=-1)

ax.add_artist(arc2)

ax.set_aspect("equal")
plt.tight_layout()
plt.show()

代码封装

下面将上面零散的代码封装成函数。

def draw_pitch(x_min=0, x_max=105,
               y_min=0, y_max=68,
               pitch_color="w",
               line_color="grey",
               line_thickness=1.5,
               point_size=20,
               orientation="horizontal",
               aspect="full",
               ax=None
               ):

    if not ax:
        raise TypeError("This function is intended to be used with an existing fig and ax in order to allow flexibility in plotting of various sizes and in subplots.")


    if orientation.lower().startswith("h"):
        first = 0
        second = 1
        arc_angle = 0

        if aspect == "half":
            ax.set_xlim(x_max / 2, x_max + 5)

    elif orientation.lower().startswith("v"):
        first = 1
        second = 0
        arc_angle = 90

        if aspect == "half":
            ax.set_ylim(x_max / 2, x_max + 5)

    
    else:
        raise NameError("You must choose one of horizontal or vertical")

    
    ax.axis("off")

    rect = plt.Rectangle((x_min, y_min),
                         x_max, y_max,
                         facecolor=pitch_color,
                         edgecolor="none",
                         zorder=-2)

    ax.add_artist(rect)

    x_conversion = x_max / 100
    y_conversion = y_max / 100

    pitch_x = [0,5.8,11.5,17,50,83,88.5,94.2,100] # pitch x markings
    pitch_x = [x * x_conversion for x in pitch_x]

    pitch_y = [0, 21.1, 36.6, 50, 63.2, 78.9, 100] # pitch y markings
    pitch_y = [x * y_conversion for x in pitch_y]

    goal_y = [45.2, 54.8] # goal posts
    goal_y = [x * y_conversion for x in goal_y]

    # side and goal lines
    lx1 = [x_min, x_max, x_max, x_min, x_min]
    ly1 = [y_min, y_min, y_max, y_max, y_min]

    # outer boxed
    lx2 = [x_max, pitch_x[5], pitch_x[5], x_max]
    ly2 = [pitch_y[1], pitch_y[1], pitch_y[5], pitch_y[5]]

    lx3 = [0, pitch_x[3], pitch_x[3], 0]
    ly3 = [pitch_y[1], pitch_y[1], pitch_y[5], pitch_y[5]]

    # goals
    lx4 = [x_max, x_max+2, x_max+2, x_max]
    ly4 = [goal_y[0], goal_y[0], goal_y[1], goal_y[1]]

    lx5 = [0, -2, -2, 0]
    ly5 = [goal_y[0], goal_y[0], goal_y[1], goal_y[1]]

    # 6 yard boxes
    lx6 = [x_max, pitch_x[7], pitch_x[7], x_max]
    ly6 = [pitch_y[2],pitch_y[2], pitch_y[4], pitch_y[4]]

    lx7 = [0, pitch_x[1], pitch_x[1], 0]
    ly7 = [pitch_y[2],pitch_y[2], pitch_y[4], pitch_y[4]]


    # Halfway line, penalty spots, and kickoff spot
    lx8 = [pitch_x[4], pitch_x[4]]
    ly8 = [0, y_max]

    lines = [
        [lx1, ly1],
        [lx2, ly2],
        [lx3, ly3],
        [lx4, ly4],
        [lx5, ly5],
        [lx6, ly6],
        [lx7, ly7],
        [lx8, ly8],
        ]

    points = [
        [pitch_x[6], pitch_y[3]],
        [pitch_x[2], pitch_y[3]],
        [pitch_x[4], pitch_y[3]]
        ]

    circle_points = [pitch_x[4], pitch_y[3]]
    arc_points1 = [pitch_x[6], pitch_y[3]]
    arc_points2 = [pitch_x[2], pitch_y[3]]


    for line in lines:
        ax.plot(line[first], line[second],
                color=line_color,
                lw=line_thickness,
                zorder=-1)

    for point in points:
        ax.scatter(point[first], point[second],
                   color=line_color,
                   s=point_size,
                   zorder=-1)

    circle = plt.Circle((circle_points[first], circle_points[second]),
                        x_max * 0.088,
                        lw=line_thickness,
                        color=line_color,
                        fill=False,
                        zorder=-1)

    ax.add_artist(circle)

    arc1 = Arc((arc_points1[first], arc_points1[second]),
               height=x_max * 0.088 * 2,
               width=x_max * 0.088 * 2,
               angle=arc_angle,
               theta1=128.75,
               theta2=231.25,
               color=line_color,
               lw=line_thickness,
               zorder=-1)

    ax.add_artist(arc1)

    arc2 = Arc((arc_points2[first], arc_points2[second]),
               height=x_max * 0.088 * 2,
               width=x_max * 0.088 * 2,
               angle=arc_angle,
               theta1=308.75,
               theta2=51.25,
               color=line_color,
               lw=line_thickness,
               zorder=-1)

    ax.add_artist(arc2)

    ax.set_aspect("equal")

    return ax

现在只需要调用函数来绘制想要的足球场!

background = "#09b309"

fig, ax = plt.subplots(figsize=(11, 7))
fig.set_facecolor(background)

draw_pitch(orientation="h",
           aspect="full",
           pitch_color=background, 
           line_color="lightgrey",
           ax=ax)

plt.tight_layout()
plt.show()

下面这张图是绘制过程gif。



代码仓库:How-To-Python: 人生苦短,我用Python

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/61764.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring框架(八):基于xml方式Bean的配置

基于xml方式Bean的配置引子基于xml方式Bean的配置Sping工厂实现静态工厂实例工厂FactoryBeanBean的依赖注入Spring的xml标签Spring的getBean方法Spring配置非自定义BeanSpringBean实例化的基本流程引子 痛定思痛,主要问题出现在自己雀氏不熟悉框架底层、一些面试题…

Vue 官方文档2.x教程学习笔记 1 基础 1.5 计算属性和侦听器 1.5.1 计算属性

Vue 官方文档2.x教程学习笔记 文章目录Vue 官方文档2.x教程学习笔记1 基础1.5 计算属性和侦听器1.5.1 计算属性1 基础 1.5 计算属性和侦听器 1.5.1 计算属性 模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。 在模板中放入太多的逻辑会让模板过重且…

【Linux内核】Linux内核介绍

Linux学习内核思路 学习过程: Linux内核引导及如何初始化进程管理、内存管理 内核引导及过程:CPU通电后,首先执行引导程序,引导程序把内核加载到**内存,**然后执行内核,内核初始化完成后,启动…

[附源码]计算机毕业设计二次元信息分享平台的设计及实现

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

年产2万吨山楂酒工厂的设计-陈酿工段及车间的设计(lunwen+任务书+cad图纸)

目录 摘 要 I Abstract II 1前 言 1 1.1设计背景及目的 1 1.1.1山楂酒的介绍及功效 1 1.1.2目标人群 1 1.1.3发展前景 2 1.2设计依据 2 1.3设计内容 2 1.4原材料的选择 3 第二章 山楂酒生产工艺设计 5 2.1工艺流程 5 2.2 操作要点 5 2.2.1 原料选择 5 2.2.2清洗: 5 …

机器学习:详细推导高斯混合聚类(GMM)原理(附Python实现)

目录0 写在前面1 高斯概率密度2 混合高斯分布3 GMM算法3.1 定义3.2 参数估计4 Python实现4.1 算法流程4.2 E步4.3 M步4.4 可视化0 写在前面 机器学习强基计划聚焦深度和广度,加深对机器学习模型的理解与应用。“深”在详细推导算法模型背后的数学原理;“…

用 NEON 实现高效的 FIR 滤波器

系列文章目录 数字信号处理中的 SIMDNeon intrinsics 简明教程 文章目录系列文章目录写在前面前言FIR 滤波器优化方案何时应该使用时域的滤波器?如何加快FIR滤波器的实现速度?初步假设有限长度信号反转的滤波器系数实际的卷积公式卷积过程可视化线性卷积…

第二期 微信云开发之位置信息获取(wx.getLocation)

很多小伙伴在开发微信小程序的时候,需要获取当前用户位置信息时,都会遇到该如何获取位置详细信息的问题,以下是我的处理方法。 首先,我在生活智打卡小程序使用的是微信小程序自带的获取用户的位置信息的接口(wx.getLoc…

基于JSP技术的猎头公司管理软件的设计和实现——内部事务部分(源代码+论文)

分类号:TP315 U D C:D10621-408-(2007)5978-0 密 级:公 开 编 号:2003031227 成都信息工程学院 学位论文 基于JSP技术的猎头公司管理软件的设计和实现 ——内部事务部分 基于JSP技术的猎头公司管理软件的设计和实现 ——内…

世界杯太精彩了,带大家用Python做个足球游戏,边玩游戏边看比赛

文章目录 Python零基础快速制作足球游戏(附源代码) 前言 一、Python环境说明 二、游戏程序说明 1、游戏开始界面 2、人物移动规则说明,可支持两位玩家 3、足球规则 4、主方法调取 三、游戏运行效果与比赛结果 1、游戏开始界面 2、…

桥接设计模式

一、桥接模式 1、定义 桥接模式(Bridge Pattern)又称作桥梁模式,指将抽象部分与具体实现部分分离,使它们都可以独立地变化,属于结构型设计模式。 桥接模式的主要目的是通过组合的方式建立两个类之间的联系&#xff0c…

java计算机毕业设计ssm社区养老服务管理系统iq0w7(附源码、数据库)

java计算机毕业设计ssm社区养老服务管理系统iq0w7(附源码、数据库) 项目运行 环境配置: Jdk1.8 Tomcat8.5 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#…

海口市美兰区图书馆建筑结构设计(计算书+任务书+建筑结构施工组织设计cad图纸)

【目录】 1目录……………………………………………………………………………………………………….1 2前言……………………………………………………………………………………………………3 3 摘要……………………………………………………………….…………………………1 结…

Java项目:SSM出租车管理系统

作者主页:源码空间站2022 简介:Java领域优质创作者、Java项目、学习资料、技术互助 文末获取源码 项目介绍 超级管理员角色包含以下功能: 超级管理员管理,公告管理,系统管理员管理,司机管理,车辆管理,维修保养管理,运营里程记录等功能。 普通…

12.4泛型 map set

目录 一,泛型 1 什么是泛型 2 引出泛型 2.1语法 3 泛型类的使用 3.1 语法 3.2 示例 3.3 类型推导(Type Inference) 4.裸类型(Raw Type) 5 泛型如何编译的 5.2 为什么不能实例化泛型类型数组 6 泛型的上界 6.1 语法 6.3 复杂示例 7 泛型方法 7.1 定义语法 二.通…

【数据结构】二分搜索树

集合java.util包下的常用子类,集合无非就是各种数据结构的应用。集合存在的目的就是为了将数据高校进行读写,无论哪种具体的集合无外乎CURD。 Collection->单个元素保存的父接口。 List->可以保存重复的单个元素。 Set->保存单个不重复元素。…

python在centos7.x下建立虚拟环境

(327条消息) python在centos下安装以及配置_雨师的博客-CSDN博客 https://blog.csdn.net/wtt234/article/details/128172281 python离线环境下安装第三方模块的方法: https://blog.csdn.net/wtt234/article/details/128162292 上篇已经把python在centos下的安装以及…

红蓝对抗--sliver 搭建

使用sliver的优点: 1 支持macos、win、linux上线 2 支持丰富的插件加载扩展,功能选择多,CS已经很普遍了,可以尝试sliver做C2 sliver相关构成: Implant:生成植入的木马 sliver-client :C2的控制端 Sliver Server:C2的控制端,客户端通过gRPC接口与server交互 架构: […

【 java 集合】Collection 接口中的常用方法

📋 个人简介 💖 作者简介:大家好,我是阿牛,全栈领域优质创作者。😜📝 个人主页:馆主阿牛🔥🎉 支持我:点赞👍收藏⭐️留言&#x1f4d…

LeetCode刷题复盘笔记—一文搞懂纯完全背包问题(动态规划系列第十一篇)

今日主要总结一下动态规划背包问题的基础——纯完全背包问题 在Leetcode题库中主要都是0-1背包和完全背包的应用问题,所以主要掌握这两个背包问题 题目:纯完全背包问题 题目描述: 有N件物品和一个最多能背重量为W的背包。第i件物品的重量是w…