# Fichier: python_cheats/cheatsheets/plotly.txt
# Cheatsheet Plotly - Guide Complet pour Visualisations Interactives


[OK] INSTALLATION & IMPORTS

# Installation
pip install plotly
pip install plotly==5.18.0                    # Version spécifique
pip install plotly kaleido                    # + export images statiques
pip install plotly pandas numpy               # Avec dépendances courantes

# Installation avec extras
pip install "plotly[jupyter]"                 # Support Jupyter
pip install plotly-express                    # Déjà inclus dans plotly 4.0+

# Import standard
import plotly.graph_objects as go
import plotly.express as px
from plotly.subplots import make_subplots
import plotly.io as pio

# Imports utiles
import pandas as pd
import numpy as np

# Configuration notebook
import plotly.offline as pyo
pyo.init_notebook_mode(connected=True)


[OK] PLOTLY EXPRESS (API SIMPLE)

# === Graphiques de Base ===

# Scatter plot
fig = px.scatter(df, x='col_x', y='col_y')
fig = px.scatter(df, x='col_x', y='col_y', 
                 color='category',                # Couleur par catégorie
                 size='size_col',                 # Taille des points
                 hover_data=['col1', 'col2'],     # Info au survol
                 title='Mon Graphique')

# Line plot
fig = px.line(df, x='date', y='value')
fig = px.line(df, x='date', y='value', 
              color='category',
              markers=True)                       # Ajouter marqueurs

# Bar chart
fig = px.bar(df, x='category', y='value')
fig = px.bar(df, x='category', y='value',
             color='subcategory',
             barmode='group')                     # 'stack', 'group', 'overlay'

# Histogram
fig = px.histogram(df, x='value')
fig = px.histogram(df, x='value', 
                   nbins=50,
                   color='category',
                   marginal='box')                # 'box', 'violin', 'rug'

# Box plot
fig = px.box(df, x='category', y='value')
fig = px.box(df, x='category', y='value',
             color='group',
             notched=True,
             points='all')                        # 'all', 'outliers', False

# Violin plot
fig = px.violin(df, x='category', y='value',
                box=True,
                points='all')

# Pie chart
fig = px.pie(df, values='value', names='category')
fig = px.pie(df, values='value', names='category',
             hole=0.3)                            # Donut chart

# Sunburst chart
fig = px.sunburst(df, path=['level1', 'level2'], values='value')

# Treemap
fig = px.treemap(df, path=['level1', 'level2'], values='value')

# Heatmap
fig = px.imshow(matrix)
fig = px.density_heatmap(df, x='col_x', y='col_y')

# Scatter matrix
fig = px.scatter_matrix(df, dimensions=['col1', 'col2', 'col3'],
                        color='category')

# Parallel coordinates
fig = px.parallel_coordinates(df, color='target',
                              dimensions=['col1', 'col2', 'col3'])

# Parallel categories
fig = px.parallel_categories(df, dimensions=['cat1', 'cat2', 'cat3'])

# === Graphiques 3D ===

# Scatter 3D
fig = px.scatter_3d(df, x='x', y='y', z='z',
                    color='category',
                    size='size')

# Line 3D
fig = px.line_3d(df, x='x', y='y', z='z',
                 color='category')

# Surface 3D
fig = px.scatter_3d(df, x='x', y='y', z='z')

# === Graphiques Statistiques ===

# Density contour
fig = px.density_contour(df, x='col_x', y='col_y')

# ECDF (Empirical Cumulative Distribution)
fig = px.ecdf(df, x='value', color='category')

# Strip plot
fig = px.strip(df, x='category', y='value')

# === Graphiques Temporels ===

# Time series
fig = px.line(df, x='date', y='value',
              range_x=['2023-01-01', '2023-12-31'])

# Area chart
fig = px.area(df, x='date', y='value')

# Gantt chart
fig = px.timeline(df, x_start='start', x_end='end', y='task',
                  color='resource')

# === Graphiques Géographiques ===

# Scatter mapbox
fig = px.scatter_mapbox(df, lat='latitude', lon='longitude',
                        color='value',
                        zoom=10,
                        mapbox_style='open-street-map')

# Choropleth (carte avec régions colorées)
fig = px.choropleth(df, locations='country_code',
                    color='value',
                    locationmode='ISO-3')

# Line mapbox
fig = px.line_mapbox(df, lat='lat', lon='lon',
                     color='route')

# === Animation ===

# Animation temporelle
fig = px.scatter(df, x='x', y='y',
                 animation_frame='year',          # Colonne pour animation
                 animation_group='country',       # Grouper animations
                 range_x=[0, 100],
                 range_y=[0, 100])

# === Facets (sous-graphiques) ===

# Facet par colonnes
fig = px.scatter(df, x='x', y='y',
                 facet_col='category')

# Facet par lignes
fig = px.scatter(df, x='x', y='y',
                 facet_row='category')

# Grille de facets
fig = px.scatter(df, x='x', y='y',
                 facet_row='cat1',
                 facet_col='cat2')

# === Options Communes ===

fig = px.scatter(
    df, x='x', y='y',
    
    # Données
    color='category',                             # Couleur
    size='size_col',                              # Taille
    symbol='symbol_col',                          # Forme des marqueurs
    hover_name='name_col',                        # Nom au survol
    hover_data=['col1', 'col2'],                  # Données au survol
    
    # Style
    color_discrete_sequence=['red', 'blue'],      # Couleurs discrètes
    color_continuous_scale='Viridis',             # Échelle continue
    opacity=0.7,
    
    # Labels
    labels={'x': 'Axe X', 'y': 'Axe Y'},
    title='Mon Titre',
    
    # Axes
    log_x=True,                                   # Échelle log X
    log_y=True,                                   # Échelle log Y
    range_x=[0, 100],
    range_y=[0, 100],
    
    # Layout
    height=600,
    width=800,
    template='plotly_dark',                       # Thème
    
    # Trendline
    trendline='ols',                              # 'ols', 'lowess'
    trendline_color_override='red'
)


