Create an app showing 3D data visualizations. Generate mock 3D data: - Spiral helix with noise (100 points) - Surface plot (z = sin(x)*cos(y)) - 3D clusters (3 clusters, 50 points each) Features: - Viz selector dropdown - Interactive 3D plots with rotate/zoom - Controls for: * Point styling (size, color, opacity) * Axis settings * Animation speed Surface plot options: - Function parameter sliders - Color scheme toggle - Contour lines All plots should be fully interactive.
To upload files, please first save the app
import streamlit as st
import numpy as np
import pandas as pd
import plotly.graph_objects as go
import plotly.express as px
from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt
# Set page config
st.set_page_config(page_title="3D Data Visualizer", layout="wide")
# Initialize session state
if 'animation_frame' not in st.session_state:
st.session_state.animation_frame = 0
# Data generation functions
@st.cache_data
def generate_spiral_helix(n_points=100, noise_level=0.1):
"""Generate spiral helix with noise"""
t = np.linspace(0, 4*np.pi, n_points)
x = np.cos(t) + noise_level * np.random.randn(n_points)
y = np.sin(t) + noise_level * np.random.randn(n_points)
z = t + noise_level * np.random.randn(n_points)
return pd.DataFrame({'x': x, 'y': y, 'z': z, 't': t})
@st.cache_data
def generate_surface_data(x_range=(-5, 5), y_range=(-5, 5), resolution=50, a=1, b=1):
"""Generate surface plot data: z = a*sin(x)*cos(b*y)"""
x = np.linspace(x_range[0], x_range[1], resolution)
y = np.linspace(y_range[0], y_range[1], resolution)
X, Y = np.meshgrid(x, y)
Z = a * np.sin(X) * np.cos(b * Y)
return X, Y, Z
@st.cache_data
def generate_3d_clusters(n_clusters=3, n_points_per_cluster=50, random_state=42):
"""Generate 3D clustered data"""
X, labels = make_blobs(n_samples=n_clusters*n_points_per_cluster,
centers=n_clusters,
n_features=3,
random_state=random_state,
cluster_std=1.5)
return pd.DataFrame({'x': X[:, 0], 'y': X[:, 1], 'z': X[:, 2], 'cluster': labels})
# Main app
def main():
st.title("馃寪 3D Data Visualizer")
st.markdown("Interactive 3D visualizations with customizable controls")
# Sidebar for visualization selection
st.sidebar.header("馃搳 Visualization Settings")
viz_type = st.sidebar.selectbox(
"Select Visualization Type",
["Spiral Helix", "Surface Plot", "3D Clusters"]
)
# Common styling controls
st.sidebar.subheader("馃帹 Styling Controls")
point_size = st.sidebar.slider("Point Size", 1, 20, 5)
opacity = st.sidebar.slider("Point Opacity", 0.1, 1.0, 0.8)
# Animation controls
st.sidebar.subheader("馃幀 Animation")
animate = st.sidebar.checkbox("Enable Animation")
if animate:
animation_speed = st.sidebar.slider("Animation Speed", 0.1, 2.0, 1.0)
# Create columns for layout
col1, col2 = st.columns([3, 1])
with col1:
if viz_type == "Spiral Helix":
create_spiral_helix_viz(point_size, opacity, animate)
elif viz_type == "Surface Plot":
create_surface_plot_viz(opacity, animate)
elif viz_type == "3D Clusters":
create_clusters_viz(point_size, opacity, animate)
with col2:
st.subheader("馃搱 Plot Information")
if viz_type == "Spiral Helix":
st.write("**Spiral Helix with Noise**")
st.write("- 100 data points")
st.write("- Parametric equations with noise")
st.write("- Color mapped to parameter t")
elif viz_type == "Surface Plot":
st.write("**Mathematical Surface**")
st.write("- Function: z = a路sin(x)路cos(b路y)")
st.write("- Customizable parameters")
st.write("- Optional contour lines")
elif viz_type == "3D Clusters":
st.write("**3D Clustered Data**")
st.write("- 3 clusters, 50 points each")
st.write("- Generated using scikit-learn")
st.write("- Color coded by cluster")
def create_spiral_helix_viz(point_size, opacity, animate):
"""Create spiral helix visualization"""
st.subheader("馃寑 Spiral Helix with Noise")
# Generate data
df = generate_spiral_helix()
# Color scheme
color_scheme = st.selectbox("Color Scheme",
["viridis", "plasma", "rainbow", "turbo"])
# Create 3D scatter plot
fig = go.Figure()
fig.add_trace(go.Scatter3d(
x=df['x'], y=df['y'], z=df['z'],
mode='markers',
marker=dict(
size=point_size,
color=df['t'],
colorscale=color_scheme,
opacity=opacity,
showscale=True,
colorbar=dict(title="Parameter t")
),
text=[f"Point {i}<br>t={t:.2f}" for i, t in enumerate(df['t'])],
hovertemplate="<b>Point %{text}</b><br>" +
"x: %{x:.2f}<br>" +
"y: %{y:.2f}<br>" +
"z: %{z:.2f}<extra></extra>"
))
# Update layout
fig.update_layout(
title="Interactive 3D Spiral Helix",
scene=dict(
xaxis_title="X",
yaxis_title="Y",
zaxis_title="Z",
camera=dict(eye=dict(x=1.5, y=1.5, z=1.5))
),
height=600,
showlegend=False
)
if animate:
# Add animation frame controls
st.write("馃幀 Animation controls will rotate the view automatically")
st.plotly_chart(fig, use_container_width=True)
def create_surface_plot_viz(opacity, animate):
"""Create surface plot visualization"""
st.subheader("馃搳 Mathematical Surface Plot")
# Surface function parameters
col1, col2 = st.columns(2)
with col1:
a_param = st.slider("Parameter a", -3.0, 3.0, 1.0, 0.1)
show_contours = st.checkbox("Show Contour Lines", value=True)
with col2:
b_param = st.slider("Parameter b", -3.0, 3.0, 1.0, 0.1)
color_scheme = st.selectbox("Surface Color Scheme",
["viridis", "plasma", "rainbow", "turbo"],
key="surface_color")
# Generate surface data
X, Y, Z = generate_surface_data(a=a_param, b=b_param)
# Create surface plot
fig = go.Figure()
# Add surface
fig.add_trace(go.Surface(
x=X, y=Y, z=Z,
colorscale=color_scheme,
opacity=opacity,
showscale=True,
name="Surface"
))
# Add contour lines if requested
if show_contours:
fig.add_trace(go.Contour(
x=X[0], y=Y[:, 0], z=Z,
contours=dict(
x=dict(highlight=False),
y=dict(highlight=False),
z=dict(highlight=True, highlightcolor="white")
),
showscale=False,
opacity=0.7,
name="Contours"
))
# Update layout
fig.update_layout(
title=f"Surface: z = {a_param}路sin(x)路cos({b_param}路y)",
scene=dict(
xaxis_title="X",
yaxis_title="Y",
zaxis_title="Z",
camera=dict(eye=dict(x=1.5, y=1.5, z=1.5))
),
height=600
)
st.plotly_chart(fig, use_container_width=True)
def create_clusters_viz(point_size, opacity, animate):
"""Create 3D clusters visualization"""
st.subheader("馃幆 3D Clustered Data")
# Generate data
df = generate_3d_clusters()
# Cluster visualization options
color_by_cluster = st.checkbox("Color by Cluster", value=True)
show_centroids = st.checkbox("Show Cluster Centroids", value=True)
# Create 3D scatter plot
fig = go.Figure()
if color_by_cluster:
# Color by cluster
colors = ['red', 'blue', 'green']
for i, cluster in enumerate(df['cluster'].unique()):
cluster_data = df[df['cluster'] == cluster]
fig.add_trace(go.Scatter3d(
x=cluster_data['x'],
y=cluster_data['y'],
z=cluster_data['z'],
mode='markers',
marker=dict(
size=point_size,
color=colors[i],
opacity=opacity
),
name=f'Cluster {cluster}',
text=[f"Cluster {cluster}<br>Point {j}" for j in range(len(cluster_data))],
hovertemplate="<b>%{text}</b><br>" +
"x: %{x:.2f}<br>" +
"y: %{y:.2f}<br>" +
"z: %{z:.2f}<extra></extra>"
))
else:
# Single color
fig.add_trace(go.Scatter3d(
x=df['x'], y=df['y'], z=df['z'],
mode='markers',
marker=dict(
size=point_size,
color='blue',
opacity=opacity
),
name='All Points',
text=[f"Point {i}" for i in range(len(df))],
hovertemplate="<b>%{text}</b><br>" +
"x: %{x:.2f}<br>" +
"y: %{y:.2f}<br>" +
"z: %{z:.2f}<extra></extra>"
))
# Add centroids if requested
if show_centroids and color_by_cluster:
centroids = df.groupby('cluster')[['x', 'y', 'z']].mean()
fig.add_trace(go.Scatter3d(
x=centroids['x'],
y=centroids['y'],
z=centroids['z'],
mode='markers',
marker=dict(
size=point_size * 2,
color='black',
symbol='diamond',
opacity=1.0,
line=dict(color='white', width=2)
),
name='Centroids',
text=[f"Centroid {i}" for i in centroids.index],
hovertemplate="<b>%{text}</b><br>" +
"x: %{x:.2f}<br>" +
"y: %{y:.2f}<br>" +
"z: %{z:.2f}<extra></extra>"
))
# Update layout
fig.update_layout(
title="Interactive 3D Clustered Data",
scene=dict(
xaxis_title="X",
yaxis_title="Y",
zaxis_title="Z",
camera=dict(eye=dict(x=1.5, y=1.5, z=1.5))
),
height=600
)
st.plotly_chart(fig, use_container_width=True)
# Show cluster statistics
st.subheader("馃搳 Cluster Statistics")
cluster_stats = df.groupby('cluster').agg({
'x': ['mean', 'std'],
'y': ['mean', 'std'],
'z': ['mean', 'std']
}).round(2)
st.dataframe(cluster_stats)
if __name__ == "__main__":
main()
Hi! I can help you with any questions about Streamlit and Python. What would you like to know?