Figure Friday 2025 - week 13

Hi Mike, it could be refered to ‘whole food’ or whole form

  • “coffee beans wf” would refer to whole, unprocessed coffee beans.
  • “rice-grains-wf” would refer to whole rice grains, retaining the bran and germ.
3 Likes

Hi all,
I started plotly.graph_objects and scatter, still in progress. :slight_smile:

3 Likes

Thank you @adamschroeder for explaining graph_objs, makes sense. And thanks to @Avacsiglo21 and @marieanne for chiming in on the wf question.

The way all of you quickly answered these curiosities is a textbook example how friendly and supportive people are in this forum.

1 Like

Thank you adamschroeder!

@Mike_Purtell I just saw your question, after I accidentally created my chart with import ploty.gaph_objs as go, I was only able to upload it to PyCafe with this version.

3 Likes

@Ester I love how you created two X axes to your graph, with a bar trace and a scatter trace: pretty advanced stuff :flexed_biceps:

1 Like

I chose the colors from colorhunt.co in the food category and the yellow marker symbolizes money. :slight_smile:

1 Like

For week 13 I created a single-plot dashboard of the scatter polar example provide with this week’s dataset. Steps taken were:
• Converted the pandas code to polars
• Set all column names to upper case and reworded some of the column labels for brevity
• Changed all categories to title case, removed all dashes
• Used ‘simple_white’ template
• Added 2 pull-down driven callbacks, 1 to select categories and 1 to select nutrient columns
• Removed the table, only visualization is the scatter polar
• I tried to post this on PyCafe, my account is not properly setup. I will work on that.

Here is the code:

from dash import Dash, dcc, html, Input, Output
import dash_bootstrap_components as dbc
import polars as pl
import plotly.graph_objects as go
# Download CSV sheet at: 
# https://drive.google.com/file/d/1EoFTpSJOIYmVzemoMLj7vMTqeM1zMy0o/view?usp=sharing

citation = (
   'Source   : Prevalence of processed foods in major US grocery stores ' +
   'Authors: Babak Ravandi, Gordana Ispirova, Michael Sebek, Peter Mehler, ' +
    'Albert-László Barabási and Giulia Menichetti ' +
    'journal: Nature Food, 2025: dio={10.1038/s43016-024-01095-7} ' +
    'url = {https://www.nature.com/articles/s43016-024-01095-7}'
)
style_space = {
    'border': 'none', 
    'height': '5px', 
    'background': 'linear-gradient(to right, #007bff, #ff7b00)', 
    'margin': '10px 0'
    }
df=pl.read_csv('GroceryDB_foods.csv')
df_filtered = (
    df
    .rename({col: col.upper() for col in df.columns})
    .with_columns(
       CATEGORY=pl.col('HARMONIZED SINGLE CATEGORY')
        .str.to_titlecase()
        .str.replace_all('-', ' ')
        .str.replace('Milk Milk Substitute', 'Milk or Substitute'),
      FAT_TOTAL=pl.col('TOTAL FAT'),
      CARBS=pl.col('CARBOHYDRATE'),
      SUGAR_TOTAL=pl.col('SUGARS, TOTAL'),
      DIETARY_FIBER=pl.col('FIBER, TOTAL DIETARY'),
      SAT_FATTY_ACIDS_TOT=pl.col('FATTY ACIDS, TOTAL SATURATED'),
      VITAMIN_A=pl.col('TOTAL VITAMIN A'),  
      VITAMIN_C=pl.col('VITAMIN C'),   
    )
    .select(   
      'CATEGORY', 'CALCIUM', 'CARBS',  'CHOLESTEROL', 'DIETARY_FIBER', 
      'FAT_TOTAL', 'IRON', 'PROTEIN', 'SAT_FATTY_ACIDS_TOT', 'SODIUM', 
      'SUGAR_TOTAL', 'VITAMIN_A', 'VITAMIN_C'     
    )
    .group_by('CATEGORY', maintain_order=True)
    .mean()
)
# these lists will be used as callback choices
category_list = sorted(df_filtered['CATEGORY'].unique().to_list())
category_defaults = [
    'Drink Shakes Other', 'Drink Juice', 'Drink Tea', 'Drink Soft Energy Mixes']
