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
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%}  ', 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=' %{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()