Figure Friday 2024 - week 46

Hi @Mike_Purtell ,
I tried to do something similar without Dash …
There are a lot of lines of code that can be optimized, but I like the result :upside_down_face:

Code
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import pandas as pd

from PIL import Image

glass_green = Image.open('/content/glass_green.png')
glass_blue = Image.open('/content/glass_blue.png')

df = pd.read_csv('https://raw.githubusercontent.com/plotly/Figure-Friday/refs/heads/main/2024/week-46/PDO_wine_data_IT_FR.csv')
df_gr = df.groupby('Country', as_index=False)['Color'].value_counts(normalize=True)

wine_colors = {'White':'white', 'Red':'crimson', 'Rosé':'pink'}
country_colors = {'FR':['France', '#004667', glass_blue], 'IT':['Italy', 'green', glass_green]}

bar_fr = px.bar(df_gr[df_gr['Country']=='FR'], 
                    x='Country', y='proportion', 
                    color='Color', custom_data='Color',
                    color_discrete_map=wine_colors,
                    opacity=0.8)

bar_it = px.bar(df_gr[df_gr['Country']=='IT'],
                    x='Country', y='proportion', 
                    color='Color', custom_data='Color',
                    color_discrete_map=wine_colors,
                    opacity=0.8)

# Create stacked bar chart with images for wine distribution by color and country

# Define Figure
fig = make_subplots(
    rows=1, cols=3, 
    horizontal_spacing=0,
    column_widths=[0.35, 0.3, 0.35],
    shared_yaxes=True)  

# Add traces for each country with stacked bars
for i in range(3):
    fig.add_trace(bar_fr.data[i], row=1, col=1)
    fig.add_trace(bar_it.data[i], row=1, col=3)    

fig.update_traces(
    width=0.64, 
    marker_cornerradius=80,    
    hovertemplate='Wine Color: %{customdata}<br>Percentage: %{y:.1%}<extra></extra>')

# Add text and images
for i, x in enumerate(['FR', 'IT']):  
    # Add additional bar for extending  yaxis
    fig.add_bar(x=[x], y=[1.2],
                width=0.1, hoverinfo='skip',
                marker=dict(color='rgba(0,0,0,0)', line_width=0),
                row=1, col=(i % 2) * 2 + 1,) 

    # Add name for each country as title   
    fig.add_scatter(x=[x], y=[-.2],  
                    mode='text', hoverinfo='skip',
                    text=country_colors[x][0], 
                    textfont=dict(size=20, color=country_colors[x][1]),
                    row=1, col=(i % 2) * 2 + 1,)
    
    # Add image above bars for each country  
    fig.add_layout_image(            
                source=country_colors[x][2],
                xref='x',
                yref='y',
                x=-0.4, y=-.12,
                sizex=.8, sizey=2.38,
                sizing='stretch', 
                opacity=1,
                layer='above', row=1, col=(i % 2) * 2 + 1,)
    
# Add text with percentage for France
fig.add_scatter(x=['FR']*3, y=[0.15, 0.5, 0.85],
                mode='text', hoverinfo='skip',
                text=df_gr[df_gr['Country']=='FR']['proportion'],
                texttemplate='%{text:.0%} &#x2003;', textposition='middle left',                
                marker_size=20,
                row=1, col=2) 

# Add text with percentage for Italy  
fig.add_scatter(x=['FR']*3,  y=[0.15, 0.5, 0.85],
                mode='text+markers',  hoverinfo='skip',
                text=df_gr[df_gr['Country']=='IT']['proportion'],
                texttemplate='&#x2003;%{text:.0%}', textposition='middle right',              
                marker=dict(color=['pink','crimson', 'white'], size=20, symbol='square'),
                row=1, col=2)  
                                       
fig.update_layout(
    title_text='Wine Distribution by Color', title_x=0.5, 
    width=700, height=500,
    xaxis_visible=False, showlegend=False,
    yaxis=dict(autorange='reversed', visible=False), 
    yaxis2_visible=False, xaxis2_visible=False,
    xaxis3_visible=False, yaxis3_visible=False,
    barmode='stack', font_size=16, font_weight='bold',
    margin=dict(l=10, t=70, r=10, b=10), hovermode='x',
    template='seaborn', paper_bgcolor='#EAEAF2')

fig.show()

Images for this graph
In addition to this, I want to show the chart without using images or icons .

Code
df_gr = df.groupby('Country', as_index=False)['Color'].value_counts(normalize=True).sort_values(by='proportion')

wine_colors = {'White':'white', 'Red':'crimson', 'Rosé':'pink'}

wine_glass = px.bar(df_gr[df_gr['Country']=='FR'],
                    x='Country', y='proportion',
                    custom_data='Color', 
                    color='Color', 
                    color_discrete_map=wine_colors, 
                    opacity=0.8)

# Update traces 
wine_glass.update_traces(
    marker=dict(cornerradius=70,            # Add rounded corners on the bars
                line_color='navy', 
                line_width=3),
    width=0.5, 
    hovertemplate='Wine Color: %{customdata}<br>Percentage: %{y:.0%}<extra></extra>')

# Add a leg for the wine glass (first part)
wine_glass.add_bar(x=['FR'], y=[1.2], width=0.1, marker_color='navy', hoverinfo='skip')

# Add a text label for the wine glass
wine_glass.add_scatter(x=['FR'], y=[-.2], mode='text', text='France', 
                       textfont=dict(size=20, color='navy'), hoverinfo='skip')

# Add the base for the leg of the wine glass
wine_glass.add_bar(x=['FR'], y=[0.1], width=0.3, base=2.1,
                   marker=dict(cornerradius=60, color='navy'), hoverinfo='skip')

# Update layout
wine_glass.update_layout(
    hovermode='x', barmode='stack', showlegend=False,
    xaxis_visible=False, 
    yaxis=dict(autorange='reversed', visible=False),    # Reverse the y-axis to obtain a rounding on the bottom side                  
    font_size=16, font_weight='bold',
    template='plotly_white',
    plot_bgcolor='#F7F7F7', paper_bgcolor='#F7F7F7',
    width=300, height=400,
    margin=dict(l=10, t=10, r=10, b=10))

wine_glass.show()