[OK] GRAPH OBJECTS (API COMPLÈTE)

# === Création de base ===

# Figure vide
fig = go.Figure()

# Avec données
fig = go.Figure(data=[go.Scatter(x=[1, 2, 3], y=[4, 5, 6])])

# Avec layout
fig = go.Figure(
    data=[go.Scatter(x=[1, 2, 3], y=[4, 5, 6])],
    layout=go.Layout(title='Mon Graphique')
)

# === Types de Traces ===

# Scatter
trace = go.Scatter(
    x=[1, 2, 3, 4],
    y=[10, 15, 13, 17],
    mode='markers',                               # 'lines', 'markers', 'lines+markers'
    name='Série 1',
    marker=dict(
        size=10,
        color='red',
        symbol='circle',                          # 'circle', 'square', 'diamond'...
        line=dict(width=2, color='black')
    ),
    line=dict(
        width=2,
        color='blue',
        dash='dash'                               # 'solid', 'dot', 'dash', 'dashdot'
    ),
    text=['A', 'B', 'C', 'D'],                   # Texte aux points
    hovertemplate='<b>%{text}</b><br>Y: %{y}<extra></extra>'
)

# Scatter 3D
trace = go.Scatter3d(
    x=[1, 2, 3],
    y=[4, 5, 6],
    z=[7, 8, 9],
    mode='markers',
    marker=dict(size=5, color='red')
)

# Bar
trace = go.Bar(
    x=['A', 'B', 'C'],
    y=[10, 15, 13],
    name='Série 1',
    marker=dict(
        color='lightblue',
        line=dict(color='black', width=1)
    ),
    text=[10, 15, 13],                           # Texte sur barres
    textposition='auto'                           # 'inside', 'outside', 'auto'
)

# Histogram
trace = go.Histogram(
    x=data,
    nbinsx=50,
    name='Distribution',
    marker=dict(color='green'),
    opacity=0.7
)

# Box
trace = go.Box(
    y=data,
    name='Box Plot',
    boxmean='sd',                                 # 'sd', True, False
    marker=dict(color='blue'),
    notched=True
)

# Violin
trace = go.Violin(
    y=data,
    name='Violin',
    box_visible=True,
    meanline_visible=True
)

# Pie
trace = go.Pie(
    labels=['A', 'B', 'C'],
    values=[30, 50, 20],
    hole=0.3,                                     # Donut
    pull=[0, 0.1, 0],                            # Détacher tranches
    marker=dict(colors=['red', 'blue', 'green'])
)

# Heatmap
trace = go.Heatmap(
    z=[[1, 2, 3], [4, 5, 6], [7, 8, 9]],
    x=['A', 'B', 'C'],
    y=['X', 'Y', 'Z'],
    colorscale='Viridis',
    colorbar=dict(title='Valeur')
)

# Contour
trace = go.Contour(
    z=matrix,
    colorscale='Jet',
    contours=dict(
        showlabels=True,
        labelfont=dict(size=12)
    )
)

# Surface 3D
trace = go.Surface(
    z=matrix,
    colorscale='Viridis',
    showscale=True
)

# Mesh 3D
trace = go.Mesh3d(
    x=[0, 1, 2, 0],
    y=[0, 0, 1, 2],
    z=[0, 2, 0, 1],
    i=[0, 0, 0, 1],
    j=[1, 2, 3, 2],
    k=[2, 3, 1, 3],
    opacity=0.5
)

# Candlestick (finance)
trace = go.Candlestick(
    x=df['date'],
    open=df['open'],
    high=df['high'],
    low=df['low'],
    close=df['close']
)

# OHLC (finance)
trace = go.Ohlc(
    x=df['date'],
    open=df['open'],
    high=df['high'],
    low=df['low'],
    close=df['close']
)

# Waterfall
trace = go.Waterfall(
    x=['A', 'B', 'C', 'Total'],
    y=[10, -5, 3, 8],
    measure=['relative', 'relative', 'relative', 'total']
)

# Funnel
trace = go.Funnel(
    y=['Étape 1', 'Étape 2', 'Étape 3'],
    x=[1000, 500, 200],
    textposition='inside'
)

# Sunburst
trace = go.Sunburst(
    labels=['A', 'B', 'C', 'D'],
    parents=['', 'A', 'A', 'B'],
    values=[10, 5, 3, 2]
)

# Treemap
trace = go.Treemap(
    labels=['A', 'B', 'C', 'D'],
    parents=['', 'A', 'A', 'B'],
    values=[10, 5, 3, 2]
)

# Sankey
trace = go.Sankey(
    node=dict(
        label=['A', 'B', 'C'],
        color='blue'
    ),
    link=dict(
        source=[0, 0, 1],
        target=[1, 2, 2],
        value=[10, 5, 8]
    )
)

# Indicator (jauge)
trace = go.Indicator(
    mode='gauge+number+delta',
    value=75,
    delta={'reference': 60},
    gauge={'axis': {'range': [0, 100]},
           'bar': {'color': 'darkblue'},
           'steps': [
               {'range': [0, 50], 'color': 'lightgray'},
               {'range': [50, 100], 'color': 'gray'}
           ],
           'threshold': {
               'line': {'color': 'red', 'width': 4},
               'thickness': 0.75,
               'value': 90
           }}
)

# Table
trace = go.Table(
    header=dict(
        values=['Col A', 'Col B'],
        fill_color='paleturquoise',
        align='left'
    ),
    cells=dict(
        values=[[1, 2, 3], [4, 5, 6]],
        fill_color='lavender',
        align='left'
    )
)

# === Ajouter Traces ===

# Méthode 1: Création
fig = go.Figure(data=[trace1, trace2])

# Méthode 2: Add trace
fig = go.Figure()
fig.add_trace(trace1)
fig.add_trace(trace2)

