拖放后将元素的位置保存到本地文件
Save Elements' Locations to local file after dragging & dropping
我正在升级我的一个项目,该项目是根据球员在球场上的位置预测篮板球几率的。这是 link:http://okc-thunder-rebounds.herokuapp.com/.
我想通过启用拖放功能使其更加人性化。我的意思是,用户可以将代表球员的物品放在球场面板的任何地方。目前,当玩家被放置到我的模型中时,我很难导入他们的最终位置,因为之前,我使用 Python 和 Streamlit 进行开发,而现在,我正在使用 HTML、CSS和JavaScript。
我是后三者的新手,所以我找不到能够将数据直接 transport/import 到我的 python 代码的方法。我想可以先在本地保存数据,然后我可以使用 python 读取它们。
简而言之:如何在放置物品后立即记录它们的位置(以像素为单位),并且如果可能的话,它们的记录可以在移动时更改?
这是我为拖放它所做的工作:
<html><head><style>
#red_button1 {
position: absolute;
top:10px;
left:20px;
z-index: 9;
background-color: #f1f1f1;
text-align: center;
border: 1px solid #d3d3d3;
display:block;
}
#def1 {
cursor: move;
z-index: 10;
background-color: #FF0000;
color: #000;
border: 1px solid #d3d3d3;
}
#red_button2 {
position: absolute;
top:60px;
left:20px;
z-index: 9;
background-color: #f1f1f1;
text-align: center;
border: 1px solid #d3d3d3;
display:block;
}
#def2 {
cursor: move;
z-index: 10;
background-color: #FF0000;
color: #000;
border: 1px solid #d3d3d3;
}
#red_button3 {
position: absolute;
top:110px;
left:20px;
z-index: 9;
background-color: #f1f1f1;
text-align: center;
border: 1px solid #d3d3d3;
display:block;
}
#def3 {
cursor: move;
z-index: 10;
background-color: #FF0000;
color: #000;
border: 1px solid #d3d3d3;
}
#red_button4 {
position: absolute;
top:160px;
left:20px;
z-index: 9;
background-color: #f1f1f1;
text-align: center;
border: 1px solid #d3d3d3;
display:block;
}
#def4 {
cursor: move;
z-index: 10;
background-color: #FF0000;
color: #000;
border: 1px solid #d3d3d3;
}
#red_button5 {
position: absolute;
top:210px;
left:20px;
z-index: 9;
background-color: #f1f1f1;
text-align: center;
border: 1px solid #d3d3d3;
display:block;
}
#def5 {
cursor: move;
z-index: 10;
background-color: #FF0000;
color: #000;
border: 1px solid #d3d3d3;
}
#blue_button1 {
position: absolute;
top:10px;
left:60px;
z-index: 9;
background-color: #f1f1f1;
text-align: center;
border: 1px solid #d3d3d3;
display:block;
}
#off1 {
cursor: move;
z-index: 10;
background-color: #0000FF;
color: #000;
border: 1px solid #d3d3d3;
}
#blue_button2 {
position: absolute;
top:60px;
left:60px;
z-index: 9;
background-color: #f1f1f1;
text-align: center;
border: 1px solid #d3d3d3;
display:block;
}
#off2 {
cursor: move;
z-index: 10;
background-color: #0000FF;
color: #000;
border: 1px solid #d3d3d3;
}
#blue_button3 {
position: absolute;
top:110px;
left:60px;
z-index: 9;
background-color: #f1f1f1;
text-align: center;
border: 1px solid #d3d3d3;
display:block;
}
#off3 {
cursor: move;
z-index: 10;
background-color: #0000FF;
color: #000;
border: 1px solid #d3d3d3;
}
#blue_button4 {
position: absolute;
top:160px;
left:60px;
z-index: 9;
background-color: #f1f1f1;
text-align: center;
border: 1px solid #d3d3d3;
display:block;
}
#off4 {
cursor: move;
z-index: 10;
background-color: #0000FF;
color: #000;
border: 1px solid #d3d3d3;
}
#blue_button5 {
position: absolute;
top:210px;
left:60px;
z-index: 9;
background-color: #f1f1f1;
text-align: center;
border: 1px solid #d3d3d3;
display:block;
}
#off5 {
cursor: move;
z-index: 10;
background-color: #0000FF;
color: #000;
border: 1px solid #d3d3d3;
}
#panel {
width: 350px;
height: 350px;
background-size: contain;
}
#display {
position: absolute;
top:500px;
left:10px;
z-index: 9;
background-color: #f1f1f1;
text-align: center;
border: 1px solid #d3d3d3;
display:block;
width: 100px;
}
</style>
</head><body>
<div id="panel" style="background-image: url('court.png');">
<div id="red_button1">
<div id="def1">1</div>
</div>
<div id="red_button2">
<div id="def2">2</div>
</div>
<div id="red_button3">
<div id="def3">3</div>
</div>
<div id="red_button4">
<div id="def4">4</div>
</div>
<div id="red_button5">
<div id="def5">5</div>
</div>
<div id="blue_button1">
<div id="off1" style="color:white">1</div>
</div>
<div id="blue_button2">
<div id="off2" style="color:white">2</div>
</div>
<div id="blue_button3">
<div id="off3" style="color:white">3</div>
</div>
<div id="blue_button4">
<div id="off4" style="color:white">4</div>
</div>
<<div id="blue_button5">
<div id="off5" style="color:white">5</div>
</div>
</div>
<input type="button" value="Show Positions" onclick="SHowDiv()">
<div id="display"></div>
<script>
//Make the DIV elements draggagle:
dragElement(document.getElementById("red_button1"));
dragElement(document.getElementById("red_button2"));
dragElement(document.getElementById("red_button3"));
dragElement(document.getElementById("red_button4"));
dragElement(document.getElementById("red_button5"));
dragElement(document.getElementById("blue_button1"));
dragElement(document.getElementById("blue_button2"));
dragElement(document.getElementById("blue_button3"));
dragElement(document.getElementById("blue_button4"));
dragElement(document.getElementById("blue_button5"));
//output their final locations
// getOffset(document.getElementById("red_button1"));
// getOffset(document.getElementById("red_button2"));
// getOffset(document.getElementById("red_button3"));
// getOffset(document.getElementById("red_button4"));
// getOffset(document.getElementById("red_button5"));
// getOffset(document.getElementById("blue_button1"));
// getOffset(document.getElementById("blue_button2"));
// getOffset(document.getElementById("blue_button3"));
// getOffset(document.getElementById("blue_button4"));
// getOffset(document.getElementById("blue_button5"));
function dragElement(elmnt) {
var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
elmnt.onmousedown = dragMouseDown;
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
// get the mouse cursor position at startup:
pos3 = e.clientX;
pos4 = e.clientY;
document.onmouseup = closeDragElement;
// call a function whenever the cursor moves:
document.onmousemove = elementDrag;
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
// calculate the new cursor position:
pos1 = pos3 - e.clientX;
pos2 = pos4 - e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
// set the element's new position:
elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
}
function closeDragElement() {
/* stop moving when mouse button is released:*/
document.onmouseup = null;
document.onmousemove = null;
}
}
function getOffset(elmnt) {
return {top: elmnt.style.top, left: elmnt.style.left};
}
String.prototype.trimRight = function(charlist) {
if (charlist === undefined)
charlist = "\s";
return this.replace(new RegExp("[" + charlist + "]+$"), "");
};
function SHowDiv()
{
document.getElementById("display").innerHTML =
getOffset(document.getElementById("red_button1")).top.trimRight("px") + ", " + getOffset(document.getElementById("red_button1")).left.trimRight("px") + "<br>" +
getOffset(document.getElementById("red_button2")).top.trimRight("px") + ", " + getOffset(document.getElementById("red_button2")).left.trimRight("px") + "<br>" +
getOffset(document.getElementById("red_button3")).top.trimRight("px") + ", " + getOffset(document.getElementById("red_button3")).left.trimRight("px") + "<br>" +
getOffset(document.getElementById("red_button4")).top.trimRight("px") + ", " + getOffset(document.getElementById("red_button4")).left.trimRight("px") + "<br>" +
getOffset(document.getElementById("red_button5")).top.trimRight("px") + ", " + getOffset(document.getElementById("red_button5")).left.trimRight("px") + "<br>" +
getOffset(document.getElementById("blue_button1")).top.trimRight("px") + ", " + getOffset(document.getElementById("blue_button1")).left.trimRight("px") + "<br>" +
getOffset(document.getElementById("blue_button2")).top.trimRight("px") + ", " + getOffset(document.getElementById("blue_button2")).left.trimRight("px") + "<br>" +
getOffset(document.getElementById("blue_button3")).top.trimRight("px") + ", " + getOffset(document.getElementById("blue_button3")).left.trimRight("px") + "<br>" +
getOffset(document.getElementById("blue_button4")).top.trimRight("px") + ", " + getOffset(document.getElementById("blue_button4")).left.trimRight("px") + "<br>" +
getOffset(document.getElementById("blue_button5")).top.trimRight("px") + ", " + getOffset(document.getElementById("blue_button5")).left.trimRight("px");
}
</script>
</body></html>
这里是我的原创作品的代码:
import streamlit as st
from joblib import load
import seaborn as sns
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Circle, Rectangle, Arc
import plotly
from plotly.subplots import make_subplots
import plotly.graph_objects as go
# draw the half court
def create_half_court(ax=None, three_line='mens', court_color='#dfbb85',
lw=3, lines_color='black', lines_alpha=0.5,
paint_fill='blue', paint_alpha=0.4,
inner_arc=False):
"""
Version 2020.2.19
Creates NBA Basketball Half Court
Dimensions are in feet (Court is 97x50 ft)
Created by: Rob Mulla / https://github.com/RobMulla
* Note that this function uses "feet" as the unit of measure.
* Our data is within this range: -47 <= x <= 47, -25 <= y <= 25.
* So to plot X/Y positions first convert to feet like this:
```
loc['loc_x_'] = 47 - loc['loc_x_']
loc['loc_y_'] = 25 - loc['loc_y_']
```
ax: matplotlib axes if None gets current axes using `plt.gca`
three_line: 'mens', 'womens' or 'both' defines 3 point line plotted
court_color : (hex) Color of the court
lw : line width
lines_color : Color of the lines
lines_alpha : transparency of lines
paint_fill : Color inside the paint
paint_alpha : transparency of the "paint"
inner_arc : paint the dotted inner arc
"""
if ax is None:
ax = plt.gca()
# Create Pathes for Court Lines
center_circle = Circle((50 / 2, 94 / 2), 6,
linewidth=lw, color=lines_color, lw=lw,
fill=False, alpha=lines_alpha)
hoop = Circle((50 / 2, 5.25), 1.5 / 2,
linewidth=lw, color=lines_color, lw=lw,
fill=False, alpha=lines_alpha)
# Paint - 18 Feet 10 inches which converts to 18.833333 feet - gross!
paint = Rectangle(((50 / 2) - 6, 0), 12, 18.833333,
fill=paint_fill, alpha=paint_alpha,
lw=lw, edgecolor=None)
paint_boarder = Rectangle(((50 / 2) - 6, 0), 12, 18.833333,
fill=False, alpha=lines_alpha,
lw=lw, edgecolor=lines_color)
arc = Arc((50 / 2, 18.833333), 12, 12, theta1=-
0, theta2=180, color=lines_color, lw=lw,
alpha=lines_alpha)
block1 = Rectangle(((50 / 2) - 6 - 0.666, 7), 0.666, 1,
fill=True, alpha=lines_alpha,
lw=0, edgecolor=lines_color,
facecolor=lines_color)
block2 = Rectangle(((50 / 2) + 6, 7), 0.666, 1,
fill=True, alpha=lines_alpha,
lw=0, edgecolor=lines_color,
facecolor=lines_color)
ax.add_patch(block1)
ax.add_patch(block2)
l1 = Rectangle(((50 / 2) - 6 - 0.666, 11), 0.666, 0.166,
fill=True, alpha=lines_alpha,
lw=0, edgecolor=lines_color,
facecolor=lines_color)
l2 = Rectangle(((50 / 2) - 6 - 0.666, 14), 0.666, 0.166,
fill=True, alpha=lines_alpha,
lw=0, edgecolor=lines_color,
facecolor=lines_color)
l3 = Rectangle(((50 / 2) - 6 - 0.666, 17), 0.666, 0.166,
fill=True, alpha=lines_alpha,
lw=0, edgecolor=lines_color,
facecolor=lines_color)
ax.add_patch(l1)
ax.add_patch(l2)
ax.add_patch(l3)
l4 = Rectangle(((50 / 2) + 6, 11), 0.666, 0.166,
fill=True, alpha=lines_alpha,
lw=0, edgecolor=lines_color,
facecolor=lines_color)
l5 = Rectangle(((50 / 2) + 6, 14), 0.666, 0.166,
fill=True, alpha=lines_alpha,
lw=0, edgecolor=lines_color,
facecolor=lines_color)
l6 = Rectangle(((50 / 2) + 6, 17), 0.666, 0.166,
fill=True, alpha=lines_alpha,
lw=0, edgecolor=lines_color,
facecolor=lines_color)
ax.add_patch(l4)
ax.add_patch(l5)
ax.add_patch(l6)
# 3 Point Line
if (three_line == 'mens') | (three_line == 'both'):
# 22' 1.75" distance to center of hoop
three_pt = Arc((50 / 2, 6.25), 44.291, 44.291, theta1=12,
theta2=168, color=lines_color, lw=lw,
alpha=lines_alpha)
# 4.25 feet max to sideline for mens
ax.plot((3.34, 3.34), (0, 11.20),
color=lines_color, lw=lw, alpha=lines_alpha)
ax.plot((50 - 3.34, 50 - 3.34), (0, 11.20),
color=lines_color, lw=lw, alpha=lines_alpha)
ax.add_patch(three_pt)
if (three_line == 'womens') | (three_line == 'both'):
# womens 3
three_pt_w = Arc((50 / 2, 6.25), 20.75 * 2, 20.75 * 2, theta1=5,
theta2=175, color=lines_color, lw=lw, alpha=lines_alpha)
# 4.25 inches max to sideline for mens
ax.plot((4.25, 4.25), (0, 8), color=lines_color,
lw=lw, alpha=lines_alpha)
ax.plot((50 - 4.25, 50 - 4.25), (0, 8.1),
color=lines_color, lw=lw, alpha=lines_alpha)
ax.add_patch(three_pt_w)
# Add Patches
ax.add_patch(paint)
ax.add_patch(paint_boarder)
ax.add_patch(center_circle)
ax.add_patch(hoop)
ax.add_patch(arc)
if inner_arc:
inner_arc = Arc((50 / 2, 18.833333), 12, 12, theta1=180,
theta2=0, color=lines_color, lw=lw,
alpha=lines_alpha, ls='--')
ax.add_patch(inner_arc)
# Restricted Area Marker
restricted_area = Arc((50 / 2, 6.25), 8, 8, theta1=0,
theta2=180, color=lines_color, lw=lw,
alpha=lines_alpha)
ax.add_patch(restricted_area)
# Backboard
ax.plot(((50 / 2) - 3, (50 / 2) + 3), (4, 4),
color=lines_color, lw=lw * 1.5, alpha=lines_alpha)
ax.plot((50 / 2, 50 / 2), (4.3, 4), color=lines_color,
lw=lw, alpha=lines_alpha)
# Half Court Line
ax.axhline(94 / 2, color=lines_color, lw=lw, alpha=lines_alpha)
# Plot Limit
ax.set_xlim(0, 50)
ax.set_ylim(0, 94 / 2 + 2)
ax.set_facecolor(court_color)
ax.set_xticks([])
ax.set_yticks([])
ax.set_xlabel('')
return ax
def slider_setting(condition, position):
x = st.sidebar.slider('Coordinate X for ' + condition + ' Player ' + str(position), min_value=-47., max_value=47.,
value=0., step=0.1)
y = st.sidebar.slider('Coordinate Y for ' + condition + ' Player ' + str(position), min_value=-25., max_value=25.,
value=0., step=0.1)
return x, y
def locate(locations, court):
off_ = pd.DataFrame({
'X': [47 - location[0] if location[0] >= 0 else 47 + location[0] for location in locations[:5]],
'Y': [25 - location[1] for location in locations[:5]]
})
def_ = pd.DataFrame({
'X': [47 - location[0] if location[0] >= 0 else 47 + location[0] for location in locations[5:]],
'Y': [25 - location[1] for location in locations[5:]]
})
off_.plot(x='Y', y='X', style='X', ax=court, alpha=1, label='Offensive players')
def_.plot(x='Y', y='X', style='X', ax=court, alpha=1, label='Defensive players')
label_point(off_, court)
label_point(def_, court)
def label_point(df, ax):
for i, point in df.iterrows():
ax.text(point[df.columns[1]]+ .2, point[df.columns[0]], str(int(i+1)), size=20)
def preprocess(locations):
input = pd.DataFrame(
{
'AtShot_loc_x_off_player_1': [locations[0][0]],
'AtShot_loc_y_off_player_1': [locations[0][1]],
'AtShot_loc_x_off_player_2': [locations[1][0]],
'AtShot_loc_y_off_player_2': [locations[1][1]],
'AtShot_loc_x_off_player_3': [locations[2][0]],
'AtShot_loc_y_off_player_3': [locations[2][1]],
'AtShot_loc_x_off_player_4': [locations[3][0]],
'AtShot_loc_y_off_player_4': [locations[3][1]],
'AtShot_loc_x_off_player_5': [locations[4][0]],
'AtShot_loc_y_off_player_5': [locations[4][1]],
'AtShot_loc_x_def_player_1': [locations[5][0]],
'AtShot_loc_y_def_player_1': [locations[5][1]],
'AtShot_loc_x_def_player_2': [locations[6][0]],
'AtShot_loc_y_def_player_2': [locations[6][1]],
'AtShot_loc_x_def_player_3': [locations[7][0]],
'AtShot_loc_y_def_player_3': [locations[7][1]],
'AtShot_loc_x_def_player_4': [locations[8][0]],
'AtShot_loc_y_def_player_4': [locations[8][1]],
'AtShot_loc_x_def_player_5': [locations[9][0]],
'AtShot_loc_y_def_player_5': [locations[9][1]]
}
)
input[[col for col in input.columns if '_y_' in col]] = (25 - input[
[col for col in input.columns if '_y_' in col]]) / (25 - (-25))
input[[col for col in input.columns if '_x_' in col]] = (47 - input[
[col for col in input.columns if '_x_' in col]]) / (47 - (-47))
return input
def stack_bar(offensive_proba, defensive_proba):
fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing = 0.15)
probas = ['Offending<br>Team<br>', 'Deffending<br>Team<br>'] # text to show
# Move common code to a function to reuse multiple times:
def plot_bar(probas, visible):
x_list = [offensive_proba, defensive_proba]
for x, proba in zip(x_list, probas):
fig.add_trace(
go.Bar(x=[x * 100], # just one number value for a bar
y=['Probability'],
name='Probability',
visible=visible,
opacity=1,
orientation='h',
text=(x),
textposition='inside',
texttemplate=proba + '%{text:.1%}'),
row=1, col=1)
plot_bar(probas, True)
fig.update_layout(barmode='stack')
# Controlling text fontsize with uniformtext
fig.update_layout(showlegend=False) # hide ledend
# Set axis font:
fig.update_yaxes(tickfont=dict(size=14))
st.plotly_chart(fig, use_container_width=True)
if __name__ == '__main__':
# this is the trained model
LDA = load('LDA.joblib')
st.write('''
# Welcome to Rebound Probability Prediction!
''')
# placeholder
imageLocation = st.empty()
fig, court_ax = plt.subplots(1, 1, figsize=(11, 11.2))
create_half_court(court_ax,
three_line='mens',
paint_alpha=0.4,
inner_arc=True)
# plot the half court without scatter
imageLocation.pyplot(fig)
st.sidebar.header('Input players\' locations when the ball is shot:')
locations = []
for condition in ['Offensive', 'Defensive']:
for i in range(5):
x, y = slider_setting(condition, i + 1)
locations.append((x, y))
button = st.sidebar.button('Confirm')
if button:
# plot the locations of players on the court
locate(locations, court_ax)
imageLocation.pyplot(fig)
# pre-processing
input = preprocess(locations)
## predict
# individual
individual_prediction = LDA.predict_proba(input)[0]
# team
offensive_proba = sum(individual_prediction[:5])
defensive_proba = sum(individual_prediction[5:])
## data vis
# individual
results = pd.DataFrame(
{
'Players': ['Offensive Player 1', 'Offensive Player 2', 'Offensive Player 3', 'Offensive Player 4',
'Offensive Player 5',
'Defensive Player 1', 'Defensive Player 2', 'Defensive Player 3', 'Defensive Player 4',
'Defensive Player 5'],
'Probability': individual_prediction
}
)
st.write('## Individual Probability')
cm = sns.light_palette("orange", as_cmap=True)
results = results.sort_values(by=['Probability'], ascending=False)
st.dataframe(results.style.background_gradient(cmap=cm).set_precision(2))
# team
st.write('## Team Probability')
stack_bar(offensive_proba, defensive_proba)
# celebrate
st.balloons()
我后来通过让 Flask 直接访问这些位置来更改我的解决方案。它只需要将值赋值给一个不可见的textarea,这样我们在使用Flask的时候就可以访问它了。
代码如下:
HTML:
<form method="post" action="{{ url_for('main') }}" id="form">
<div class="form-group">
<textarea name="hidden" class="form-control" style="display: none;" value="" id="hidden"></textarea>
</div>
<input type="submit" value="Confirm" onclick="Assign()" align="center">
</form>
<script>
function Assign()
{
document.getElementById("hidden").value = "some values";
}
Python:
@app.route('/', methods=['GET', 'POST'])
def main():
if request.method == 'POST':
value_you_want = request.form['hidden']
我正在升级我的一个项目,该项目是根据球员在球场上的位置预测篮板球几率的。这是 link:http://okc-thunder-rebounds.herokuapp.com/.
我想通过启用拖放功能使其更加人性化。我的意思是,用户可以将代表球员的物品放在球场面板的任何地方。目前,当玩家被放置到我的模型中时,我很难导入他们的最终位置,因为之前,我使用 Python 和 Streamlit 进行开发,而现在,我正在使用 HTML、CSS和JavaScript。
我是后三者的新手,所以我找不到能够将数据直接 transport/import 到我的 python 代码的方法。我想可以先在本地保存数据,然后我可以使用 python 读取它们。
简而言之:如何在放置物品后立即记录它们的位置(以像素为单位),并且如果可能的话,它们的记录可以在移动时更改?
这是我为拖放它所做的工作:
<html><head><style>
#red_button1 {
position: absolute;
top:10px;
left:20px;
z-index: 9;
background-color: #f1f1f1;
text-align: center;
border: 1px solid #d3d3d3;
display:block;
}
#def1 {
cursor: move;
z-index: 10;
background-color: #FF0000;
color: #000;
border: 1px solid #d3d3d3;
}
#red_button2 {
position: absolute;
top:60px;
left:20px;
z-index: 9;
background-color: #f1f1f1;
text-align: center;
border: 1px solid #d3d3d3;
display:block;
}
#def2 {
cursor: move;
z-index: 10;
background-color: #FF0000;
color: #000;
border: 1px solid #d3d3d3;
}
#red_button3 {
position: absolute;
top:110px;
left:20px;
z-index: 9;
background-color: #f1f1f1;
text-align: center;
border: 1px solid #d3d3d3;
display:block;
}
#def3 {
cursor: move;
z-index: 10;
background-color: #FF0000;
color: #000;
border: 1px solid #d3d3d3;
}
#red_button4 {
position: absolute;
top:160px;
left:20px;
z-index: 9;
background-color: #f1f1f1;
text-align: center;
border: 1px solid #d3d3d3;
display:block;
}
#def4 {
cursor: move;
z-index: 10;
background-color: #FF0000;
color: #000;
border: 1px solid #d3d3d3;
}
#red_button5 {
position: absolute;
top:210px;
left:20px;
z-index: 9;
background-color: #f1f1f1;
text-align: center;
border: 1px solid #d3d3d3;
display:block;
}
#def5 {
cursor: move;
z-index: 10;
background-color: #FF0000;
color: #000;
border: 1px solid #d3d3d3;
}
#blue_button1 {
position: absolute;
top:10px;
left:60px;
z-index: 9;
background-color: #f1f1f1;
text-align: center;
border: 1px solid #d3d3d3;
display:block;
}
#off1 {
cursor: move;
z-index: 10;
background-color: #0000FF;
color: #000;
border: 1px solid #d3d3d3;
}
#blue_button2 {
position: absolute;
top:60px;
left:60px;
z-index: 9;
background-color: #f1f1f1;
text-align: center;
border: 1px solid #d3d3d3;
display:block;
}
#off2 {
cursor: move;
z-index: 10;
background-color: #0000FF;
color: #000;
border: 1px solid #d3d3d3;
}
#blue_button3 {
position: absolute;
top:110px;
left:60px;
z-index: 9;
background-color: #f1f1f1;
text-align: center;
border: 1px solid #d3d3d3;
display:block;
}
#off3 {
cursor: move;
z-index: 10;
background-color: #0000FF;
color: #000;
border: 1px solid #d3d3d3;
}
#blue_button4 {
position: absolute;
top:160px;
left:60px;
z-index: 9;
background-color: #f1f1f1;
text-align: center;
border: 1px solid #d3d3d3;
display:block;
}
#off4 {
cursor: move;
z-index: 10;
background-color: #0000FF;
color: #000;
border: 1px solid #d3d3d3;
}
#blue_button5 {
position: absolute;
top:210px;
left:60px;
z-index: 9;
background-color: #f1f1f1;
text-align: center;
border: 1px solid #d3d3d3;
display:block;
}
#off5 {
cursor: move;
z-index: 10;
background-color: #0000FF;
color: #000;
border: 1px solid #d3d3d3;
}
#panel {
width: 350px;
height: 350px;
background-size: contain;
}
#display {
position: absolute;
top:500px;
left:10px;
z-index: 9;
background-color: #f1f1f1;
text-align: center;
border: 1px solid #d3d3d3;
display:block;
width: 100px;
}
</style>
</head><body>
<div id="panel" style="background-image: url('court.png');">
<div id="red_button1">
<div id="def1">1</div>
</div>
<div id="red_button2">
<div id="def2">2</div>
</div>
<div id="red_button3">
<div id="def3">3</div>
</div>
<div id="red_button4">
<div id="def4">4</div>
</div>
<div id="red_button5">
<div id="def5">5</div>
</div>
<div id="blue_button1">
<div id="off1" style="color:white">1</div>
</div>
<div id="blue_button2">
<div id="off2" style="color:white">2</div>
</div>
<div id="blue_button3">
<div id="off3" style="color:white">3</div>
</div>
<div id="blue_button4">
<div id="off4" style="color:white">4</div>
</div>
<<div id="blue_button5">
<div id="off5" style="color:white">5</div>
</div>
</div>
<input type="button" value="Show Positions" onclick="SHowDiv()">
<div id="display"></div>
<script>
//Make the DIV elements draggagle:
dragElement(document.getElementById("red_button1"));
dragElement(document.getElementById("red_button2"));
dragElement(document.getElementById("red_button3"));
dragElement(document.getElementById("red_button4"));
dragElement(document.getElementById("red_button5"));
dragElement(document.getElementById("blue_button1"));
dragElement(document.getElementById("blue_button2"));
dragElement(document.getElementById("blue_button3"));
dragElement(document.getElementById("blue_button4"));
dragElement(document.getElementById("blue_button5"));
//output their final locations
// getOffset(document.getElementById("red_button1"));
// getOffset(document.getElementById("red_button2"));
// getOffset(document.getElementById("red_button3"));
// getOffset(document.getElementById("red_button4"));
// getOffset(document.getElementById("red_button5"));
// getOffset(document.getElementById("blue_button1"));
// getOffset(document.getElementById("blue_button2"));
// getOffset(document.getElementById("blue_button3"));
// getOffset(document.getElementById("blue_button4"));
// getOffset(document.getElementById("blue_button5"));
function dragElement(elmnt) {
var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
elmnt.onmousedown = dragMouseDown;
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
// get the mouse cursor position at startup:
pos3 = e.clientX;
pos4 = e.clientY;
document.onmouseup = closeDragElement;
// call a function whenever the cursor moves:
document.onmousemove = elementDrag;
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
// calculate the new cursor position:
pos1 = pos3 - e.clientX;
pos2 = pos4 - e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
// set the element's new position:
elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
}
function closeDragElement() {
/* stop moving when mouse button is released:*/
document.onmouseup = null;
document.onmousemove = null;
}
}
function getOffset(elmnt) {
return {top: elmnt.style.top, left: elmnt.style.left};
}
String.prototype.trimRight = function(charlist) {
if (charlist === undefined)
charlist = "\s";
return this.replace(new RegExp("[" + charlist + "]+$"), "");
};
function SHowDiv()
{
document.getElementById("display").innerHTML =
getOffset(document.getElementById("red_button1")).top.trimRight("px") + ", " + getOffset(document.getElementById("red_button1")).left.trimRight("px") + "<br>" +
getOffset(document.getElementById("red_button2")).top.trimRight("px") + ", " + getOffset(document.getElementById("red_button2")).left.trimRight("px") + "<br>" +
getOffset(document.getElementById("red_button3")).top.trimRight("px") + ", " + getOffset(document.getElementById("red_button3")).left.trimRight("px") + "<br>" +
getOffset(document.getElementById("red_button4")).top.trimRight("px") + ", " + getOffset(document.getElementById("red_button4")).left.trimRight("px") + "<br>" +
getOffset(document.getElementById("red_button5")).top.trimRight("px") + ", " + getOffset(document.getElementById("red_button5")).left.trimRight("px") + "<br>" +
getOffset(document.getElementById("blue_button1")).top.trimRight("px") + ", " + getOffset(document.getElementById("blue_button1")).left.trimRight("px") + "<br>" +
getOffset(document.getElementById("blue_button2")).top.trimRight("px") + ", " + getOffset(document.getElementById("blue_button2")).left.trimRight("px") + "<br>" +
getOffset(document.getElementById("blue_button3")).top.trimRight("px") + ", " + getOffset(document.getElementById("blue_button3")).left.trimRight("px") + "<br>" +
getOffset(document.getElementById("blue_button4")).top.trimRight("px") + ", " + getOffset(document.getElementById("blue_button4")).left.trimRight("px") + "<br>" +
getOffset(document.getElementById("blue_button5")).top.trimRight("px") + ", " + getOffset(document.getElementById("blue_button5")).left.trimRight("px");
}
</script>
</body></html>
这里是我的原创作品的代码:
import streamlit as st
from joblib import load
import seaborn as sns
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Circle, Rectangle, Arc
import plotly
from plotly.subplots import make_subplots
import plotly.graph_objects as go
# draw the half court
def create_half_court(ax=None, three_line='mens', court_color='#dfbb85',
lw=3, lines_color='black', lines_alpha=0.5,
paint_fill='blue', paint_alpha=0.4,
inner_arc=False):
"""
Version 2020.2.19
Creates NBA Basketball Half Court
Dimensions are in feet (Court is 97x50 ft)
Created by: Rob Mulla / https://github.com/RobMulla
* Note that this function uses "feet" as the unit of measure.
* Our data is within this range: -47 <= x <= 47, -25 <= y <= 25.
* So to plot X/Y positions first convert to feet like this:
```
loc['loc_x_'] = 47 - loc['loc_x_']
loc['loc_y_'] = 25 - loc['loc_y_']
```
ax: matplotlib axes if None gets current axes using `plt.gca`
three_line: 'mens', 'womens' or 'both' defines 3 point line plotted
court_color : (hex) Color of the court
lw : line width
lines_color : Color of the lines
lines_alpha : transparency of lines
paint_fill : Color inside the paint
paint_alpha : transparency of the "paint"
inner_arc : paint the dotted inner arc
"""
if ax is None:
ax = plt.gca()
# Create Pathes for Court Lines
center_circle = Circle((50 / 2, 94 / 2), 6,
linewidth=lw, color=lines_color, lw=lw,
fill=False, alpha=lines_alpha)
hoop = Circle((50 / 2, 5.25), 1.5 / 2,
linewidth=lw, color=lines_color, lw=lw,
fill=False, alpha=lines_alpha)
# Paint - 18 Feet 10 inches which converts to 18.833333 feet - gross!
paint = Rectangle(((50 / 2) - 6, 0), 12, 18.833333,
fill=paint_fill, alpha=paint_alpha,
lw=lw, edgecolor=None)
paint_boarder = Rectangle(((50 / 2) - 6, 0), 12, 18.833333,
fill=False, alpha=lines_alpha,
lw=lw, edgecolor=lines_color)
arc = Arc((50 / 2, 18.833333), 12, 12, theta1=-
0, theta2=180, color=lines_color, lw=lw,
alpha=lines_alpha)
block1 = Rectangle(((50 / 2) - 6 - 0.666, 7), 0.666, 1,
fill=True, alpha=lines_alpha,
lw=0, edgecolor=lines_color,
facecolor=lines_color)
block2 = Rectangle(((50 / 2) + 6, 7), 0.666, 1,
fill=True, alpha=lines_alpha,
lw=0, edgecolor=lines_color,
facecolor=lines_color)
ax.add_patch(block1)
ax.add_patch(block2)
l1 = Rectangle(((50 / 2) - 6 - 0.666, 11), 0.666, 0.166,
fill=True, alpha=lines_alpha,
lw=0, edgecolor=lines_color,
facecolor=lines_color)
l2 = Rectangle(((50 / 2) - 6 - 0.666, 14), 0.666, 0.166,
fill=True, alpha=lines_alpha,
lw=0, edgecolor=lines_color,
facecolor=lines_color)
l3 = Rectangle(((50 / 2) - 6 - 0.666, 17), 0.666, 0.166,
fill=True, alpha=lines_alpha,
lw=0, edgecolor=lines_color,
facecolor=lines_color)
ax.add_patch(l1)
ax.add_patch(l2)
ax.add_patch(l3)
l4 = Rectangle(((50 / 2) + 6, 11), 0.666, 0.166,
fill=True, alpha=lines_alpha,
lw=0, edgecolor=lines_color,
facecolor=lines_color)
l5 = Rectangle(((50 / 2) + 6, 14), 0.666, 0.166,
fill=True, alpha=lines_alpha,
lw=0, edgecolor=lines_color,
facecolor=lines_color)
l6 = Rectangle(((50 / 2) + 6, 17), 0.666, 0.166,
fill=True, alpha=lines_alpha,
lw=0, edgecolor=lines_color,
facecolor=lines_color)
ax.add_patch(l4)
ax.add_patch(l5)
ax.add_patch(l6)
# 3 Point Line
if (three_line == 'mens') | (three_line == 'both'):
# 22' 1.75" distance to center of hoop
three_pt = Arc((50 / 2, 6.25), 44.291, 44.291, theta1=12,
theta2=168, color=lines_color, lw=lw,
alpha=lines_alpha)
# 4.25 feet max to sideline for mens
ax.plot((3.34, 3.34), (0, 11.20),
color=lines_color, lw=lw, alpha=lines_alpha)
ax.plot((50 - 3.34, 50 - 3.34), (0, 11.20),
color=lines_color, lw=lw, alpha=lines_alpha)
ax.add_patch(three_pt)
if (three_line == 'womens') | (three_line == 'both'):
# womens 3
three_pt_w = Arc((50 / 2, 6.25), 20.75 * 2, 20.75 * 2, theta1=5,
theta2=175, color=lines_color, lw=lw, alpha=lines_alpha)
# 4.25 inches max to sideline for mens
ax.plot((4.25, 4.25), (0, 8), color=lines_color,
lw=lw, alpha=lines_alpha)
ax.plot((50 - 4.25, 50 - 4.25), (0, 8.1),
color=lines_color, lw=lw, alpha=lines_alpha)
ax.add_patch(three_pt_w)
# Add Patches
ax.add_patch(paint)
ax.add_patch(paint_boarder)
ax.add_patch(center_circle)
ax.add_patch(hoop)
ax.add_patch(arc)
if inner_arc:
inner_arc = Arc((50 / 2, 18.833333), 12, 12, theta1=180,
theta2=0, color=lines_color, lw=lw,
alpha=lines_alpha, ls='--')
ax.add_patch(inner_arc)
# Restricted Area Marker
restricted_area = Arc((50 / 2, 6.25), 8, 8, theta1=0,
theta2=180, color=lines_color, lw=lw,
alpha=lines_alpha)
ax.add_patch(restricted_area)
# Backboard
ax.plot(((50 / 2) - 3, (50 / 2) + 3), (4, 4),
color=lines_color, lw=lw * 1.5, alpha=lines_alpha)
ax.plot((50 / 2, 50 / 2), (4.3, 4), color=lines_color,
lw=lw, alpha=lines_alpha)
# Half Court Line
ax.axhline(94 / 2, color=lines_color, lw=lw, alpha=lines_alpha)
# Plot Limit
ax.set_xlim(0, 50)
ax.set_ylim(0, 94 / 2 + 2)
ax.set_facecolor(court_color)
ax.set_xticks([])
ax.set_yticks([])
ax.set_xlabel('')
return ax
def slider_setting(condition, position):
x = st.sidebar.slider('Coordinate X for ' + condition + ' Player ' + str(position), min_value=-47., max_value=47.,
value=0., step=0.1)
y = st.sidebar.slider('Coordinate Y for ' + condition + ' Player ' + str(position), min_value=-25., max_value=25.,
value=0., step=0.1)
return x, y
def locate(locations, court):
off_ = pd.DataFrame({
'X': [47 - location[0] if location[0] >= 0 else 47 + location[0] for location in locations[:5]],
'Y': [25 - location[1] for location in locations[:5]]
})
def_ = pd.DataFrame({
'X': [47 - location[0] if location[0] >= 0 else 47 + location[0] for location in locations[5:]],
'Y': [25 - location[1] for location in locations[5:]]
})
off_.plot(x='Y', y='X', style='X', ax=court, alpha=1, label='Offensive players')
def_.plot(x='Y', y='X', style='X', ax=court, alpha=1, label='Defensive players')
label_point(off_, court)
label_point(def_, court)
def label_point(df, ax):
for i, point in df.iterrows():
ax.text(point[df.columns[1]]+ .2, point[df.columns[0]], str(int(i+1)), size=20)
def preprocess(locations):
input = pd.DataFrame(
{
'AtShot_loc_x_off_player_1': [locations[0][0]],
'AtShot_loc_y_off_player_1': [locations[0][1]],
'AtShot_loc_x_off_player_2': [locations[1][0]],
'AtShot_loc_y_off_player_2': [locations[1][1]],
'AtShot_loc_x_off_player_3': [locations[2][0]],
'AtShot_loc_y_off_player_3': [locations[2][1]],
'AtShot_loc_x_off_player_4': [locations[3][0]],
'AtShot_loc_y_off_player_4': [locations[3][1]],
'AtShot_loc_x_off_player_5': [locations[4][0]],
'AtShot_loc_y_off_player_5': [locations[4][1]],
'AtShot_loc_x_def_player_1': [locations[5][0]],
'AtShot_loc_y_def_player_1': [locations[5][1]],
'AtShot_loc_x_def_player_2': [locations[6][0]],
'AtShot_loc_y_def_player_2': [locations[6][1]],
'AtShot_loc_x_def_player_3': [locations[7][0]],
'AtShot_loc_y_def_player_3': [locations[7][1]],
'AtShot_loc_x_def_player_4': [locations[8][0]],
'AtShot_loc_y_def_player_4': [locations[8][1]],
'AtShot_loc_x_def_player_5': [locations[9][0]],
'AtShot_loc_y_def_player_5': [locations[9][1]]
}
)
input[[col for col in input.columns if '_y_' in col]] = (25 - input[
[col for col in input.columns if '_y_' in col]]) / (25 - (-25))
input[[col for col in input.columns if '_x_' in col]] = (47 - input[
[col for col in input.columns if '_x_' in col]]) / (47 - (-47))
return input
def stack_bar(offensive_proba, defensive_proba):
fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing = 0.15)
probas = ['Offending<br>Team<br>', 'Deffending<br>Team<br>'] # text to show
# Move common code to a function to reuse multiple times:
def plot_bar(probas, visible):
x_list = [offensive_proba, defensive_proba]
for x, proba in zip(x_list, probas):
fig.add_trace(
go.Bar(x=[x * 100], # just one number value for a bar
y=['Probability'],
name='Probability',
visible=visible,
opacity=1,
orientation='h',
text=(x),
textposition='inside',
texttemplate=proba + '%{text:.1%}'),
row=1, col=1)
plot_bar(probas, True)
fig.update_layout(barmode='stack')
# Controlling text fontsize with uniformtext
fig.update_layout(showlegend=False) # hide ledend
# Set axis font:
fig.update_yaxes(tickfont=dict(size=14))
st.plotly_chart(fig, use_container_width=True)
if __name__ == '__main__':
# this is the trained model
LDA = load('LDA.joblib')
st.write('''
# Welcome to Rebound Probability Prediction!
''')
# placeholder
imageLocation = st.empty()
fig, court_ax = plt.subplots(1, 1, figsize=(11, 11.2))
create_half_court(court_ax,
three_line='mens',
paint_alpha=0.4,
inner_arc=True)
# plot the half court without scatter
imageLocation.pyplot(fig)
st.sidebar.header('Input players\' locations when the ball is shot:')
locations = []
for condition in ['Offensive', 'Defensive']:
for i in range(5):
x, y = slider_setting(condition, i + 1)
locations.append((x, y))
button = st.sidebar.button('Confirm')
if button:
# plot the locations of players on the court
locate(locations, court_ax)
imageLocation.pyplot(fig)
# pre-processing
input = preprocess(locations)
## predict
# individual
individual_prediction = LDA.predict_proba(input)[0]
# team
offensive_proba = sum(individual_prediction[:5])
defensive_proba = sum(individual_prediction[5:])
## data vis
# individual
results = pd.DataFrame(
{
'Players': ['Offensive Player 1', 'Offensive Player 2', 'Offensive Player 3', 'Offensive Player 4',
'Offensive Player 5',
'Defensive Player 1', 'Defensive Player 2', 'Defensive Player 3', 'Defensive Player 4',
'Defensive Player 5'],
'Probability': individual_prediction
}
)
st.write('## Individual Probability')
cm = sns.light_palette("orange", as_cmap=True)
results = results.sort_values(by=['Probability'], ascending=False)
st.dataframe(results.style.background_gradient(cmap=cm).set_precision(2))
# team
st.write('## Team Probability')
stack_bar(offensive_proba, defensive_proba)
# celebrate
st.balloons()
我后来通过让 Flask 直接访问这些位置来更改我的解决方案。它只需要将值赋值给一个不可见的textarea,这样我们在使用Flask的时候就可以访问它了。
代码如下: HTML:
<form method="post" action="{{ url_for('main') }}" id="form">
<div class="form-group">
<textarea name="hidden" class="form-control" style="display: none;" value="" id="hidden"></textarea>
</div>
<input type="submit" value="Confirm" onclick="Assign()" align="center">
</form>
<script>
function Assign()
{
document.getElementById("hidden").value = "some values";
}
Python:
@app.route('/', methods=['GET', 'POST'])
def main():
if request.method == 'POST':
value_you_want = request.form['hidden']