如何根据传球次数条件设置Matplotlib点间折线颜色
解决方案
一、实现折线颜色随传球次数(Count)变化
要让折线颜色随Count值增大偏向红色,你可以直接将upd_passes['Count']加入循环的zip对象,同时借助matplotlib的颜色映射与归一化工具,把Count值映射到对应颜色区间:
修改后的折线绘制代码:
# 对Count值做归一化,适配颜色映射的0-1区间 norm = plt.Normalize(upd_passes['Count'].min(), upd_passes['Count'].max()) # 选择从蓝到红的渐变配色(改用'Reds'可实现纯红色系渐变) cmap = plt.get_cmap('coolwarm') # Lines between points: for x0, y0, x1, y1, count in zip(x, y, xr, yr, upd_passes['Count']): # 根据当前Count值获取对应颜色 line_color = cmap(norm(count)) plt.plot((x0, x1), (y0, y1), '-', color=line_color, linewidth=3, alpha=0.6, zorder=1)
这里移除了原代码中的-ro(无需给每条折线添加红色圆点),调整alpha让颜色对比更明显。通过norm将Count值缩放到0-1范围,再用cmap匹配对应颜色,实现Count越大颜色越偏红的效果。
二、简化DataFrame合并操作
原代码在数据合并环节存在冗余,可通过链式调用+直接重命名列的方式优化,避免重复创建中间DataFrame:
优化后的upd_passes构建代码:
# 链式合并所有数据,减少中间变量 upd_passes = (pd.merge(players, passes, on='Player_id') .groupby(['Player_id', 'Name', 'Receiver_id']) .size() .reset_index(name='Count') # 直接命名统计列,无需后续修改columns .merge(avg_positions.rename(columns={'Name': 'Player_name', 'avg_pos_x': 'Player_x', 'avg_pos_y': 'Player_y'}), on='Player_id') .merge(avg_positions.rename(columns={'Player_id': 'Receiver_id', 'avg_pos_x': 'Receiver_x', 'avg_pos_y': 'Receiver_y'}), on='Receiver_id') .merge(players.rename(columns={'Player_id': 'Receiver_id', 'Name': 'Receiver_name'}), on='Receiver_id') .sort_values('Player_id') .reset_index(drop=True)) # 按需筛选保留列(不需要可省略) upd_passes = upd_passes[['Player_id', 'Player_name', 'Player_x', 'Player_y', 'Receiver_id', 'Receiver_name', 'Receiver_x', 'Receiver_y', 'Count']]
此方式省去了创建avg_positions2和receivers的步骤,直接在merge时重命名列,链式调用让代码更简洁紧凑。
完整修改后的代码
整合上述优化点后的完整代码如下:
import matplotlib.pyplot as plt import pandas as pd import matplotlib.patheffects as PathEffects pd.set_option('display.width', 400) pd.set_option('display.max_columns', 10) players = pd.DataFrame([[1, 'Player 1'], [2, 'Player 2'], [3, 'Player 3'], [4, 'Player 4'], [5, 'Player 5'], [6, 'Player 6'], [7, 'Player 7']], columns=['Player_id', 'Name']) avg_positions = pd.DataFrame([[1, 15, 34], [2, 35, 48], [3, 58, 27], [4, 62, 55], [5, 52, 40], [6, 69, 31], [7, 27, 9]], columns=['Player_id', 'avg_pos_x', 'avg_pos_y']) passes = pd.DataFrame([[1, 2], [1, 2], [1, 3], [2, 1], [2, 5], [3, 6], [6, 1], [4, 2], [4, 2], [5, 7], [6, 2], [7, 3], [7, 3], [7, 3], [7, 1]], columns=['Player_id', 'Receiver_id']) plt.style.use('_mpl-gallery') # 优化后的DataFrame合并逻辑 upd_passes = (pd.merge(players, passes, on='Player_id') .groupby(['Player_id', 'Name', 'Receiver_id']) .size() .reset_index(name='Count') .merge(avg_positions.rename(columns={'Name': 'Player_name', 'avg_pos_x': 'Player_x', 'avg_pos_y': 'Player_y'}), on='Player_id') .merge(avg_positions.rename(columns={'Player_id': 'Receiver_id', 'avg_pos_x': 'Receiver_x', 'avg_pos_y': 'Receiver_y'}), on='Receiver_id') .merge(players.rename(columns={'Player_id': 'Receiver_id', 'Name': 'Receiver_name'}), on='Receiver_id') .sort_values('Player_id') .reset_index(drop=True)) upd_passes = upd_passes[['Player_id', 'Player_name', 'Player_x', 'Player_y', 'Receiver_id', 'Receiver_name', 'Receiver_x', 'Receiver_y', 'Count']] print(upd_passes) passes_count = passes.groupby('Player_id')['Player_id'].count() # Player (dots) coordinates: xa = avg_positions.avg_pos_y ya = avg_positions.avg_pos_x # Player's coordinates: x = upd_passes.Player_y y = upd_passes.Player_x # Receiver's coordinates: xr = upd_passes.Receiver_y yr = upd_passes.Receiver_x # Point sizes and colors: sizes = passes_count * 80 colors = passes_count # Define player names for text annotations: names = players.Name # plot fig, ax = plt.subplots() ax.scatter(xa, ya, s=sizes, c=colors, vmin=0, vmax=5, cmap=plt.get_cmap('viridis'), zorder=2) # Text above points: for i, txt in enumerate(names): ax.annotate(txt, xy=(xa[i], ya[i]), xytext=(xa[i]-3, ya[i]+2), fontsize=9, color='black', path_effects=[PathEffects.withStroke(linewidth=3, foreground="w")]) # 处理折线颜色逻辑 norm = plt.Normalize(upd_passes['Count'].min(), upd_passes['Count'].max()) cmap = plt.get_cmap('coolwarm') # Lines between points: for x0, y0, x1, y1, count in zip(x, y, xr, yr, upd_passes['Count']): line_color = cmap(norm(count)) plt.plot((x0, x1), (y0, y1), '-', color=line_color, linewidth=3, alpha=0.6, zorder=1) fig.set_size_inches(5, 5) plt.show()
内容的提问来源于stack exchange,提问作者muted_buddy
相关产品推荐
相关产品推荐