# Méthode 3: Add_* helpers
fig.add_scatter(x=[1, 2, 3], y=[4, 5, 6], name='Série 1')
fig.add_bar(x=['A', 'B'], y=[10, 20], name='Série 2')


[OK] LAYOUT & STYLE

# === Configuration Layout ===

fig.update_layout(
    # Titre
    title='Mon Graphique',
    title_text='Mon Graphique',
    title_font=dict(size=24, color='blue', family='Arial'),
    title_x=0.5,                                  # Centrer (0 à 1)
    title_xanchor='center',
    
    # Dimensions
    width=800,
    height=600,
    margin=dict(l=50, r=50, t=100, b=50),        # Marges
    
    # Fond
    paper_bgcolor='white',                        # Fond page
    plot_bgcolor='lightgray',                     # Fond graphique
    
    # Police
    font=dict(
        family='Arial',
        size=12,
        color='black'
    ),
    
    # Légende
    showlegend=True,
    legend=dict(
        x=1,                                      # Position (0 à 1)
        y=1,
        xanchor='right',
        yanchor='top',
        bgcolor='rgba(255, 255, 255, 0.5)',
        bordercolor='black',
        borderwidth=1,
        orientation='v',                          # 'v' ou 'h'
        font=dict(size=10)
    ),
    
    # Hover
    hovermode='closest',                          # 'x', 'y', 'closest', False
    hoverlabel=dict(
        bgcolor='white',
        font_size=12,
        font_family='Arial'
    ),
    
    # Template
    template='plotly',                            # Voir section Templates
    
    # Autres
    autosize=True,
    bargap=0.2,                                   # Espace entre barres
    bargroupgap=0.1,
    barmode='group',                              # 'stack', 'group', 'overlay'
    
    # Annotations
    annotations=[
        dict(
            text='Annotation',
            x=2,
            y=5,
            showarrow=True,
            arrowhead=2
        )
    ],
    
    # Shapes
    shapes=[
        dict(
            type='rect',
            x0=1, x1=2,
            y0=3, y1=4,
            fillcolor='rgba(255, 0, 0, 0.2)',
            line=dict(color='red')
        )
    ]
)

# === Configuration Axes ===

fig.update_xaxes(
    # Titre
    title='Axe X',
    title_font=dict(size=14, color='blue'),
    title_standoff=10,
    
    # Plage
    range=[0, 10],
    autorange=True,                               # True, False, 'reversed'
    
    # Type
    type='linear',                                # 'linear', 'log', 'date', 'category'
    
    # Ticks
    showticklabels=True,
    tickmode='linear',                            # 'auto', 'linear', 'array'
    tick0=0,                                      # Premier tick
    dtick=1,                                      # Intervalle
    tickvals=[0, 2, 4, 6],                       # Valeurs spécifiques
    ticktext=['A', 'B', 'C', 'D'],               # Labels spécifiques
    tickangle=-45,
    tickfont=dict(size=10, color='black'),
    tickformat='.2f',                             # Format nombre
    
    # Grille
    showgrid=True,
    gridcolor='lightgray',
    gridwidth=1,
    griddash='dot',
    
    # Ligne zéro
    zeroline=True,
    zerolinecolor='black',
    zerolinewidth=2,
    
    # Ligne d'axe
    showline=True,
    linecolor='black',
    linewidth=2,
    mirror=True,                                  # Miroir sur côté opposé
    
    # Spike (ligne verticale au survol)
    showspikes=True,
    spikemode='across',                           # 'toaxis', 'across', 'marker'
    spikethickness=2,
    spikecolor='gray',
    spikedash='dot'
)

fig.update_yaxes(
    title='Axe Y',
    range=[0, 100],
    showgrid=True,
    gridcolor='lightgray'
)

# Axes secondaires
fig.update_layout(
    xaxis2=dict(
        overlaying='x',
        side='top'
    ),
    yaxis2=dict(
        overlaying='y',
        side='right'
    )
)

# Associer trace à axe secondaire
fig.add_scatter(x=[1, 2, 3], y=[10, 20, 30], yaxis='y2')


[OK] TEMPLATES & THEMES

# Templates prédéfinis
templates = [
    'plotly',           # Défaut
    'plotly_white',     # Fond blanc
    'plotly_dark',      # Fond sombre
    'ggplot2',          # Style ggplot2
    'seaborn',          # Style seaborn
    'simple_white',     # Minimaliste blanc
    'presentation',     # Présentation
    'xgridoff',         # Sans grille X
    'ygridoff',         # Sans grille Y
    'gridon',           # Avec grilles
    'none'              # Aucun style
]

# Utiliser template
fig.update_layout(template='plotly_dark')

# Template global
pio.templates.default = 'plotly_dark'

# Créer template personnalisé
custom_template = go.layout.Template(
    layout=dict(
        font=dict(family='Arial', size=14),
        plot_bgcolor='#f0f0f0',
        paper_bgcolor='white'
    )
)
pio.templates['custom'] = custom_template
fig.update_layout(template='custom')

# Échelles de couleurs
colorscales = [
    'Viridis', 'Plasma', 'Inferno', 'Magma', 'Cividis',  # Perceptuelles
    'Blues', 'Greens', 'Reds', 'Greys',                   # Séquentielles
    'RdBu', 'RdYlGn', 'Spectral',                         # Divergentes
    'Portland', 'Jet', 'Hot', 'Blackbody', 'Earth'        # Autres
]

# Utiliser
fig = px.scatter(df, x='x', y='y', color='z',
                 color_continuous_scale='Viridis')

# Échelle personnalisée
custom_scale = [
    [0.0, 'rgb(0, 0, 255)'],      # Bleu à 0%
    [0.5, 'rgb(0, 255, 0)'],      # Vert à 50%
    [1.0, 'rgb(255, 0, 0)']       # Rouge à 100%
]
fig.update_traces(marker=dict(colorscale=custom_scale))


[OK] SUBPLOTS (SOUS-GRAPHIQUES)

# === Création ===