nutrition_list = sorted([c for c in df_filtered.columns if c!= 'CATEGORY'])
nutrient_defaults = ['DIETARY_FIBER', 'SAT_FATTY_ACIDS_TOT']

#----- DEFINE FUNCTIONS---------------------------------------------------------
def make_fig(df_filtered, selected_cats, selected_nutrients):
    df_selected = (
        df_filtered
        .filter(pl.col('CATEGORY').is_in(selected_cats))
        .select(['CATEGORY'] + selected_nutrients)
    )
    fig = go.Figure()
    for nutrient in selected_nutrients:
        fig.add_trace(go.Scatterpolar(
            r=df_selected[nutrient],
            theta=df_selected['CATEGORY'],
            fill='toself',
            name=nutrient,
        ))
    fig.update_layout(
        template='simple_white',
        polar=dict(
            radialaxis=dict(
            visible=False,
            showticklabels = False,
            )),
        showlegend=True,
            legend=dict(
                title=dict(
                    text="Average Ingredient Count"
                )
        ),
        margin=dict(l=200, r=20, t=0, b=20),
        height=900, width=900,
    )
    return fig

app = Dash(external_stylesheets=[dbc.themes.SANDSTONE])
app.layout = dbc.Container([
    html.Hr(style=style_space),
    html.H2(
        'Scatterpolar Nutrition', 
        style={
            'text-align': 'left'
        }
    ),
    html.Hr(style=style_space),
    html.Div([
        html.P(
            f'Citation: {citation}',
            ),
        html.Hr(style=style_space)
    ]),
    html.Hr(style=style_space),
    html.Div([
        html.P(
            f'Use Left pulldown to select category, right pull down to select nutrients',
            ),
        html.Hr(style=style_space)
    ]),
    dbc.Row([
        dbc.Col(
        [dcc.Dropdown(       
            category_list,       
            category_defaults,   
            id='cat_dropdown', 
            multi=True,
            ),
        ]),
        dbc.Col([dcc.Dropdown(       
            nutrition_list,    
            nutrient_defaults,    
            id='nutrient_dropdown', 
            multi=True,
        ),]),
    ]),
   
    html.Div(id='dd-output-container2'),

    dbc.Row(
        [
            dbc.Col(
                dcc.Graph(
                    id='scatterpolar_fig',
                    style={
                        'width': '75vh', 
                        'height': '75vh', 
                    },
                ), 
            ),
        ]
    )
])

@app.callback(
        Output('scatterpolar_fig', 'figure'),
        Input('cat_dropdown', 'value'),
        Input('nutrient_dropdown', 'value'),
)
def update_dashboard(selected_cats, selected_nutrients):
    # call back returns string if 1 item is selected, list if multiple items 
    # are selected. The make_fig requires lists, next 4 lines take care of this
    if not type(selected_cats) is list:
        selected_cats = [selected_cats]
    if not type(selected_nutrients) is list:
        selected_nutrients = [selected_nutrients]
    scatter_polar = make_fig(df_filtered, selected_cats, selected_nutrients)
    return scatter_polar

#----- RUN THE APP -------------------------------------------------------------
if __name__ == "__main__":
    app.run(debug=True)
4 Likes

Hi Alex, this is brilliant work. I have downloaded your code, and it ran seamlessly on my system. If my dashboards can ever be as attractive and useful as what you have done, I would be so happy. Based on your work I am looking online at the differences between cosine similarity and Pearson regression which I use from time to time. Fascinating stuff. Have a great weekend.

2 Likes

Wow Mike, I’m grateful for your words, they mean a lot. I get help from AI and many hours of trial and error for the dashboards, and obviously the community feedback is the most valuable thing. We’re on the same page, I love looking for relationships/patterns. I find the scikit-learn library spectacular, and these work sections allow me to find ways to implement those fascinating tools. Of course, sometimes it’s difficult to find something, but I make the attempt. Happy weekend to you too.

:muscle: :muscle:

1 Like