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
from sklearn.cluster import KMeans
import time
# Set page config
st.set_page_config(page_title="3D Data Visualizer", layout="wide")
# Title
st.title("🌐 3D Data Visualizer")
st.markdown("Explore interactive 3D data visualizations with customizable parameters.")
# Data generation functions
@st.cache_data
def generate_spiral_helix(n_points=100, noise_level=0.1):
"""Generate 3D 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 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, noise=1.0):
"""Generate 3D clustered data"""
n_samples = n_clusters * n_points_per_cluster
X, y = make_blobs(n_samples=n_samples, centers=n_clusters,
n_features=3, random_state=42,
cluster_std=noise)
return pd.DataFrame({
'x': X[:, 0],
'y': X[:, 1],
'z': X[:, 2],
'cluster': y
})
# Sidebar controls
st.sidebar.header("🎛️ Visualization Controls")
# Visualization selector
viz_type = st.sidebar.selectbox(
"Select Visualization",
["Spiral Helix", "Surface Plot", "3D Clusters"]
)
st.sidebar.markdown("---")
# Common styling controls
st.sidebar.subheader("Point Styling")
point_size = st.sidebar.slider("Point Size", 1, 20, 8)
opacity = st.sidebar.slider("Opacity", 0.1, 1.0, 0.8)
# Animation controls
st.sidebar.subheader("Animation")
animation_speed = st.sidebar.slider("Animation Speed (ms)", 50, 2000, 500)
auto_rotate = st.sidebar.checkbox("Auto Rotate", value=False)
# Main content area
col1, col2 = st.columns([3, 1])
with col1:
if viz_type == "Spiral Helix":
st.subheader("🌀 Spiral Helix Visualization")
# Helix-specific controls
with col2:
st.subheader("Helix Controls")
n_points = st.slider("Number of Points", 50, 200, 100)
noise_level = st.slider("Noise Level", 0.0, 0.5, 0.1)
color_by = st.selectbox("Color By", ["Height (z)", "Parameter (t)", "Uniform"])
# Generate data
helix_data = generate_spiral_helix(n_points, noise_level)
# Create plot
fig = go.Figure()
if color_by == "Height (z)":
color_vals = helix_data['z']
colorscale = 'Viridis'
elif color_by == "Parameter (t)":
color_vals = helix_data['t']
colorscale = 'Rainbow'
else:
color_vals = None
colorscale = None
fig.add_trace(go.Scatter3d(
x=helix_data['x'],
y=helix_data['y'],
z=helix_data['z'],
mode='markers',
marker=dict(
size=point_size,
opacity=opacity,
color=color_vals,
colorscale=colorscale,
showscale=True if color_vals is not None else False
),
name='Helix Points'
))
# Add connecting line
if st.sidebar.checkbox("Show Connection Line", value=True):
fig.add_trace(go.Scatter3d(
x=helix_data['x'],
y=helix_data['y'],
z=helix_data['z'],
mode='lines',
line=dict(color='rgba(100,100,100,0.3)', width=2),
name='Connection'
))
elif viz_type == "Surface Plot":
st.subheader("🏔️ Surface Plot Visualization")
# Surface-specific controls
with col2:
st.subheader("Surface Controls")
resolution = st.slider("Resolution", 20, 100, 50)
a_param = st.slider("Parameter A", 0.1, 3.0, 1.0)
b_param = st.slider("Parameter B", 0.1, 3.0, 1.0)
color_scheme = st.selectbox("Color Scheme",
['Viridis', 'Rainbow', 'Blues', 'Reds', 'Hot'])
show_contours = st.checkbox("Show Contour Lines", value=False)
surface_opacity = st.slider("Surface Opacity", 0.3, 1.0, 0.8)
# Generate surface data
X, Y, Z = generate_surface_data(resolution=resolution, a=a_param, b=b_param)
# Create plot
fig = go.Figure()
fig.add_trace(go.Surface(
x=X, y=Y, z=Z,
colorscale=color_scheme,
opacity=surface_opacity,
showscale=True,
contours=dict(
z=dict(show=show_contours, usecolormap=True, highlightcolor="limegreen", project_z=True)
) if show_contours else None
))
elif viz_type == "3D Clusters":
st.subheader("🎯 3D Clusters Visualization")
# Cluster-specific controls
with col2:
st.subheader("Cluster Controls")
n_clusters = st.slider("Number of Clusters", 2, 6, 3)
n_points_per_cluster = st.slider("Points per Cluster", 20, 100, 50)
cluster_noise = st.slider("Cluster Spread", 0.5, 3.0, 1.0)
show_centers = st.checkbox("Show Cluster Centers", value=True)
# Generate cluster data
cluster_data = generate_3d_clusters(n_clusters, n_points_per_cluster, cluster_noise)
# Create plot
fig = go.Figure()
# Plot clusters with different colors
colors = px.colors.qualitative.Set1[:n_clusters]
for i in range(n_clusters):
cluster_points = cluster_data[cluster_data['cluster'] == i]
fig.add_trace(go.Scatter3d(
x=cluster_points['x'],
y=cluster_points['y'],
z=cluster_points['z'],
mode='markers',
marker=dict(
size=point_size,
opacity=opacity,
color=colors[i]
),
name=f'Cluster {i+1}'
))
# Add cluster centers
if show_centers:
centers = cluster_data.groupby('cluster')[['x', 'y', 'z']].mean()
fig.add_trace(go.Scatter3d(
x=centers['x'],
y=centers['y'],
z=centers['z'],
mode='markers',
marker=dict(
size=point_size*2,
opacity=1.0,
color='black',
symbol='diamond',
line=dict(color='white', width=2)
),
name='Centers'
))
# Configure layout
fig.update_layout(
scene=dict(
xaxis_title='X Axis',
yaxis_title='Y Axis',
zaxis_title='Z Axis',
camera=dict(
eye=dict(x=1.5, y=1.5, z=1.5)
)
),
width=800,
height=600,
title=f"{viz_type} - Interactive 3D Visualization"
)
# Add animation if enabled
if auto_rotate:
fig.update_layout(
updatemenus=[dict(
type="buttons",
buttons=[dict(
label="Auto Rotate",
method="animate",
args=[None, {"frame": {"duration": animation_speed, "redraw": True},
"fromcurrent": True, "transition": {"duration": 0}}]
)]
)]
)
# Display plot
st.plotly_chart(fig, use_container_width=True)
# Statistics and information
with st.expander("📊 Data Statistics"):
if viz_type == "Spiral Helix":
st.write(f"**Points:** {len(helix_data)}")
st.write(f"**X range:** [{helix_data['x'].min():.2f}, {helix_data['x'].max():.2f}]")
st.write(f"**Y range:** [{helix_data['y'].min():.2f}, {helix_data['y'].max():.2f}]")
st.write(f"**Z range:** [{helix_data['z'].min():.2f}, {helix_data['z'].max():.2f}]")
st.subheader("Sample Data")
st.dataframe(helix_data.head())
elif viz_type == "Surface Plot":
st.write(f"**Resolution:** {resolution}x{resolution}")
st.write(f"**Function:** z = {a_param}*sin(x)*cos({b_param}*y)")
st.write(f"**Z range:** [{Z.min():.2f}, {Z.max():.2f}]")
elif viz_type == "3D Clusters":
st.write(f"**Total Points:** {len(cluster_data)}")
st.write(f"**Clusters:** {n_clusters}")
st.write(f"**Points per Cluster:** {n_points_per_cluster}")
cluster_stats = cluster_data.groupby('cluster')[['x', 'y', 'z']].agg(['mean', 'std'])
st.subheader("Cluster Statistics")
st.dataframe(cluster_stats)
# Instructions
with st.expander("📖 How to Use"):
st.markdown("""
### Navigation:
- **Rotate:** Click and drag to rotate the 3D view
- **Zoom:** Use mouse wheel or zoom controls
- **Pan:** Hold Shift and drag to pan
### Features:
- **Spiral Helix:** Customize noise, point count, and coloring
- **Surface Plot:** Adjust function parameters and visualization style
- **3D Clusters:** Control cluster count, spread, and point distribution
### Tips:
- Use the sidebar controls to customize each visualization
- Enable auto-rotate for animated views
- Adjust opacity for better visualization of overlapping points
- Show/hide elements using the legend
""")
# Footer
st.markdown("---")
st.markdown("Built with ❤️ using Streamlit and Plotly")
Hi! I can help you with any questions about Streamlit and Python. What would you like to know?