# Grille simple
fig = make_subplots(rows=2, cols=2)

# Avec titres
fig = make_subplots(
    rows=2, cols=2,
    subplot_titles=('Plot 1', 'Plot 2', 'Plot 3', 'Plot 4')
)

# Avec types spécifiques
fig = make_subplots(
    rows=2, cols=2,
    specs=[
        [{'type': 'scatter'}, {'type': 'bar'}],
        [{'type': 'scatter3d'}, {'type': 'pie'}]
    ]
)

# Spans (fusion de cellules)
fig = make_subplots(
    rows=3, cols=2,
    specs=[
        [{'colspan': 2}, None],                   # Ligne 1 fusionnée
        [{}, {}],                                  # Ligne 2 normale
        [{'rowspan': 2}, {}]                      # Colonne 1 fusionnée
    ]
)

# Axes partagés
fig = make_subplots(
    rows=2, cols=1,
    shared_xaxes=True,                            # Partager X
    shared_yaxes=False,
    vertical_spacing=0.1                          # Espace vertical
)

# Axes secondaires
fig = make_subplots(
    rows=1, cols=1,
    specs=[[{'secondary_y': True}]]
)

# === Ajouter Traces ===

# Spécifier position
fig.add_trace(
    go.Scatter(x=[1, 2, 3], y=[4, 5, 6]),
    row=1, col=1
)

fig.add_trace(
    go.Bar(x=['A', 'B'], y=[10, 20]),
    row=1, col=2
)

# Avec axe secondaire
fig.add_trace(
    go.Scatter(x=[1, 2, 3], y=[40, 50, 60]),
    secondary_y=True
)

# === Mise à jour ===

# Layout global
fig.update_layout(title='Mes Subplots', height=600)

# Axes spécifiques
fig.update_xaxes(title='X', row=1, col=1)
fig.update_yaxes(title='Y', row=1, col=2)

# Tous les axes
fig.update_xaxes(showgrid=True)
fig.update_yaxes(showgrid=True)


[OK] INTERACTIVITÉ

# === Hover ===

# Personnaliser hover
fig.update_traces(
    hovertemplate='<b>%{fullData.name}</b><br>' +
                  'X: %{x}<br>' +
                  'Y: %{y:.2f}<br>' +
                  '<extra></extra>'                # Supprimer box secondaire
)

# Hover HTML
fig.update_traces(
    hovertemplate='<b>Point</b><br>' +
                  '<i>Valeur: %{y}</i><br>' +
                  '<extra></extra>'
)

# Hover info
fig.update_traces(hoverinfo='x+y+text')           # 'x', 'y', 'text', 'name'...

# === Boutons ===

# Boutons pour changer traces
fig.update_layout(
    updatemenus=[
        dict(
            type='buttons',
            direction='left',
            x=0.7,
            y=1.15,
            buttons=[
                dict(
                    label='Tous',
                    method='update',
                    args=[{'visible': [True, True, True]}]
                ),
                dict(
                    label='Série 1',
                    method='update',
                    args=[{'visible': [True, False, False]}]
                ),
                dict(
                    label='Série 2',
                    method='update',
                    args=[{'visible': [False, True, False]}]
                )
            ]
        )
    ]
)

# Boutons pour changer layout
fig.update_layout(
    updatemenus=[
        dict(
            buttons=[
                dict(
                    label='Linéaire',
                    method='relayout',
                    args=[{'yaxis.type': 'linear'}]
                ),
                dict(
                    label='Log',
                    method='relayout',
                    args=[{'yaxis.type': 'log'}]
                )
            ]
        )
    ]
)

# === Sliders ===

# Slider temporel
fig.update_layout(
    sliders=[
        dict(
            active=0,
            steps=[
                dict(
                    label=str(year),
                    method='update',
                    args=[
                        {'visible': [year == y for y in years]},
                        {'title': f'Année {year}'}
                    ]
                )
                for year in years
            ]
        )
    ]
)

# === Range Slider ===

# Sur axe X
fig.update_xaxes(rangeslider_visible=True)

# Configuration
fig.update_xaxes(
    rangeslider=dict(
        visible=True,
        thickness=0.1,
        bgcolor='white',
        bordercolor='gray',
        borderwidth=1
    )
)

# === Range Selector ===

# Boutons de sélection temporelle
fig.update_xaxes(
    rangeselector=dict(
        buttons=list([
            dict(count=1, label='1m', step='month', stepmode='backward'),
            dict(count=6, label='6m', step='month', stepmode='backward'),
            dict(count=1, label='1y', step='year', stepmode='backward'),
            dict(step='all', label='All')
        ])
    )
)

# === Click Events (Dash requis) ===

# Voir section DASH pour événements click


[OK] ANNOTATIONS & SHAPES

# === Annotations ===

# Annotation simple
fig.add_annotation(
    x=2, y=5,
    text='Point important',
    showarrow=True,
    arrowhead=2,
    arrowsize=1,
    arrowwidth=2,
    arrowcolor='red',
    ax=-40,                                       # Offset X flèche
    ay=-40                                        # Offset Y flèche
)

# Annotation avec style
fig.add_annotation(
    x=2, y=5,
    text='<b>Important</b>',
    font=dict(size=14, color='red'),
    bgcolor='yellow',
    bordercolor='black',
    borderwidth=2,
    borderpad=4,
    opacity=0.8
)

# Annotation sur subplot
fig.add_annotation(
    x=2, y=5,
    text='Annotation',
    xref='x1', yref='y1',                         # Référence axes
    row=1, col=1
)

# Annotation relative
fig.add_annotation(
    x=0.5, y=0.5,
    text='Centré',
    xref='paper', yref='paper',                   # Coordonnées relatives (0-1)
    showarrow=False
)

# Annotations multiples
annotations = [
    dict(x=i, y=i**2, text=f'Point {i}', showarrow=True)
    for i in range(5)
]
fig.update_layout(annotations=annotations)

# === Shapes ===

