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 math
# Set page config
st.set_page_config(page_title="3D Data Visualizer", layout="wide")
# Title
st.title("🌌 3D Data Visualizer")
st.markdown("Interactive 3D visualizations with customizable controls")
# Sidebar controls
st.sidebar.header("Visualization Settings")
# Visualization selector
viz_type = st.sidebar.selectbox(
"Select Visualization",
["Spiral Helix", "Surface Plot", "3D Clusters"]
)
# 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)
# Color scheme
color_scheme = st.sidebar.selectbox(
"Color Scheme",
["Viridis", "Plasma", "Inferno", "Magma", "Cividis", "Rainbow", "Turbo"]
)
# Animation controls
st.sidebar.subheader("Animation")
animation_speed = st.sidebar.slider("Animation Speed (ms)", 50, 500, 100)
auto_rotate = st.sidebar.checkbox("Auto Rotate", False)
# Axis settings
st.sidebar.subheader("Axis Settings")
show_axes = st.sidebar.checkbox("Show Axes", True)
show_grid = st.sidebar.checkbox("Show Grid", True)
# Data generation functions
@st.cache_data
def generate_spiral_helix(n_points=100):
"""Generate spiral helix with noise"""
t = np.linspace(0, 4*np.pi, n_points)
x = np.cos(t) + 0.1 * np.random.randn(n_points)
y = np.sin(t) + 0.1 * np.random.randn(n_points)
z = t + 0.2 * np.random.randn(n_points)
return pd.DataFrame({
'x': x,
'y': y,
'z': z,
'parameter': 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_clusters(n_clusters=3, n_points_per_cluster=50):
"""Generate 3D clusters"""
total_points = n_clusters * n_points_per_cluster
# Generate cluster data
X, y = make_blobs(
n_samples=total_points,
centers=n_clusters,
n_features=3,
random_state=42,
cluster_std=1.5
)
return pd.DataFrame({
'x': X[:, 0],
'y': X[:, 1],
'z': X[:, 2],
'cluster': y
})
# Main visualization area
col1, col2 = st.columns([3, 1])
with col1:
if viz_type == "Spiral Helix":
st.subheader("Spiral Helix with Noise")
# Generate data
spiral_data = generate_spiral_helix()
# Create 3D scatter plot
fig = go.Figure(data=go.Scatter3d(
x=spiral_data['x'],
y=spiral_data['y'],
z=spiral_data['z'],
mode='markers',
marker=dict(
size=point_size,
color=spiral_data['parameter'],
colorscale=color_scheme,
opacity=opacity,
colorbar=dict(title="Parameter t")
),
text=[f"Point {i}" for i in range(len(spiral_data))],
hovertemplate="<b>Point %{text}</b><br>X: %{x:.2f}<br>Y: %{y:.2f}<br>Z: %{z:.2f}<extra></extra>"
))
# Update layout
fig.update_layout(
scene=dict(
xaxis=dict(showgrid=show_grid, visible=show_axes),
yaxis=dict(showgrid=show_grid, visible=show_axes),
zaxis=dict(showgrid=show_grid, visible=show_axes),
camera=dict(
eye=dict(x=1.5, y=1.5, z=1.5)
)
),
width=800,
height=600,
title="Interactive Spiral Helix"
)
st.plotly_chart(fig, use_container_width=True)
elif viz_type == "Surface Plot":
st.subheader("Surface Plot: z = a×sin(x)×cos(b×y)")
# Surface plot specific controls
with col2:
st.subheader("Surface Controls")
a_param = st.slider("Parameter a", 0.1, 3.0, 1.0, 0.1)
b_param = st.slider("Parameter b", 0.1, 3.0, 1.0, 0.1)
resolution = st.slider("Resolution", 20, 100, 50, 5)
show_contours = st.checkbox("Show Contours", False)
surface_opacity = st.slider("Surface Opacity", 0.1, 1.0, 0.8)
# Generate surface data
X, Y, Z = generate_surface_data(resolution=resolution, a=a_param, b=b_param)
# Create surface plot
fig = go.Figure(data=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
))
# Update layout
fig.update_layout(
scene=dict(
xaxis=dict(showgrid=show_grid, visible=show_axes, title="X"),
yaxis=dict(showgrid=show_grid, visible=show_axes, title="Y"),
zaxis=dict(showgrid=show_grid, visible=show_axes, title="Z"),
camera=dict(
eye=dict(x=1.5, y=1.5, z=1.5)
)
),
width=800,
height=600,
title=f"Surface: z = {a_param}×sin(x)×cos({b_param}×y)"
)
st.plotly_chart(fig, use_container_width=True)
elif viz_type == "3D Clusters":
st.subheader("3D Clusters")
# Cluster specific controls
with col2:
st.subheader("Cluster Controls")
n_clusters = st.slider("Number of Clusters", 2, 6, 3)
points_per_cluster = st.slider("Points per Cluster", 20, 100, 50, 10)
show_centroids = st.checkbox("Show Centroids", True)
# Generate cluster data
cluster_data = generate_clusters(n_clusters, points_per_cluster)
# Create 3D scatter plot
fig = go.Figure()
# Add points for each cluster
for i in range(n_clusters):
cluster_subset = cluster_data[cluster_data['cluster'] == i]
fig.add_trace(go.Scatter3d(
x=cluster_subset['x'],
y=cluster_subset['y'],
z=cluster_subset['z'],
mode='markers',
marker=dict(
size=point_size,
opacity=opacity,
color=px.colors.qualitative.Set1[i % len(px.colors.qualitative.Set1)]
),
name=f'Cluster {i+1}',
text=[f"Cluster {i+1} - Point {j}" for j in range(len(cluster_subset))],
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:
centroids = cluster_data.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,
opacity=1.0,
color='black',
symbol='diamond'
),
name='Centroids',
text=[f"Centroid {i+1}" for i in range(len(centroids))],
hovertemplate="<b>%{text}</b><br>X: %{x:.2f}<br>Y: %{y:.2f}<br>Z: %{z:.2f}<extra></extra>"
))
# Update layout
fig.update_layout(
scene=dict(
xaxis=dict(showgrid=show_grid, visible=show_axes, title="X"),
yaxis=dict(showgrid=show_grid, visible=show_axes, title="Y"),
zaxis=dict(showgrid=show_grid, visible=show_axes, title="Z"),
camera=dict(
eye=dict(x=1.5, y=1.5, z=1.5)
)
),
width=800,
height=600,
title=f"3D Clusters ({n_clusters} clusters, {points_per_cluster} points each)"
)
st.plotly_chart(fig, use_container_width=True)
# Display data statistics
with col2:
if viz_type != "Surface Plot":
st.subheader("Data Statistics")
if viz_type == "Spiral Helix":
data = spiral_data
elif viz_type == "3D Clusters":
data = cluster_data
st.write(f"**Total Points:** {len(data)}")
st.write("**Data Summary:**")
st.dataframe(data.describe())
# Show sample of data
st.write("**Sample Data:**")
st.dataframe(data.head())
# Instructions
st.markdown("""
### 🎮 How to Use:
1. **Select Visualization**: Choose from Spiral Helix, Surface Plot, or 3D Clusters
2. **Customize Styling**: Adjust point size, opacity, and color scheme
3. **Interact with Plot**:
- Click and drag to rotate
- Scroll to zoom
- Double-click to reset view
4. **Animation**: Enable auto-rotate for continuous rotation
5. **Axis Controls**: Toggle grid and axes visibility
### 📊 Visualization Types:
- **Spiral Helix**: Parametric spiral with added noise
- **Surface Plot**: Mathematical surface z = a×sin(x)×cos(b×y)
- **3D Clusters**: Generated cluster data with optional centroids
### 🔧 Features:
- Fully interactive 3D plots
- Real-time parameter adjustments
- Multiple color schemes
- Hover tooltips with detailed information
- Export options (via Plotly toolbar)
""")
Hi! I can help you with any questions about Streamlit and Python. What would you like to know?