Arjit
Production-ready Option-Implied PDF Visualizer
8e1643b
"""
Visualization theme configuration for consistent dark theme styling across all plots.
"""
from typing import Dict
import plotly.graph_objects as go
from config.constants import PLOT_WIDTH, PLOT_HEIGHT, PLOT_COLORSCALE, PLOT_BG_COLOR
# Dark theme colors
DARK_THEME = {
'background': 'rgb(20,20,20)',
'paper': 'rgb(20,20,20)',
'plot_bg': 'rgb(30,30,30)',
'grid': 'rgb(50,50,50)',
'text': 'rgb(220,220,220)',
'primary': '#00D9FF', # Cyan
'secondary': '#FF00FF', # Magenta
'success': '#00FF88', # Green
'warning': '#FFD700', # Gold
'danger': '#FF4444', # Red
'neutral': 'rgb(150,150,150)'
}
# Colorscales
COLORSCALES = {
'viridis': 'Viridis',
'plasma': 'Plasma',
'inferno': 'Inferno',
'magma': 'Magma',
'cividis': 'Cividis',
'turbo': 'Turbo',
'rainbow': 'Rainbow',
'jet': 'Jet',
'portland': 'Portland',
'picnic': 'Picnic'
}
# Default layout template
DEFAULT_LAYOUT = {
'paper_bgcolor': DARK_THEME['background'],
'plot_bgcolor': DARK_THEME['plot_bg'],
'font': {
'color': DARK_THEME['text'],
'family': 'Arial, sans-serif',
'size': 12
},
'title': {
'font': {
'size': 18,
'color': DARK_THEME['text']
}
},
'xaxis': {
'gridcolor': DARK_THEME['grid'],
'zerolinecolor': DARK_THEME['grid'],
'color': DARK_THEME['text']
},
'yaxis': {
'gridcolor': DARK_THEME['grid'],
'zerolinecolor': DARK_THEME['grid'],
'color': DARK_THEME['text']
},
'width': PLOT_WIDTH,
'height': PLOT_HEIGHT,
'hovermode': 'closest'
}
def apply_dark_theme(fig: go.Figure, **kwargs) -> go.Figure:
"""
Apply dark theme to a Plotly figure.
Args:
fig: Plotly figure
**kwargs: Additional layout parameters to override defaults
Returns:
Figure with dark theme applied
"""
layout_updates = DEFAULT_LAYOUT.copy()
layout_updates.update(kwargs)
fig.update_layout(**layout_updates)
return fig
def create_base_layout(
title: str = "",
xaxis_title: str = "",
yaxis_title: str = "",
**kwargs
) -> Dict:
"""
Create base layout configuration with dark theme.
Args:
title: Plot title
xaxis_title: X-axis label
yaxis_title: Y-axis label
**kwargs: Additional layout parameters
Returns:
Layout dictionary
"""
layout = DEFAULT_LAYOUT.copy()
layout.update({
'title': title,
'xaxis': {
**layout['xaxis'],
'title': xaxis_title
},
'yaxis': {
**layout['yaxis'],
'title': yaxis_title
}
})
layout.update(kwargs)
return layout
def get_line_style(index: int) -> Dict:
"""
Get line style for multi-line plots.
Args:
index: Line index (0-based)
Returns:
Dictionary with color and dash pattern
"""
colors = [
DARK_THEME['primary'],
DARK_THEME['secondary'],
DARK_THEME['success'],
DARK_THEME['warning'],
DARK_THEME['danger'],
'#00FFFF', # Cyan
'#FF1493', # Deep Pink
'#00FF00', # Lime
'#FFA500', # Orange
'#9370DB' # Medium Purple
]
dash_patterns = ['solid', 'dash', 'dot', 'dashdot']
return {
'color': colors[index % len(colors)],
'dash': dash_patterns[(index // len(colors)) % len(dash_patterns)],
'width': 2
}
def format_hover_template(
x_label: str = "X",
y_label: str = "Y",
extra_fields: Dict[str, str] = None
) -> str:
"""
Create hover template for consistent hover display.
Args:
x_label: Label for x-axis value
y_label: Label for y-axis value
extra_fields: Additional fields to display
Returns:
Hover template string
"""
template = f"<b>{x_label}:</b> %{{x}}<br>"
template += f"<b>{y_label}:</b> %{{y}}<br>"
if extra_fields:
for label, value_key in extra_fields.items():
template += f"<b>{label}:</b> {value_key}<br>"
template += "<extra></extra>" # Remove trace name
return template
# 3D scene configuration
SCENE_3D_CONFIG = {
'bgcolor': DARK_THEME['plot_bg'],
'xaxis': {
'backgroundcolor': DARK_THEME['plot_bg'],
'gridcolor': DARK_THEME['grid'],
'showbackground': True,
'zerolinecolor': DARK_THEME['grid'],
'color': DARK_THEME['text']
},
'yaxis': {
'backgroundcolor': DARK_THEME['plot_bg'],
'gridcolor': DARK_THEME['grid'],
'showbackground': True,
'zerolinecolor': DARK_THEME['grid'],
'color': DARK_THEME['text']
},
'zaxis': {
'backgroundcolor': DARK_THEME['plot_bg'],
'gridcolor': DARK_THEME['grid'],
'showbackground': True,
'zerolinecolor': DARK_THEME['grid'],
'color': DARK_THEME['text']
}
}
def create_3d_scene_config(
xaxis_title: str = "X",
yaxis_title: str = "Y",
zaxis_title: str = "Z",
**kwargs
) -> Dict:
"""
Create 3D scene configuration.
Args:
xaxis_title: X-axis label
yaxis_title: Y-axis label
zaxis_title: Z-axis label
**kwargs: Additional scene parameters
Returns:
Scene configuration dictionary
"""
scene = SCENE_3D_CONFIG.copy()
scene['xaxis']['title'] = xaxis_title
scene['yaxis']['title'] = yaxis_title
scene['zaxis']['title'] = zaxis_title
scene.update(kwargs)
return scene
# Export all theme components
__all__ = [
'DARK_THEME',
'COLORSCALES',
'DEFAULT_LAYOUT',
'SCENE_3D_CONFIG',
'apply_dark_theme',
'create_base_layout',
'get_line_style',
'format_hover_template',
'create_3d_scene_config'
]
if __name__ == "__main__":
# Test theme configuration
import plotly.graph_objects as go
import numpy as np
print("Testing theme configuration...")
# Create sample plot
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)
fig = go.Figure()
# Add traces with themed styles
style1 = get_line_style(0)
style2 = get_line_style(1)
fig.add_trace(go.Scatter(
x=x, y=y1, name='Sin',
line=style1,
hovertemplate=format_hover_template("X", "Sin(X)")
))
fig.add_trace(go.Scatter(
x=x, y=y2, name='Cos',
line=style2,
hovertemplate=format_hover_template("X", "Cos(X)")
))
# Apply dark theme
layout = create_base_layout(
title="Theme Test Plot",
xaxis_title="X Value",
yaxis_title="Y Value"
)
fig.update_layout(**layout)
# Save test
fig.write_html("test_theme.html")
print("✅ Theme test saved to test_theme.html")