# Rectangle
fig.add_shape(
    type='rect',
    x0=1, x1=3,
    y0=2, y1=6,
    fillcolor='rgba(255, 0, 0, 0.2)',
    line=dict(color='red', width=2)
)

# Cercle
fig.add_shape(
    type='circle',
    xref='x', yref='y',
    x0=1, x1=3,
    y0=2, y1=4,
    fillcolor='rgba(0, 0, 255, 0.2)',
    line=dict(color='blue')
)

# Ligne
fig.add_shape(
    type='line',
    x0=0, x1=5,
    y0=0, y1=5,
    line=dict(color='green', width=3, dash='dash')
)

# Ligne horizontale
fig.add_hline(y=5, line_dash='dash', line_color='red')

# Ligne verticale
fig.add_vline(x=3, line_dash='dot', line_color='blue')

# Rectangle de sélection
fig.add_vrect(
    x0=1, x1=3,
    fillcolor='green',
    opacity=0.2,
    layer='below',
    line_width=0
)

fig.add_hrect(
    y0=2, y1=5,
    fillcolor='yellow',
    opacity=0.2
)

# Shapes multiples
shapes = [
    dict(type='rect', x0=i, x1=i+1, y0=0, y1=i, fillcolor='rgba(0,0,255,0.2)')
    for i in range(5)
]
fig.update_layout(shapes=shapes)


[OK] EXPORT & SAUVEGARDE

# === Images Statiques ===

# Installer kaleido
# pip install kaleido

# PNG
fig.write_image('graph.png')
fig.write_image('graph.png', width=1200, height=800, scale=2)

# JPEG
fig.write_image('graph.jpg', format='jpeg')

# SVG (vectoriel)
fig.write_image('graph.svg')

# PDF
fig.write_image('graph.pdf')

# WebP
fig.write_image('graph.webp')

# === HTML Interactif ===

# HTML complet
fig.write_html('graph.html')

# HTML avec options
fig.write_html(
    'graph.html',
    include_plotlyjs='cdn',                       # 'cdn', True, False, 'directory'
    auto_open=True,                               # Ouvrir dans navigateur
    config={'displayModeBar': False}              # Masquer barre outils
)

# HTML minimal
fig.write_html('graph.html', include_plotlyjs='cdn', full_html=False)

# === JSON ===

# Sauvegarder JSON
fig.write_json('graph.json')

# Charger JSON
import plotly.io as pio
fig = pio.read_json('graph.json')

# Obtenir JSON
json_str = fig.to_json()
json_dict = fig.to_dict()

# === Dans Notebook ===

# Afficher figure
fig.show()

# Afficher avec configuration
fig.show(config={'displayModeBar': False})

# Renderer par défaut
import plotly.io as pio
pio.renderers.default = 'browser'                 # 'browser', 'notebook', 'colab'

# === Configuration Export ===

config = {
    'toImageButtonOptions': {
        'format': 'png',                          # 'png', 'svg', 'jpeg', 'webp'
        'filename': 'mon_graph',
        'height': 800,
        'width': 1200,
        'scale': 2
    },
    'displayModeBar': True,                       # Afficher barre outils
    'displaylogo': False,                         # Masquer logo Plotly
    'modeBarButtonsToRemove': ['pan2d', 'lasso2d'],
    'modeBarButtonsToAdd': ['drawline', 'drawopenpath'],
    'scrollZoom': True,                           # Zoom molette
    'editable': True,                             # Édition annotations
    'responsive': True                            # Responsive
}

fig.show(config=config)
fig.write_html('graph.html', config=config)


[OK] PERFORMANCE & OPTIMISATION

# === Réduire Taille Fichier ===

# WebGL pour grands datasets
fig = go.Figure(data=[go.Scattergl(                # Scattergl au lieu de Scatter
    x=large_x,
    y=large_y,
    mode='markers'
)])

# Autres traces GL
go.Scattergl()                                     # Scatter rapide
go.Scatter3d()                                     # Déjà optimisé
go.Heatmapgl()                                     # Heatmap rapide

# Downsampling
# Réduire nombre de points si nécessaire
x_sample = x[::10]                                 # Prendre 1 point sur 10
y_sample = y[::10]

# === Streaming Data ===

# Avec FigureWidget (Jupyter)
from plotly.graph_objs import FigureWidget

fw = FigureWidget()
scatter = fw.add_scatter()

# Mettre à jour données
with fw.batch_update():
    scatter.x = new_x
    scatter.y = new_y

# === Caching ===

# Désactiver animation pour performance
fig.update_layout(transition_duration=0)

# === Mémoire ===

# Libérer mémoire
del fig
import gc
gc.collect()


[OK] DASH - APPLICATIONS WEB

# Installation
# pip install dash

# === Application Simple ===

import dash
from dash import dcc, html
from dash.dependencies import Input, Output

app = dash.Dash(__name__)

app.layout = html.Div([
    html.H1('Mon Dashboard'),
    
    dcc.Graph(id='graph'),
    
    dcc.Slider(
        id='slider',
        min=0,
        max=10,
        value=5,
        marks={i: str(i) for i in range(11)}
    )
])

@app.callback(
    Output('graph', 'figure'),
    Input('slider', 'value')
)
def update_graph(value):
    fig = px.line(x=[0, 1, 2], y=[0, value, value*2])
    return fig

if __name__ == '__main__':
    app.run_server(debug=True)

# === Callbacks Multiples ===

@app.callback(
    [Output('graph1', 'figure'),
     Output('graph2', 'figure')],
    [Input('dropdown', 'value'),
     Input('slider', 'value')]
)
def update_graphs(dropdown_val, slider_val):
    fig1 = px.scatter(...)
    fig2 = px.bar(...)
    return fig1, fig2

# === Click Events ===

@app.callback(
    Output('output', 'children'),
    Input('graph', 'clickData')
)
def display_click_data(clickData):
    if clickData:
        point = clickData['points'][0]
        return f"X: {point['x']}, Y: {point['y']}"
    return "Cliquez sur un point"

