import plotly.graph_objects as go import plotly.express as px from plotly.subplots import make_subplots import pandas as pd from typing import Dict, List, Any, Optional import logging logger = logging.getLogger(__name__) class CryptoVisualizations: """Professional cryptocurrency data visualizations""" @staticmethod def create_price_chart(data: Dict[str, Any], symbol: str = "BTC") -> go.Figure: """Create a professional price chart with volume""" try: if not data or 'prices' not in data: return CryptoVisualizations._create_empty_chart("No price data available") prices = data['prices'] volumes = data.get('total_volumes', []) # Convert to DataFrame df = pd.DataFrame({ 'timestamp': [pd.to_datetime(p[0], unit='ms') for p in prices], 'price': [p[1] for p in prices], 'volume': [v[1] if v else 0 for v in (volumes[:len(prices)] if volumes else [])] }) # Create subplot with secondary y-axis fig = make_subplots( rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.1, subplot_titles=(f'{symbol.upper()} Price', 'Volume'), row_heights=[0.7, 0.3] ) # Price line fig.add_trace( go.Scatter( x=df['timestamp'], y=df['price'], mode='lines', name='Price', line=dict(color='#00d4aa', width=2), hovertemplate='%{y:,.2f} USD
%{x}' ), row=1, col=1 ) # Volume bars if not df['volume'].empty and df['volume'].sum() > 0: fig.add_trace( go.Bar( x=df['timestamp'], y=df['volume'], name='Volume', marker_color='rgba(0, 212, 170, 0.3)', hovertemplate='%{y:,.0f}
%{x}' ), row=2, col=1 ) # Update layout fig.update_layout( title=dict( text=f'{symbol.upper()} Price Analysis', font=dict(size=24, color='#2c3e50'), x=0.5 ), showlegend=False, height=600, margin=dict(l=60, r=30, t=80, b=60), plot_bgcolor='white', paper_bgcolor='white', font=dict(family="SF Pro Display, -apple-system, system-ui, sans-serif", size=12) ) # Update axes fig.update_xaxes( gridcolor='#ecf0f1', gridwidth=1, showgrid=True, tickfont=dict(color='#7f8c8d') ) fig.update_yaxes( gridcolor='#ecf0f1', gridwidth=1, showgrid=True, tickfont=dict(color='#7f8c8d') ) return fig except Exception as e: logger.error(f"Error creating price chart: {e}") return CryptoVisualizations._create_empty_chart(f"Error: {str(e)}") @staticmethod def create_market_overview(data: List[Dict[str, Any]]) -> go.Figure: """Create market overview with top cryptocurrencies""" try: if not data: return CryptoVisualizations._create_empty_chart("No market data available") # Convert to DataFrame df = pd.DataFrame(data) # Take top 10 by market cap df = df.head(10).sort_values('market_cap', ascending=True) # Create horizontal bar chart fig = go.Figure() # Market cap bars fig.add_trace( go.Bar( y=df['name'], x=df['market_cap'], orientation='h', marker=dict( color=df['price_change_percentage_24h'], colorscale='RdYlGn', colorbar=dict(title="24h Change %"), line=dict(color='white', width=1) ), hovertemplate='%{y}
Market Cap: $%{x:,.0f}
24h: %{marker.color:.2f}%' ) ) fig.update_layout( title=dict( text='Top 10 Cryptocurrencies by Market Cap', font=dict(size=24, color='#2c3e50'), x=0.5 ), xaxis_title='Market Cap (USD)', height=500, margin=dict(l=120, r=30, t=80, b=60), plot_bgcolor='white', paper_bgcolor='white', font=dict(family="SF Pro Display, -apple-system, system-ui, sans-serif", size=12) ) fig.update_xaxes( gridcolor='#ecf0f1', gridwidth=1, showgrid=True, tickfont=dict(color='#7f8c8d') ) fig.update_yaxes( tickfont=dict(color='#2c3e50', size=11) ) return fig except Exception as e: logger.error(f"Error creating market overview: {e}") return CryptoVisualizations._create_empty_chart(f"Error: {str(e)}") @staticmethod def _create_empty_chart(message: str) -> go.Figure: """Create an empty chart with error message""" fig = go.Figure() fig.add_annotation( text=message, xref="paper", yref="paper", x=0.5, y=0.5, showarrow=False, font=dict(size=16, color="#7f8c8d") ) fig.update_layout( height=400, margin=dict(l=60, r=60, t=60, b=60), plot_bgcolor='white', paper_bgcolor='white', xaxis=dict(showgrid=False, showticklabels=False), yaxis=dict(showgrid=False, showticklabels=False) ) return fig # Convenience functions for backward compatibility def create_price_chart(data: Dict[str, Any], symbol: str = "BTC") -> go.Figure: """Create price chart - backward compatibility function""" return CryptoVisualizations.create_price_chart(data, symbol) def create_market_overview(data: List[Dict[str, Any]]) -> go.Figure: """Create market overview - backward compatibility function""" return CryptoVisualizations.create_market_overview(data)