0

I have created a shot map using matplotlib, it is currently not interactive and just a static image of all the shots a player has taken (goal, blocked, saved, missed)

The code I used as reference to create the pitch map can be found here: https://fcpython.com/visualisation/drawing-pitchmap-adding-lines-circles-matplotlib

Shot Map

Below is the python code used to plot the shot map:

# Plotting Shots Horizontal Full Pitch

draw_pitch("#3E3E40","#faf0e6","horizontal","full")

x = df_salah['XM'].tolist()
y = df_salah['YM'].tolist()
y1 = [68 - i for i in y]

## Add Z variable for xG
z = df_salah['xG'].tolist()
z1 = [500 * i for i in z] # This is to scale the "xG" values for plotting

## Add small legend in the bottom corner
mSize = [0.05,0.10,0.2,0.4,0.6,1]
mSizeS = [500 * i for i in mSize]
mx = [5.5,7,9,11,13.5,16.5]
my = [60,60,60,60,60,60]

colors = {'Goal':'Green', 'MissedShots':'Purple', 'BlockedShot':'Red', 'SavedShot':'Blue', 'ShotOnPost':'Yellow'}
## markers = {'Goal':'Star', 'MissedShots':'X', 'BlockedShot':'O', 'SavedShot':'V', 'ShotOnPost':'S'}

plt.text(11,55,"xG", color="white", ha="center",va="center", zorder=zo, fontsize=16)
plt.scatter(x,y,s=z1, marker='o',color=df_salah['result'].map(colors),edgecolors="black", zorder=zo)
plt.scatter(mx,my,s=mSizeS,facecolors="white", edgecolor="white",zorder=zo)
plt.plot([5.5,17], [57,57],color="white",lw=2,zorder=zo)

i = 0

for i in range(len(mx)):
    plt.text(mx[i], my[i], mSize[i], fontsize=mSize[i]*18, color="#195905", zorder=zo,ha="center", va="center")

    
## Title
plt.title("Mohamed Salah Shots 19/20 Season")

plt.show()

What I want to do is make this interactive by adding filters (widgets) so I can filter for type of shot taken so the map only reveals that particular type of shot on the map e.g. If I filter for "goals" then the map should show only shots that lead to a goal, etc.

I also want to add the "hover" feature from plotly where if you hover over the shot it will tell you the "xG" value, time of shot etc.

When using plotly, how do I keep the pitch map as I can't figure that out. I tried the following which resulted in:

trace1 = px.scatter(df_salah, x='XM', y='YM', color='result')
fig = go.FigureWidget(trace1)

Plotly Test

I also want to keep the scaling of of the circles

Could someone help start me off with the code as I am a bit lost on how to do this or if I'm even using the correct libraries/platform?

Hemz Shah
  • 1
  • 2
  • [Yes, it is possible](https://stackoverflow.com/a/47166787/8881141). But what is your code-specific question? – Mr. T Jan 08 '21 at 23:37
  • @Mr.T How would I code something like this? – Hemz Shah Jan 08 '21 at 23:46
  • By starting to adapt, what others (like in the link) have done, to your needs. If you encounter problems, you read the documentation on [event handling](https://matplotlib.org/3.3.3/users/event_handling.html) and have a look at how [examples in the gallery](https://matplotlib.org/3.3.3/gallery/index.html) solved similar problems. If you then encounter a specific problem, you come and ask a specific code-related question. Nobody will write you the entire code. – Mr. T Jan 08 '21 at 23:51
  • @Mr.T Thanks, I get that but I don't know how to keep my pitch map when using plotly, which is what I want to figure out first. – Hemz Shah Jan 09 '21 at 00:02
  • Well, for a start, you could decide what platform you want to use. Seemingly, you want to use plotly - so why is this tagged as matplotlib? And the first hit on duckduckgo is this: https://www.tutorialspoint.com/plotly/plotly_with_matplotlib_and_chart_studio.htm – Mr. T Jan 09 '21 at 00:07

1 Answers1

1

There are several issues you want to achieve, but you want to use plotly to apply your pitch first, so I will answer only that. As you can see in the official reference, you can use the PIL library to display a background image.

  1. Save the image using the library you showed. (The code you showed has parameters, but the library doesn't have that feature.
  2. Add a plotly background image with fig.add_layout_image(). This will accomplish the basic functionality, but you will need to make some adjustments, such as calculating the off-pitch margins and modifying the graph size.
fig=plt.figure(figsize=(15, 10.38), dpi=100, facecolor='#3E3E40')
...
plt.savefig('plotly_add_pitch.png', format='png', bbox_inches='tight', pad_inches=0)

enter image description here

import plotly
import plotly.graph_objects as go
from PIL import Image

img = Image.open('./plotly_add_pitch.png')
fig = go.Figure()

fig.add_trace(
    go.Scatter(x=[0, 110, 112, 114, 115, 130],
               y=[0, 65, 55, 49, 53, 90],
                mode='markers',
                marker=dict(size=15,
                color='red'),
               name='Salah'
))

# axis hide、yaxis reversed
fig.update_layout(
    autosize=False,
    width=1163,
    height=783,
    xaxis=dict(visible=True,autorange=True),
    yaxis=dict(visible=True,autorange='reversed')
)

# background image add
fig.add_layout_image(
    dict(source=img,
         xref='x',
         yref='y',
         x=0,
         y=0,
         sizex=135,
         sizey=95,
         sizing='stretch',
         opacity=0.9,
         layer='below')
)

# Set templates
fig.update_layout(template="plotly_white")

fig.show()

enter image description here

The X and Y axes are shown, but you should change them to visible=False in practice.

r-beginners
  • 31,170
  • 3
  • 14
  • 32