# === Hover Events ===

@app.callback(
    Output('output', 'children'),
    Input('graph', 'hoverData')
)
def display_hover_data(hoverData):
    if hoverData:
        point = hoverData['points'][0]
        return f"Point survolé: {point['x']}, {point['y']}"
    return "Survolez un point"

# === Selection Events ===

@app.callback(
    Output('output', 'children'),
    Input('graph', 'selectedData')
)
def display_selected_data(selectedData):
    if selectedData:
        points = selectedData['points']
        return f"{len(points)} points sélectionnés"
    return "Sélectionnez des points"


[OK] GRAPHIQUES FINANCIERS

# === Candlestick ===

import pandas as pd
import plotly.graph_objects as go

# Données OHLC
df = pd.DataFrame({
    'date': pd.date_range('2023-01-01', periods=100),
    'open': [100 + i + np.random.rand() for i in range(100)],
    'high': [102 + i + np.random.rand() for i in range(100)],
    'low': [98 + i + np.random.rand() for i in range(100)],
    'close': [101 + i + np.random.rand() for i in range(100)],
    'volume': [1000000 + np.random.randint(0, 500000) for i in range(100)]
})

# Candlestick
fig = go.Figure(data=[
    go.Candlestick(
        x=df['date'],
        open=df['open'],
        high=df['high'],
        low=df['low'],
        close=df['close'],
        name='Prix'
    )
])

fig.update_layout(
    title='Graphique Candlestick',
    yaxis_title='Prix',
    xaxis_rangeslider_visible=False               # Masquer range slider
)

# === OHLC ===

fig = go.Figure(data=[
    go.Ohlc(
        x=df['date'],
        open=df['open'],
        high=df['high'],
        low=df['low'],
        close=df['close']
    )
])

# === Avec Volume ===

from plotly.subplots import make_subplots

fig = make_subplots(
    rows=2, cols=1,
    shared_xaxes=True,
    vertical_spacing=0.03,
    row_heights=[0.7, 0.3]
)

# Prix
fig.add_trace(
    go.Candlestick(
        x=df['date'],
        open=df['open'],
        high=df['high'],
        low=df['low'],
        close=df['close'],
        name='Prix'
    ),
    row=1, col=1
)

# Volume
fig.add_trace(
    go.Bar(x=df['date'], y=df['volume'], name='Volume'),
    row=2, col=1
)

fig.update_layout(xaxis_rangeslider_visible=False)

# === Moyennes Mobiles ===

df['MA20'] = df['close'].rolling(window=20).mean()
df['MA50'] = df['close'].rolling(window=50).mean()

fig.add_trace(
    go.Scatter(x=df['date'], y=df['MA20'], name='MA20', line=dict(color='orange'))
)
fig.add_trace(
    go.Scatter(x=df['date'], y=df['MA50'], name='MA50', line=dict(color='blue'))
)

# === Bollinger Bands ===

df['MA'] = df['close'].rolling(window=20).mean()
df['std'] = df['close'].rolling(window=20).std()
df['upper'] = df['MA'] + 2 * df['std']
df['lower'] = df['MA'] - 2 * df['std']

fig.add_trace(go.Scatter(
    x=df['date'],
    y=df['upper'],
    name='Upper Band',
    line=dict(color='gray', dash='dash')
))

fig.add_trace(go.Scatter(
    x=df['date'],
    y=df['lower'],
    name='Lower Band',
    line=dict(color='gray', dash='dash'),
    fill='tonexty',                                # Remplir jusqu'à trace précédente
    fillcolor='rgba(128, 128, 128, 0.2)'
))


[OK] CARTES GÉOGRAPHIQUES

# === Scatter Mapbox ===

# Token Mapbox (gratuit sur mapbox.com)
# pio.templates[pio.templates.default].layout.mapbox.accesstoken = 'YOUR_TOKEN'

fig = px.scatter_mapbox(
    df,
    lat='latitude',
    lon='longitude',
    color='value',
    size='size',
    hover_name='name',
    zoom=10,
    mapbox_style='open-street-map'                # Gratuit, pas de token requis
)

# Styles Mapbox (avec token)
mapbox_styles = [
    'open-street-map',    # Gratuit
    'white-bg',           # Gratuit
    'carto-positron',     # Gratuit
    'carto-darkmatter',   # Gratuit
    'stamen-terrain',     # Gratuit
    'stamen-toner',       # Gratuit
    'stamen-watercolor',  # Gratuit
    'basic',              # Token requis
    'streets',            # Token requis
    'outdoors',           # Token requis
    'light',              # Token requis
    'dark',               # Token requis
    'satellite',          # Token requis
    'satellite-streets'   # Token requis
]

# === Choropleth (régions colorées) ===

# Carte du monde
fig = px.choropleth(
    df,
    locations='country_code',                      # Code ISO-3
    color='value',
    hover_name='country',
    locationmode='ISO-3',                          # 'ISO-3', 'USA-states', 'country names'
    color_continuous_scale='Viridis',
    title='Carte Mondiale'
)

# Carte USA par états
fig = px.choropleth(
    df,
    locations='state_code',
    color='value',
    locationmode='USA-states',
    scope='usa'
)

# Carte personnalisée (GeoJSON)
import json

with open('custom.geojson') as f:
    geojson = json.load(f)

fig = px.choropleth(
    df,
    geojson=geojson,
    locations='region_id',
    featureidkey='properties.id',
    color='value'
)

# === Density Mapbox ===

fig = px.density_mapbox(
    df,
    lat='latitude',
    lon='longitude',
    z='value',
    radius=10,
    zoom=10,
    mapbox_style='open-street-map'
)

# === Line Mapbox (trajets) ===

fig = px.line_mapbox(
    df,
    lat='latitude',
    lon='longitude',
    color='route',
    zoom=10,
    mapbox_style='open-street-map'
)

# === Carte avec Graph Objects ===

