我在做以下事情时遇到了很大的困难。我有一个由 css 格式化的破折号应用程序,以显示在不同的容器中。标记为“hexgrid-1-container”的容器是最大的容器,而其他容器较小,并围绕该容器组织。我想更新我的破折号应用程序,以便每当单击另一个容器中的图形/图形时,它都会出现在“hexgrid-1-container”中,而之前位于“hexgrid-1-container”中的图形会出现在较小的容器中容器。
我有一个破折号应用程序,如下所示:
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
from jupyter_dash import JupyterDash
import plotly.express as px
import plotly.graph_objects as go
import pandas as pd
import sqlite3
import locale
import numpy as np
import plotly.figure_factory as ff
import plotly.express as px
# Set the locale for formatting
locale.setlocale(locale.LC_ALL, '')
app = dash.Dash(__name__)
app.layout = html.Div(className= 'container glass', children=[
html.Div(className='hexgrid-1-container', style={'border': '1px solid black'}, children=[
dcc.Graph(id='hexgrid-1', style={"height": "75%", "width": "100%"}, className='hexgrid1')
]),
html.Div(className='hexgrid-2-container', style={'border': '1px solid black'}, children=[
dcc.Graph(id='hexgrid-2', style={"height": "100%", "width": "100%"}, className='hexgrid2')
]),
html.Div(className='base-plot-container', style={'border': '1px solid black'}, children=[
dcc.Graph(id='base-plot', style={"height": "100%", "width": "100%"})
]),
html.Div(className='us-map-container', style={'border': '1px solid black'}, children=[
dcc.Graph(id='us-map-graph', style={"height": "100%", "width": "100%"})
]),
html.Div(className='fifth-container', style={'border': '1px solid black'}, children=[
# dcc.Graph(id='us-map-graph', style={"height": "100%", "width": "100%"})
#html.H2("5th Container")
]),
html.Div(className='sixth-container', style={'border': '1px solid black'}, children=[
# dcc.Graph(id='us-map-graph', style={"height": "100%", "width": "100%"})
#html.H2("6th Container")
])
])
@app.callback(
Output('hexgrid-1', 'figure'),
Input('hexgrid-1', 'id')
)
def render_hexgrid_1(_):
# Open a new database connection
conn = sqlite3.connect(r"C:\Users\HituJani\Downloads\txns.db")
# Fetching all columns in the transactions table
query = '''
PRAGMA table_info(transactions)
'''
# Fetch data
data = pd.read_sql_query(query, conn)
# Filtering out the relevant columns, this step can be skipped if you want all columns.
relevant_columns = data[data['name'].isin(['TranType', 'MessageTypeIdentifier', 'MerchantType', 'IResponseCode'])]
# Creating the hex grid with column names
plot_data = go.Scatter(x=relevant_columns.index, y=relevant_columns['name'], text=relevant_columns['name'],
marker=dict(symbol='hexagon', size=30), mode='markers+text')
layout = go.Layout(title="Select a Category")
return go.Figure(data=[plot_data], layout=layout)
@app.callback(
Output('hexgrid-2', 'figure'),
Output('hexgrid-2', 'style'),
Input('hexgrid-1', 'clickData')
)
def render_hexgrid_2(clickData):
# Open a new database connection
conn = sqlite3.connect(r"C:\Users\HituJani\Downloads\txns.db")
if clickData is None:
return go.Figure(), {"display": "none"}
else:
category = clickData['points'][0]['text']
# Fetching all columns in the transactions table
query = '''
PRAGMA table_info(transactions)
'''
# Fetch data
data = pd.read_sql_query(query, conn)
# Filtering out the relevant numerical features columns
relevant_columns = data[data['name'].isin(['TransactionAmount', 'OutstandingAmount', 'CurrentBalance', 'TotalOutStgAuthAmt'])]
# Generating random points on the surface of a sphere
phi = np.random.uniform(0, np.pi, len(relevant_columns))
theta = np.random.uniform(0, 2*np.pi, len(relevant_columns))
x = np.cos(theta) * np.sin(phi)
y = np.sin(theta) * np.sin(phi)
z = np.cos(phi)
# Create a 3D scatter plot with sphere markers
scatter = go.Scatter3d(
x=x,
y=y,
z=z,
mode='markers+text',
marker=dict(
size=12,
color=np.arange(len(relevant_columns)),
colorscale='Viridis',
symbol='circle',
opacity=0.8
),
text=relevant_columns['name'],
hoverinfo='text'
)
# Create a wireframe sphere using a mesh
u = np.linspace(0, 2 * np.pi, 100)
v = np.linspace(0, np.pi, 100)
x_sphere = np.outer(np.cos(u), np.sin(v))
y_sphere = np.outer(np.sin(u), np.sin(v))
z_sphere = np.outer(np.ones(np.size(u)), np.cos(v))
sphere = go.Mesh3d(x=x_sphere.ravel(),
y=y_sphere.ravel(),
z=z_sphere.ravel(),
opacity=0.1,
color='cyan')
# Combine the scatter plot and wireframe into a single figure
fig = go.Figure(data=[scatter, sphere])
fig.update_layout(
margin=dict(l=0, r=0, b=0, t=0),
scene=dict(
xaxis=dict(title=None, visible=False),
yaxis=dict(title=None, visible=False),
zaxis=dict(title=None, visible=False),
),
template='plotly_dark'
)
return fig, {"height": "50vh", "width": "100%", "display": "inline-block"}
# Define the callback function that will update the plot, highlight the sphere and enable drilling down
@app.callback(
Output('base-plot', 'figure'),
Input('hexgrid-2', 'clickData'),
State('hexgrid-1', 'clickData')
)
def update_base_plot(clickData_hexgrid_2, clickData_hexgrid_1):
try:
# Open a new database connection
conn = sqlite3.connect(r"C:\Users\HituJani\Downloads\txns.db")
category = clickData_hexgrid_1['points'][0]['text']
numerical_feature = clickData_hexgrid_2['points'][0]['text']
# SQL query to retrieve aggregated data based on selected category and numerical feature
query = f'''
SELECT {category}, WeekOfMonth, SUM({numerical_feature}) AS TotalAmount
FROM transactions
GROUP BY {category}, WeekOfMonth
ORDER BY TotalAmount DESC
'''
# Fetch the data from the database
df_base = pd.read_sql(query, conn)
# Close the database connection
conn.close()
# Formatting the Total column
df_base['TotalAmount'] = df_base['TotalAmount'].apply(lambda x: locale.currency(x, grouping=True))
# Creating 3D scatter plot with sphere markers
fig = go.Figure()
# Define colorscale for WeekOfMonth values
colorscale = [
[0, 'blue'], # Week 1: Blue
[0.25, 'purple'], # Week 2: Purple
[0.5, 'darkorange'], # Week 3: Dark Orange
[0.75, 'yellow'], # Week 4: Yellow
[1, 'pink'] # Week 5: Pink
]
# Add the scatter plot trace
fig.add_trace(
go.Scatter3d(
x=df_base[category],
y=df_base['WeekOfMonth'].astype(int),
z=df_base['TotalAmount'],
mode='markers+text',
marker=dict(
size=5, # Adjust the size of markers to make them smaller
symbol='circle', # Use 'circle' symbol for spheres
color=df_base['WeekOfMonth'],
colorscale=colorscale,
),
textposition='top center',
hovertemplate=(
f"<b>{category}</b>: %{{x}}<br>" +
"<b>Total Amount</b>: %{z}<br>" +
"<b>WeekOfMonth</b>: %{y}<br>"
)
)
)
# Dynamically set y-axis range
y_max = df_base['WeekOfMonth'].max()
fig.update_layout(
scene=dict(
xaxis=dict(
title=category,
title_font=dict(size=14, color='darkorange'),
visible=False # Hide the x-axis
),
yaxis=dict(
title='Week of Month',
title_font=dict(size=14, color='purple'),
tickmode='array',
tickvals=[0.5, 1.5, 2.5, 3.5, 4.5, 5.5],
ticktext=['1', '2', '3', '4', '5'], # Display tick labels as 1, 2, 3, 4, 5],
visible=False # Hide the y-axis
),
zaxis=dict(
title=f'Total {numerical_feature} ($)',
title_font=dict(size=14, color='yellow'),
autorange='reversed',
visible=False # Hide the z-axis
),
),
xaxis=dict(
type='category',
tickmode='linear',
tickangle=45,
automargin=True,
visible=False # Hide the x-axis labels
),
margin=dict(l=10, r=10, t=10, b=10), # Increase the b value to enlarge the viewing window
template='plotly_dark',
)
return fig
except Exception as e:
print(f"Error: {e}")
return go.Figure()
@app.callback(
Output('us-map-graph', 'figure'),
Output('us-map-graph', 'style'),
Input('base-plot', 'clickData'),
State('hexgrid-1', 'clickData'),
State('hexgrid-2', 'clickData')
)
def display_transaction_amount(base_plot_click_data, hexgrid_1_clickData, hexgrid_2_clickData):
try:
# Check if data from hexgrid-1 and hexgrid-2 is available
if hexgrid_1_clickData is None or hexgrid_2_clickData is None:
# Return an empty figure and hide the map
return go.Figure(), {"display": "none"}
# Get the selected category from hexgrid-1 and numerical feature from hexgrid-2
selected_category = hexgrid_1_clickData['points'][0]['text']
numerical_feature = hexgrid_2_clickData['points'][0]['text']
# Get the selected subcategory from base_plot_click_data
selected_subcategory = None
if base_plot_click_data is not None:
selected_subcategory = base_plot_click_data['points'][0]['x']
# Open a new database connection
conn = sqlite3.connect(r"C:\Users\HituJani\Downloads\txns.db")
# SQL query to retrieve transaction data by state for the selected category, subcategory, and numerical feature
query = f'''
SELECT StateCode, {selected_category}, SUM({numerical_feature}) AS TotalTransactionAmount
FROM transactions
WHERE {selected_category} = ?
GROUP BY StateCode, {selected_category}
'''
# Execute the query and fetch the results into a DataFrame
state_data = pd.read_sql(query, conn, params=(selected_subcategory,))
# Close the database connection
conn.close()
# Create a Choropleth map using the filtered data
fig = px.choropleth(
data_frame=state_data,
locationmode='USA-states',
locations='StateCode',
scope='usa',
color='TotalTransactionAmount',
hover_data={'StateCode': True, 'TotalTransactionAmount': ':$,f'},
color_continuous_scale='Reds',
labels={'TotalTransactionAmount': 'Total Transaction Amount'},
template='plotly_dark'
)
fig.update_traces(
hovertemplate="<b>%{customdata[0]}</b><br>" +
"<b>TotalTransactionAmount</b>: $%{customdata[1]:,.2f}<br>",
customdata=list(zip(state_data['StateCode'], state_data['TotalTransactionAmount']))
)
fig.update_layout(
title_text=f'Total Transaction Amount by State for Category: {selected_category}, Subcategory: {selected_subcategory}',
title_xanchor='center',
title_font=dict(size=12),
title_x=0.5,
geo=dict(scope='usa'),
)
# Return the figure and set the display style to block (visible)
return fig, {"display": "block"}
except Exception as e:
print(f"Error: {e}")
return go.Figure(), {"display": "none"}
if __name__ == '__main__':
app.run_server(debug=True, use_reloader=False)
此外,我还有这个格式化网页的css文件:
/* styles.css */
.container {
display: grid;
grid-template-rows: 1fr 1fr 1fr;
grid-template-columns: 1fr 1fr 1fr;
grid-column-gap: 15px;
grid-row-gap: 15px;
background-image: url("https://plainbackground.com/plain1024/383c3d.png");
background-size: 100%;
background-position: grid-ce;
}
.hexgrid-1-container {
/* grid-area: 1/1/3/3; */
grid-row: span 2;
grid-column: span 2;
padding: 2px 2px 2px 2px;
border: 1px solid hsl(176, 87%, 7%, 0.6);
border-radius: 10px;
box-shadow: rgba(250, 118, 3, 0.4) -5px 5px, rgba(250, 118, 3, 0.3) -10px 10px, rgba(250, 118, 3, 0.2) -15px 15px;
background: hsla(0, 7%, 11%, 0.9);
position: relative;
}
.hexgrid-2-container {
grid-area: 1/3/2/4;
padding: 3rem 4rem 4rem;
width: 70%;
border: 1px solid hsl(176, 87%, 7%, 0.6);
border-radius: 10px;
box-shadow: rgba(250, 118, 3, 0.4) -5px 5px, rgba(250, 118, 3, 0.3) -10px 10px, rgba(250, 118, 3, 0.2) -15px 15px;
background: hsl(0, 7%, 11%, 0.9);
position: relative;
}
.base-plot-container {
/* Add your custom styles for base-plot container here */
grid-area: 2/3/3/4;
padding: 3rem 4rem 4rem;
width: 70%;
border: 1px solid hsl(176, 87%, 7%, 0.6);
border-radius: 10px;
box-shadow: rgba(250, 118, 3, 0.4) -5px 5px, rgba(250, 118, 3, 0.3) -10px 10px, rgba(250, 118, 3, 0.2) -15px 15px;
background: hsl(0, 7%, 11%, 0.9);
position: relative;
}
.us-map-container {
grid-area: 3/3/4/4;
padding: 3rem 4rem 4rem;
width: 70%;
/* position: fixed; */
border: 1px solid hsl(176, 87%, 7%, 0.6);
border-radius: 10px;
box-shadow: rgba(250, 118, 3, 0.4) -5px 5px, rgba(250, 118, 3, 0.3) -10px 10px, rgba(250, 118, 3, 0.2) -15px 15px;
background: hsl(0, 7%, 11%, 0.9);
position: relative;
}
.fifth-container {
grid-area: 3/2/4/3;
border: 1px solid hsl(176, 87%, 7%, 0.6);
border-radius: 10px;
box-shadow: rgba(250, 118, 3, 0.4) -5px 5px, rgba(250, 118, 3, 0.3) -10px 10px, rgba(250, 118, 3, 0.2) -15px 15px;
background: hsl(0, 7%, 11%, 0.9);
position: relative;
}
.sixth-container {
grid-area: 3/1/4/2;
border: 1px solid hsl(176, 87%, 7%, 0.6);
border-radius: 10px;
box-shadow: rgba(250, 118, 3, 0.4) -5px 5px, rgba(250, 118, 3, 0.3) -10px 10px, rgba(250, 118, 3, 0.2) -15px 15px;
background: hsl(0, 7%, 11%, 0.9);
position: relative;
}
我尝试更新回调函数,但进展不大,而且似乎我做错了很多事情。实现此功能的最直接方法是什么?预先感谢您。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号
您可以进行回调来侦听单击事件,交换图形位置,然后将图形返回到更新的位置。您需要根据您的用例设置点击逻辑。你可以实现这样的东西:
@app.callback( Output('hexgrid-1-container', 'children'), Output('hexgrid-2-container', 'children'), Input('hexgrid-2', 'clickData'), State('hexgrid-1-container', 'children'), State('hexgrid-2-container', 'children') ) def swap_graphs(clickData, hexgrid_1_children, hexgrid_2_children): clicked_graph_id = 1 # Assuming hexgrid-2 was clicked, you can change this logic based on your use case if clicked_graph_id == 1: # Swap graph between hexgrid-1 and hexgrid-2 return hexgrid_2_children, hexgrid_1_children return hexgrid_1_children, hexgrid_2_children