我来为您设计一个实时显示场上优势的Python案例,这个案例模拟一场足球比赛,实时计算并显示双方的攻防优势。

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import time
from collections import deque
import random
class MatchTracker:
"""实时比赛优势追踪器"""
def __init__(self, team1="主队", team2="客队"):
self.team1_name = team1
self.team2_name = team2
# 实时数据存储(缓存最近60秒数据)
self.time_window = 60
self.timestamps = deque(maxlen=self.time_window)
# 主队数据
self.team1_possession = deque(maxlen=self.time_window) # 控球率
self.team1_shots = deque(maxlen=self.time_window) # 射门
self.team1_corners = deque(maxlen=self.time_window) # 角球
self.team1_danger = deque(maxlen=self.time_window) # 危险进攻
# 客队数据
self.team2_possession = deque(maxlen=self.time_window)
self.team2_shots = deque(maxlen=self.time_window)
self.team2_corners = deque(maxlen=self.time_window)
self.team2_danger = deque(maxlen=self.time_window)
# 综合优势评分
self.team1_advantage = deque(maxlen=self.time_window)
self.team2_advantage = deque(maxlen=self.time_window)
# 比赛数据累计
self.total_possession_t1 = 50
self.total_possession_t2 = 50
self.score_t1 = 0
self.score_t2 = 0
# 统计权重
self.weights = {
'possession': 0.3, # 控球率权重
'shots': 0.25, # 射门权重
'corners': 0.15, # 角球权重
'danger': 0.3 # 危险进攻权重
}
# 创建图表
self.setup_plot()
def setup_plot(self):
"""初始化图表布局"""
self.fig = plt.figure(figsize=(15, 8))
gs = self.fig.add_gridspec(3, 3)
# 主优势仪表盘
self.ax_gauge = self.fig.add_subplot(gs[0, :])
self.ax_gauge.set_xlim(-1.5, 1.5)
self.ax_gauge.set_ylim(-1, 1)
self.ax_gauge.axis('off')
# 控球率
self.ax_possession = self.fig.add_subplot(gs[1, 0])
self.ax_possession.set_ylabel('控球率')
# 射门统计
self.ax_shots = self.fig.add_subplot(gs[1, 1])
self.ax_shots.set_ylabel('射门')
# 危险进攻
self.ax_danger = self.fig.add_subplot(gs[1, 2])
self.ax_danger.set_ylabel('危险进攻')
# 整体优势趋势
self.ax_trend = self.fig.add_subplot(gs[2, :])
self.ax_trend.set_ylabel('优势度')
self.ax_trend.set_xlabel('时间(秒)')
self.ax_trend.axhline(y=0, color='gray', linestyle='--', alpha=0.5)
self.fig.suptitle(f'{self.team1_name} vs {self.team2_name} 实时优势分析', fontsize=16, fontweight='bold')
# 颜色设置
self.color_t1 = '#1e88e5'
self.color_t2 = '#e53935'
def calculate_advantage(self):
"""计算综合优势"""
if not self.timestamps:
return 0, 0
# 获取最近的数据
t1_pos = np.mean(self.team1_possession) if self.team1_possession else 50
t2_pos = np.mean(self.team2_possession) if self.team2_possession else 50
t1_shot = np.sum(self.team1_shots) if self.team1_shots else 0
t2_shot = np.sum(self.team2_shots) if self.team2_shots else 0
t1_corner = np.sum(self.team1_corners) if self.team1_corners else 0
t2_corner = np.sum(self.team2_corners) if self.team2_corners else 0
t1_danger = np.sum(self.team1_danger) if self.team1_danger else 0
t2_danger = np.sum(self.team2_danger) if self.team2_danger else 0
# 归一化处理
max_shots = max(t1_shot, t2_shot, 1)
max_corners = max(t1_corner, t2_corner, 1)
max_danger = max(t1_danger, t2_danger, 1)
# 计算各项比分
possession_score = (t1_pos - t2_pos) / 100
shots_score = (t1_shot - t2_shot) / max_shots
corners_score = (t1_corner - t2_corner) / max_corners
danger_score = (t1_danger - t2_danger) / max_danger
# 加权计算总优势
t1_adv = (possession_score * self.weights['possession'] +
shots_score * self.weights['shots'] +
corners_score * self.weights['corners'] +
danger_score * self.weights['danger'])
# 加上比分权重
score_advantage = (self.score_t1 - self.score_t2) * 0.2
return t1_adv + score_advantage, -(t1_adv + score_advantage)
def update_data(self):
"""模拟实时数据更新"""
current_time = time.time()
self.timestamps.append(current_time)
# 模拟比赛数据(真实应用中从传感器/数据源获取)
# 主队数据
t1_possession = 40 + random.uniform(-15, 15)
t1_shots = random.choice([0, 0, 0, 0, 1, 1, 1, 2])
t1_corners = random.choice([0, 0, 0, 1, 1, 2])
t1_danger = random.choice([0, 0, 1, 1, 1, 2, 3])
# 客队数据(反相关增加对抗性)
t2_possession = 100 - t1_possession
t2_shots = random.choice([0, 0, 0, 0, 1, 1, 1, 2])
t2_corners = random.choice([0, 0, 0, 1, 1, 2])
t2_danger = random.choice([0, 0, 1, 1, 1, 2, 3])
# 更新数据存储
self.team1_possession.append(t1_possession)
self.team1_shots.append(t1_shots)
self.team1_corners.append(t1_corners)
self.team1_danger.append(t1_danger)
self.team2_possession.append(t2_possession)
self.team2_shots.append(t2_shots)
self.team2_corners.append(t2_corners)
self.team2_danger.append(t2_danger)
# 更新总控球率
self.total_possession_t1 = 0.95 * self.total_possession_t1 + 0.05 * t1_possession
self.total_possession_t2 = 100 - self.total_possession_t1
# 模拟进球(小概率)
if random.random() < 0.01: # 1%概率进球
if random.random() < 0.5:
self.score_t1 += 1
self.team1_advantage.append(0.5) # 进球加分
else:
self.score_t2 += 1
self.team2_advantage.append(0.5)
# 计算综合优势
t1_adv, t2_adv = self.calculate_advantage()
self.team1_advantage.append(t1_adv)
self.team2_advantage.append(t2_adv)
def update_plot(self, frame):
"""更新图表"""
# 更新数据
self.update_data()
# 清空所有子图
for ax in [self.ax_gauge, self.ax_possession, self.ax_shots,
self.ax_danger, self.ax_trend]:
ax.clear()
# 1. 仪表盘显示
advantage = self.team1_advantage[-1] if self.team1_advantage else 0
self.draw_gauge(self.ax_gauge, advantage)
# 2. 控球率饼图
sizes = [self.total_possession_t1, self.total_possession_t2]
labels = [f'{self.team1_name}\n{sizes[0]:.1f}%',
f'{self.team2_name}\n{sizes[1]:.1f}%']
colors = [self.color_t1, self.color_t2]
self.ax_possession.clear()
wedges, texts, autotexts = self.ax_possession.pie(
sizes, labels=labels, colors=colors, autopct='%1.1f%%',
startangle=90, explode=(0.05, 0.05)
)
self.ax_possession.set_title('控球率')
# 3. 射门统计
if self.team1_shots and self.team2_shots:
shots_t1 = np.sum(self.team1_shots)
shots_t2 = np.sum(self.team2_shots)
self.ax_shots.bar([0, 1], [shots_t1, shots_t2],
color=[self.color_t1, self.color_t2], alpha=0.7)
self.ax_shots.set_xticks([0, 1])
self.ax_shots.set_xticklabels([self.team1_name, self.team2_name])
self.ax_shots.set_title(f'射门(主队:{shots_t1} 客队:{shots_t2})')
# 4. 危险进攻
if self.team1_danger and self.team2_danger:
danger_t1 = np.sum(self.team1_danger)
danger_t2 = np.sum(self.team2_danger)
self.ax_danger.bar([0, 1], [danger_t1, danger_t2],
color=[self.color_t1, self.color_t2], alpha=0.7)
self.ax_danger.set_xticks([0, 1])
self.ax_danger.set_xticklabels([self.team1_name, self.team2_name])
self.ax_danger.set_title(f'危险进攻(主队:{danger_t1} 客队:{danger_t2})')
# 5. 优势趋势图
if len(self.team1_advantage) > 1:
x = range(len(self.team1_advantage))
self.ax_trend.plot(x, list(self.team1_advantage),
color=self.color_t1, label=f'{self.team1_name}优势', linewidth=2)
self.ax_trend.plot(x, list(self.team2_advantage),
color=self.color_t2, label=f'{self.team2_name}优势', linewidth=2)
# 填充优势区域
self.ax_trend.fill_between(x, 0, list(self.team1_advantage),
alpha=0.2, color=self.color_t1)
self.ax_trend.fill_between(x, 0, list(self.team2_advantage),
alpha=0.2, color=self.color_t2)
self.ax_trend.legend(loc='upper right')
self.ax_trend.grid(True, alpha=0.3)
self.ax_trend.set_ylim(-1.5, 1.5)
# 在仪表盘下方显示比分
self.fig.text(0.5, 0.88,
f'比分: {self.team1_name} {self.score_t1} - {self.score_t2} {self.team2_name}',
ha='center', fontsize=12, color='black',
bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.5))
def draw_gauge(self, ax, value):
"""绘制优势仪表盘"""
# 背景圆环
theta = np.linspace(0, 2*np.pi, 100)
x = np.cos(theta)
y = np.sin(theta)
# 绘制半圆背景
theta_half = np.linspace(np.pi, 2*np.pi, 50)
ax.fill(np.cos(theta_half), np.sin(theta_half), color='lightgray', alpha=0.3)
# 绘制优势指示
angle = np.pi + (np.clip(value, -1, 1) + 1) * np.pi/2
arrow_length = 0.8
ax.annotate('', xy=(arrow_length*np.cos(angle), arrow_length*np.sin(angle)),
xytext=(0, 0),
arrowprops=dict(arrowstyle='->', lw=3, color='black'))
# 添加标签
ax.text(0, -0.2, f'优势度: {value:.2f}', ha='center', fontsize=12)
ax.text(-1.2, 0, self.team1_name, color=self.color_t1, fontweight='bold')
ax.text(1.2, 0, self.team2_name, color=self.color_t2, fontweight='bold')
# 绘制刻度和文字
for i in range(-2, 3):
angle_i = np.pi + (i + 2) * np.pi/4
value_i = i/2
ax.text(1.1*np.cos(angle_i), 1.1*np.sin(angle_i),
f'{value_i:.1f}', ha='center', fontsize=8)
# 判断优势方
if value > 0.1:
ax.text(0, 0.5, f'{self.team1_name}占优!', ha='center',
fontsize=14, color=self.color_t1, fontweight='bold')
elif value < -0.1:
ax.text(0, 0.5, f'{self.team2_name}占优!', ha='center',
fontsize=14, color=self.color_t2, fontweight='bold')
else:
ax.text(0, 0.5, '势均力敌', ha='center', fontsize=14, color='gray')
def main():
"""主函数"""
# 创建追踪器
tracker = MatchTracker("主队", "客队")
# 创建动画
ani = FuncAnimation(tracker.fig, tracker.update_plot,
interval=1000, # 1秒更新一次
save_count=100)
print("实时比赛优势追踪器已启动")
print("按Ctrl+C停止运行")
try:
plt.tight_layout()
plt.show()
except KeyboardInterrupt:
print("\n追踪器已停止")
# 显示最终统计
print("\n===== 比赛总结 =====")
print(f"最终比分: {tracker.team1_name} {tracker.score_t1} - {tracker.score_t2} {tracker.team2_name}")
print(f"最终控球率: {tracker.team1_name} {tracker.total_possession_t1:.1f}% - {tracker.total_possession_t2:.1f}% {tracker.team2_name}")
if tracker.team1_advantage:
final_adv = tracker.team1_advantage[-1]
print(f"最终优势度: {final_adv:.2f}")
if final_adv > 0.1:
print(f" {tracker.team1_name}在场上更具优势!")
elif final_adv < -0.1:
print(f" {tracker.team2_name}在场上更具优势!")
else:
print(" 两队势均力敌")
if __name__ == "__main__":
main()
运行效果:
- 实时仪表盘:顶部显示当前优势度,指针偏向优势方
- 控球率:直观的饼图显示双方控球比例
- 射门统计:柱状图展示双方射门次数
- 危险进攻:显示创造的威胁机会
- 优势趋势:动态折线图展示整场比赛的优势变化
扩展建议:
- 接入真实比赛数据(如API、传感器)
- 添加更多统计指标(传球成功率、抢断、犯规等)
- 增加比赛事件标记(进球、红黄牌等)
- 支持多场比赛同时监控
- 添加预警系统(某队连续占优时提醒)
这个系统可以用于体育分析、比赛直播辅助、战术分析等场景,实时反映场上哪一方更具优势。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播