fig = go.Figure(go.Scattermapbox(
    lat=[48.8566, 51.5074],
    lon=[2.3522, -0.1278],
    mode='markers+text',
    marker=dict(size=14, color='red'),
    text=['Paris', 'Londres'],
    textposition='top right'
))

fig.update_layout(
    mapbox=dict(
        style='open-street-map',
        center=dict(lat=50, lon=0),
        zoom=4
    ),
    height=600
)


[OK] ANIMATION

# === Animation Temporelle ===

fig = px.scatter(
    df,
    x='x',
    y='y',
    animation_frame='year',                        # Colonne temporelle
    animation_group='country',                     # Grouper objets
    size='population',
    color='continent',
    hover_name='country',
    range_x=[0, 100],
    range_y=[0, 100],
    title='Animation Temporelle'
)

# Configuration animation
fig.layout.updatemenus[0].buttons[0].args[1]['frame']['duration'] = 1000
fig.layout.updatemenus[0].buttons[0].args[1]['transition']['duration'] = 500

# === Animation Personnalisée ===

import plotly.graph_objects as go

# Créer frames
frames = [
    go.Frame(
        data=[go.Scatter(x=[1, 2, 3], y=[i, i+1, i+2])],
        name=str(i)
    )
    for i in range(10)
]

fig = go.Figure(
    data=[go.Scatter(x=[1, 2, 3], y=[0, 1, 2])],
    layout=go.Layout(
        updatemenus=[
            dict(
                type='buttons',
                showactive=False,
                buttons=[
                    dict(label='Play',
                         method='animate',
                         args=[None, {'frame': {'duration': 500}}]),
                    dict(label='Pause',
                         method='animate',
                         args=[[None], {'frame': {'duration': 0}, 'mode': 'immediate'}])
                ]
            )
        ]
    ),
    frames=frames
)

# === Slider Animation ===

fig.update_layout(
    sliders=[
        dict(
            active=0,
            yanchor='top',
            y=0.99,
            xanchor='left',
            x=0.01,
            len=0.9,
            steps=[
                dict(
                    args=[[f.name], {'frame': {'duration': 0}, 'mode': 'immediate'}],
                    label=f.name,
                    method='animate'
                )
                for f in fig.frames
            ]
        )
    ]
)


[OK] 3D AVANCÉ

# === Surface 3D ===

x = np.linspace(-5, 5, 50)
y = np.linspace(-5, 5, 50)
X, Y = np.meshgrid(x, y)
Z = np.sin(np.sqrt(X**2 + Y**2))

fig = go.Figure(data=[
    go.Surface(
        x=X,
        y=Y,
        z=Z,
        colorscale='Viridis',
        contours={
            'z': {'show': True, 'usecolormap': True, 'project': {'z': True}}
        }
    )
])

fig.update_layout(
    scene=dict(
        xaxis_title='X',
        yaxis_title='Y',
        zaxis_title='Z',
        camera=dict(
            eye=dict(x=1.5, y=1.5, z=1.5)          # Position caméra
        ),
        aspectmode='cube'                          # 'auto', 'cube', 'data', 'manual'
    ),
    title='Surface 3D'
)

# === Scatter 3D Personnalisé ===

fig = go.Figure(data=[
    go.Scatter3d(
        x=[1, 2, 3],
        y=[4, 5, 6],
        z=[7, 8, 9],
        mode='markers+lines',
        marker=dict(
            size=10,
            color=[1, 2, 3],
            colorscale='Viridis',
            showscale=True,
            colorbar=dict(title='Valeur')
        ),
        line=dict(
            color='blue',
            width=5
        )
    )
])

# === Mesh 3D ===

fig = go.Figure(data=[
    go.Mesh3d(
        x=[0, 1, 2, 0],
        y=[0, 0, 1, 2],
        z=[0, 2, 0, 1],
        i=[0, 0, 0, 1],                           # Indices triangles
        j=[1, 2, 3, 2],
        k=[2, 3, 1, 3],
        intensity=[0, 0.33, 0.66, 1],
        colorscale='Viridis',
        opacity=0.8
    )
])

# === Cone (champ vectoriel) ===

fig = go.Figure(data=[
    go.Cone(
        x=[1, 2, 3],
        y=[1, 2, 3],
        z=[1, 2, 3],
        u=[1, 0, 0],                              # Composantes vecteur
        v=[0, 1, 0],
        w=[0, 0, 1],
        colorscale='Blues',
        sizemode='absolute',
        sizeref=0.5
    )
])

# === Streamtube (flux) ===

fig = go.Figure(data=[
    go.Streamtube(
        x=x, y=y, z=z,
        u=u, v=v, w=w,
        colorscale='Portland',
        sizeref=0.3,
        showscale=True
    )
])


[OK] GRAPHIQUES STATISTIQUES AVANCÉS

# === Violin avec Points ===

fig = go.Figure()

for category in df['category'].unique():
    data = df[df['category'] == category]['value']
    
    fig.add_trace(go.Violin(
        y=data,
        name=category,
        box_visible=True,
        meanline_visible=True,
        points='all',                             # Afficher tous points
        jitter=0.05,                              # Dispersion points
        scalemode='count'                         # Largeur proportionnelle
    ))

# === Distribution avec Courbe ===

fig = go.Figure()

# Histogram
fig.add_trace(go.Histogram(
    x=data,
    name='Distribution',
    opacity=0.7,
    histnorm='probability density'               # Normaliser
))

# Courbe KDE
from scipy import stats
kde = stats.gaussian_kde(data)
x_range = np.linspace(data.min(), data.max(), 100)
fig.add_trace(go.Scatter(
    x=x_range,
    y=kde(x_range),
    mode='lines',
    name='KDE',
    line=dict(color='red', width=3)
))

# === Q-Q Plot ===

from scipy import stats

theoretical_quantiles = stats.norm.ppf(np.linspace(0.01, 0.99, len(data)))
sample_quantiles = np.sort(data)

fig = go.Figure()
fig.add_trace(go.Scatter(
    x=theoretical_quantiles,
    y=sample_quantiles,
    mode='markers',
    name='Q-Q'
))

# Ligne de référence
fig.add_trace(go.Scatter(
    x=[theoretical_quantiles.min(), theoretical_quantiles.max()],
    y=[sample_quantiles.min(), sample_quantiles.max()],
    mode='lines',
    name='Référence',
    line=dict(color='red', dash='dash')
))

# === Correlation Heatmap ===

corr_matrix = df.corr()

fig = go.Figure(data=go.Heatmap(
    z=corr_matrix.values,
    x=corr_matrix.columns,
    y=corr_matrix.columns,
    colorscale='RdBu',
    zmid=0,
    text=corr_matrix.values.round(2),
    texttemplate='%{text}',
    textfont=dict(size=10),
    colorbar=dict(title='Corrélation')
))

fig.update_layout(title='Matrice de Corrélation')


[OK] EXEMPLES PRATIQUES

# === Dashboard Multi-Graphiques ===

from plotly.subplots import make_subplots

fig = make_subplots(
    rows=2, cols=2,
    subplot_titles=('Time Series', 'Distribution', 'Scatter', 'Box Plot'),
    specs=[
        [{'type': 'scatter'}, {'type': 'histogram'}],
        [{'type': 'scatter'}, {'type': 'box'}]
    ]
)

# Time series
fig.add_trace(
    go.Scatter(x=df['date'], y=df['value'], name='Series'),
    row=1, col=1
)

# Distribution
fig.add_trace(
    go.Histogram(x=df['value'], name='Dist'),
    row=1, col=2
)

# Scatter
fig.add_trace(
    go.Scatter(x=df['x'], y=df['y'], mode='markers', name='Scatter'),
    row=2, col=1
)

# Box
fig.add_trace(
    go.Box(y=df['value'], name='Box'),
    row=2, col=2
)

fig.update_layout(height=800, showlegend=False, title='Dashboard')

# === Graphique avec Régression ===

from sklearn.linear_model import LinearRegression

x = df['x'].values.reshape(-1, 1)
y = df['y'].values

model = LinearRegression()
model.fit(x, y)
y_pred = model.predict(x)

fig = go.Figure()

# Points
fig.add_trace(go.Scatter(
    x=df['x'],
    y=df['y'],
    mode='markers',
    name='Données',
    marker=dict(size=8)
))

# Ligne de régression
fig.add_trace(go.Scatter(
    x=df['x'],
    y=y_pred,
    mode='lines',
    name=f'Régression (R²={model.score(x, y):.3f})',
    line=dict(color='red', width=2)
))

# === Graphique Interactif Complet ===

fig = px.scatter(
    df,
    x='x',
    y='y',
    color='category',
    size='size',
    hover_data=['info1', 'info2'],
    facet_col='group',
    trendline='ols',
    title='Analyse Complète'
)

fig.update_layout(
    template='plotly_white',
    hovermode='closest',
    height=600
)

fig.update_xaxes(showgrid=True, gridcolor='lightgray')
fig.update_yaxes(showgrid=True, gridcolor='lightgray')


[OK] BONNES PRATIQUES

# 1. Performance
# - Utiliser Scattergl pour >10k points
# - Downsampler données si possible
# - Éviter trop d'annotations

# 2. Lisibilité
# - Choisir couleurs accessibles
# - Ajouter labels clairs
# - Utiliser hover informatif

# 3. Interactivité
# - Activer range slider pour time series
# - Ajouter boutons pour filtres
# - Utiliser facets pour comparaisons

# 4. Export
# - HTML pour interactivité
# - PNG/SVG pour documents
# - Kaleido pour automatisation

# 5. Organisation Code
# - Séparer données/visualisation
# - Fonctions réutilisables
# - Configuration centralisée

# === Fonction Réutilisable ===

def create_scatter_plot(df, x, y, color=None, title=''):
    """Créer scatter plot standardisé"""
    
    fig = px.scatter(
        df,
        x=x,
        y=y,
        color=color,
        template='plotly_white',
        title=title
    )
    
    fig.update_layout(
        height=600,
        hovermode='closest',
        font=dict(size=12)
    )
    
    fig.update_xaxes(showgrid=True, gridcolor='lightgray')
    fig.update_yaxes(showgrid=True, gridcolor='lightgray')
    
    return fig

# Utilisation
fig = create_scatter_plot(df, 'x', 'y', 'category', 'Mon Graphique')


[OK] DÉPANNAGE

# === Graphique ne s'affiche pas ===
# - Vérifier import: import plotly.graph_objects as go
# - Appeler fig.show()
# - En Jupyter: activer mode offline
# - Vérifier renderer: pio.renderers.default

# === Performance lente ===
# - Utiliser Scattergl au lieu de Scatter
# - Réduire nombre de points
# - Désactiver animations
# - Utiliser WebGL

# === Export image échoue ===
# - Installer kaleido: pip install kaleido
# - Vérifier chemins fichiers
# - Permissions écriture

# === Hover ne fonctionne pas ===
# - Vérifier hovermode layout
# - Vérifier hovertemplate
# - Désactiver puis réactiver

# === Légende coupée ===
# - Augmenter margins
# - Ajuster position légende
# - Réduire font size

# === Couleurs incorrectes ===
# - Vérifier colorscale
# - Vérifier color_discrete_map
# - Type données (numérique vs catégoriel)


[OK] RESSOURCES

# Documentation officielle
# https://plotly.com/python/

# Galerie d'exemples
# https://plotly.com/python/plotly-express/
# https://plotly.com/python/reference/

# Dash (applications web)
# https://dash.plotly.com/

# Community
# https://community.plotly.com/

# GitHub
# https://github.com/plotly/plotly.py

# Cheatsheet visuelle
# https://images.plot.ly/plotly-documentation/images/python_cheat_sheet.pdf