Diet logging plots


source

draw_pie_chart

 draw_pie_chart (ax:matplotlib.axes._axes.Axes, x:float, y:float,
                 data:List[float], size:float, palette:str='muted',
                 alpha:float=0.7)

*Draw a pie chart as an inset (in absolute figure coordinates) within the given axes at the specified data coordinates. What this solves is the issue of y-axis and x-axis scaling being different, which distorts the pie chart when drawn directly on the axes.

Args:

ax (plt.Axes): The axis on which to draw the pie chart.
x (float): The x-coordinate in data coordinates where the pie chart's center will be placed.
y (float): The y-coordinate in data coordinates where the pie chart's center will be placed.
data (List[float]): The data values to be represented in the pie chart.
size (float): The size (radius) of the pie chart in axes-relative coordinates.
palette (str): The color palette to use for the pie slices.

Returns:

List[plt.Patch]: A list of wedge objects representing the pie chart slices.*

source

extract_units

 extract_units (column_names:List[str])

source

prepare_meals

 prepare_meals (diet_log:pandas.core.frame.DataFrame,
                participant_id:int=None, array_index:int=None,
                time_range:Tuple[str,str]=None,
                label:str='short_food_name', return_meals:bool=True,
                return_summary:bool=False, y_include:List[str]=None,
                y_exclude:List[str]=None, agg_units:dict={'kcal': 'sum',
                'g': 'sum', 'mg': 'sum', 'unknown': 'first'},
                x_col:str='collection_timestamp')

*Prepare the diet log data for plotting meals and/or daily summaries.

Args:

diet_log (pd.DataFrame): The dataframe containing the diet log data, with columns for timestamps, nutrients, and other measurements.
participant_id (Optional[int]): The participant's ID to filter the diet log. If None, no filtering is done. Default is None.
array_index (Optional[int]): The array index to filter the diet log. If None, no filtering is done. Default is None.
time_range (Optional[Tuple[str, str]]): A tuple of strings representing the start and end dates for filtering the data. Format should be 'YYYY-MM-DD'. Default is None.
label (str): The name of the column in `diet_log` representing the labels for each meal. Default is 'short_food_name'.
return_meals (bool): If True, includes individual meals in the plot. Default is True.
return_summary (bool): If True, includes a daily summary in the plot. Default is False.
y_include (List[str]): A list of nutrients (regex) to include in the plot. Default is None.
y_exclude (List[str]): A list of nutrients (regex) to exclude from the plot. Default is None.
agg_units (dict): A dictionary mapping nutrient units to aggregation functions.
x_col (str): The name of the column in `diet_log` representing the x-axis variable, such as timestamps. Default is 'collection_timestamp'.

Returns:

pd.DataFrame: A dataframe containing the prepared data for plotting.*

source

plot_nutrient_lollipop

 plot_nutrient_lollipop (diet_log:pandas.core.frame.DataFrame,
                         x:str='collection_timestamp',
                         y:str='calories_kcal', size:str='total_g',
                         label:str='short_food_name',
                         participant_id:int=None, array_index:int=None,
                         time_range:Tuple[str,str]=None, meals:bool=True,
                         summary:bool=False, nut_include:List[str]=None,
                         nut_exclude:List[str]=None, legend:bool=True,
                         size_scale:float=5, palette:str='muted',
                         alpha:float=0.7,
                         ax:matplotlib.axes._axes.Axes=None,
                         figsize:Tuple[float,float]=(12, 3))

*Plot a lollipop chart with pie charts representing nutrient composition for each meal.

NOTE: The y-axis is scaled to match the units of the x-axis, to avoid distortion of the pie charts. Due to scaling, if you intend to change xlim after plotting, you must also provide date_range. Use the second_y of g.plot() option to plot it with other y-axis data.

Args:

diet_log (pd.DataFrame): The dataframe containing the diet log data, with columns for timestamps, nutrients, and other measurements.
x (str): The name of the column in `diet_log` representing the x-axis variable, such as timestamps. Default is 'collection_timestamp'.
y (str): The name of the column in `diet_log` representing the y-axis variable, such as calories. Default is 'calories_kcal'.
size (str): The name of the column in `diet_log` representing the size of the pie charts. Default is 'total_g'.
label (str): The name of the column in `diet_log` representing the labels for each meal. Default is 'short_food_name'.
participant_id (Optional[int]): The participant's ID to filter the diet log. If None, no filtering is done. Default is None.
time_range (Optional[Tuple[str, str]]): A tuple of strings representing the start and end dates for filtering the data. Format should be 'YYYY-MM-DD'. Default is None.
meals (bool): If True, includes individual meals in the plot. Default is True.
summary (bool): If True, includes a daily summary in the plot. Default is False.
nut_include (List[str]): A list of nutrients to include in the plot. Default is None.
nut_exclude (List[str]): A list of nutrients to exclude from the plot. Default is None.
legend (bool): If True, includes a legend in the plot. Default is True.
size_scale (float): The scaling factor for the size of the pie charts. Default is 5.
palette (str): The color palette to use for the pie slices. Default is DEFAULT_PALETTTE.
alpha (float): The transparency of the pie slices. Default is 0.7.
ax (Optional[plt.Axes]): The Matplotlib axis on which to plot the lollipop chart. If None, a new axis is created. Default is None.
figsize (Tuple[float, float]): The size of the figure to create. Default is (12, 6).

Returns:

plt.Axes: The Matplotlib axis on which the chart was plotted.*

source

plot_nutrient_bars

 plot_nutrient_bars (diet_log:pandas.core.frame.DataFrame,
                     x:str='collection_timestamp',
                     label:str='short_food_name', participant_id:int=None,
                     array_index:int=None, time_range:Tuple[str,str]=None,
                     meals:bool=True, summary:bool=False,
                     nut_include:List[str]=None,
                     nut_exclude:List[str]=None, agg_units:dict={'kcal':
                     'sum', 'g': 'sum', 'mg': 'sum'}, legend:bool=True,
                     bar_width=numpy.timedelta64(15,'m'),
                     palette:str='muted', alpha:float=0.7,
                     ax:matplotlib.axes._axes.Axes=None,
                     figsize:Tuple[float,float]=(14, 3))

*Plot a stacked bar chart representing nutrient intake for each meal over time.

Args:

diet_log (pd.DataFrame): The dataframe containing the diet log data, with columns for timestamps, nutrients, and other measurements.
x (str): The name of the column in `diet_log` representing the x-axis variable, such as timestamps. Default is 'collection_timestamp'.
label (str): The name of the column in `diet_log` representing the labels for each meal. Default is 'short_food_name'.
participant_id (Optional[int]): The participant's ID to filter the diet log. If None, no filtering is done. Default is None.
array_index (Optional[int]): The array index to filter the diet log. If None, no filtering is done. Default is None.
time_range (Optional[Tuple[str, str]]): A tuple of strings representing the start and end dates for filtering the data. Format should be 'YYYY-MM-DD'. Default is None.
meals (bool): If True, includes individual meals in the plot. Default is True.
summary (bool): If True, includes a daily summary in the plot. Default is False.
nut_include (List[str]): A list of nutrients to include in the plot. Default is None.
nut_exclude (List[str]): A list of nutrients to exclude from the plot. Default is None.
agg_units (dict): A dictionary mapping nutrient units to aggregation functions. Only nutrients with units in this dictionary are plotted.
legend (bool): If True, includes a legend in the plot. Default is True.
bar_width (np.timedelta64): The width of the bars representing each meal on the time axis. Default is 15 minutes.
palette (str): The color palette to use for the stacked bars.
alpha (float): The transparency of the stacked bars. Default is 0.7.
ax (Optional[plt.Axes]): The Matplotlib axis on which to plot the bar chart. If None, a new axis is created. Default is None.
figsize (Tuple[float, float]): The size of the figure to create. Default is (14, 3).

Returns:

None: The function creates a stacked bar chart on the specified or newly created axis.*

source

add_size_legend

 add_size_legend (ax:matplotlib.axes._axes.Axes, sizes:List[int],
                  size_scale:float, alpha:float, shift:int=0)

Add a size legend to a plot_meals_hbars plot using broken_barh.


source

plot_meals_hbars

 plot_meals_hbars (diet_log:pandas.core.frame.DataFrame,
                   x:str='collection_timestamp',
                   y:str='short_food_category', size:str='weight_g',
                   hue:str='short_food_category', participant_id:int=None,
                   array_index:int=None, time_range:Tuple[str,str]=None,
                   y_include:List[str]=None, y_exclude:List[str]=None,
                   rename_categories:dict={'beef, veal, lamb, and other
                   meat products': 'meat products', 'milk, cream cheese
                   and yogurts': 'milk products', 'nuts, seeds, and
                   products': 'nuts and seeds', 'eggs and their products':
                   'eggs', 'pulses and products': 'pulses', 'fruit juices
                   and soft drinks': 'juices and soft drinks', 'low
                   calories and diet drinks': 'low cal. drinks', 'poultry
                   and its products': 'poultry', 'pasta, grains and side
                   dishes': 'grains', 'industrialized vegetarian food
                   ready to eat': 'industrialized veg.'},
                   legend:bool=True, size_legend:List[int]=[100, 200,
                   500], size_scale:float=5, palette:str='muted',
                   alpha:float=0.7, ax:matplotlib.axes._axes.Axes=None,
                   figsize:Tuple[float,float]=(12, 6))

*Plot a diet chart with bars representing meals and their size over time.

Args:

diet_log (pd.DataFrame): The dataframe containing the diet log data, with columns for timestamps, nutrients, and other measurements.
x (str): The name of the column in `diet_log` representing the x-axis variable, such as timestamps. Default is 'collection_timestamp'.
y (str): The name of the column in `diet_log` representing the y-axis variable, such as food categories. Default is 'short_food_category'.
size (str): The name of the column in `diet_log` representing the size of the bars. Default is 'weight_g'.
hue (str): The name of the column in `diet_log` representing the color of the bars. Default is 'short_food_category'.
participant_id (Optional[int]): The participant's ID to filter the diet log. If None, no filtering is done. Default is None.
time_range (Optional[Tuple[str, str]]): A tuple of strings representing the start and end dates for filtering the data. Format should be 'YYYY-MM-DD'. Default is None.
y_include (List[str]): A list of strings representing the categories to include in the plot. Default is None.
y_exclude (List[str]): A list of strings representing the categories to exclude from the plot. Default is None.
rename_categories (dict): A dictionary mapping original food categories to shorter names. Default is SHORT_FOOD_CATEGORIES.
legend (bool): If True, includes a legend in the plot. Default is True.
size_legend (List[int]): A list of integers representing the sizes to include in the size legend. Default is [100, 200, 500].
size_scale (float): The scaling factor for the size of the bars. Default is 5.
palette (str): The palette to use for the bars.
alpha (float): The transparency of the bars. Default is 0.7.
ax (Optional[plt.Axes]): The Matplotlib axis on which to plot the lollipop chart. If None, a new axis is created. Default is None.
figsize (Tuple[float, float]): The size of the figure to create. Default is (12, 6).

Returns:

plt.Axes: The Matplotlib axis on which the chart was plotted.*

source

plot_diet_cgm_sleep

 plot_diet_cgm_sleep (diet:pandas.core.frame.DataFrame=None,
                      cgm:pandas.core.frame.DataFrame=None,
                      sleep_events:pandas.core.frame.DataFrame=None,
                      sleep_channels:pandas.core.frame.DataFrame=None,
                      cgm_grid:List[int]=[0, 54, 70, 100, 140, 180],
                      channel_filter:List[str]=['heart_rate', 'actigraph',
                      'spo2'], participant_id=None, array_index=None,
                      time_range:Tuple[str,str]=None, figsize=(14, 10),
                      nutrient_kws:dict={}, meals_kws:dict={},
                      cgm_kws:dict={}, events_kws:dict={},
                      channels_kws:dict={})

*Plot diet, CGM and sleep data together.

Arg:

diet (pd.DataFrame): Diet logging data. Set to None to remove from figure.
cgm (pd.DataFrame): CGM data. Set to None to remove from figure.
sleep_events (pd.DataFrame): Sleep events data. Set to None to remove from figure.
sleep_channels (pd.DataFrame): Sleep channels data. Set to None to remove from figure.
cgm_grid (List[int]): CGM grid lines. Default: [0, 54, 70, 100, 140, 180].
channel_filter (List[str]): Which sleep channels to include in the plot. Default: ['heart_rate', 'actigraph', 'spo2'].
participant_id (int): Participant ID.
array_index (int): Array index.
time_range (Tuple[str, str]): Time range to plot.
figsize (Tuple[int, int]): Figure size.
nutrient_kws (dict): Keyword arguments for diet nutrients lollipop plot.
meals_kws (dict): Keyword arguments for diet meals plot.
cgm_kws (dict): Keyword arguments for CGM plot.
events_kws (dict): Keyword arguments for sleep events plot.
channels_kws (dict): Keyword arguments for sleep channels plot.

Returns:

TimeSeriesFigure: The figure object containing the plots.*

How to plot diet logs

This module provides functions for plotting diet data, as well as a function for plotting diet, CGM and sleep data together.

First, we will load the time series data for diet, CGM and sleep. (See also the dedicated modules for sleep and CGM.)

from pheno_utils import PhenoLoader

pl = PhenoLoader('sleep')
channels_df = pl.load_bulk_data('channels_time_series')  # contains: heart_rate, spo2, respiratory_movement
events_df = pl.load_bulk_data('events_time_series')

diet_df = PhenoLoader('diet_logging').dfs['diet_logging']
cgm_df = PhenoLoader('cgm').dfs['cgm']
Warning: index is not unique for diet_logging
/home/ec2-user/projects/pheno-utils/pheno_utils/pheno_loader.py:610: UserWarning: No date field found
  warnings.warn(f'No date field found')
/home/ec2-user/projects/pheno-utils/pheno_utils/pheno_loader.py:610: UserWarning: No date field found
  warnings.warn(f'No date field found')
/home/ec2-user/projects/pheno-utils/pheno_utils/pheno_loader.py:610: UserWarning: No date field found
  warnings.warn(f'No date field found')
diet_df.head(5)
short_food_name food_category weight_g calories_kcal carbohydrate_g lipid_g protein_g sodium_mg dietary_fiber_g alcohol_g
participant_id collection_timestamp
0 2020-06-21 16:06:00+03:00 Quinoa Pasta, Grains and Side dishes_wholewheat 56.0 78.3104 12.1744 1.2992 2.8000 37.1504 1.4896 0.0
2020-06-21 16:06:00+03:00 Hummus Salad Pulses and products 80.0 215.2000 9.4400 16.8000 6.5600 377.6000 0.0000 NaN
2020-06-21 16:06:00+03:00 Meatballs Beef, veal, lamb, and other meat products 180.0 311.0940 16.1280 15.4440 24.7320 1164.5460 2.3904 0.0
2020-06-21 19:28:00+03:00 Banana Fruits 128.0 113.9200 25.9072 0.4224 1.3952 1.2800 3.3280 0.0
2020-06-21 21:07:00+03:00 Bread Bread 60.0 162.6000 28.3800 2.1000 5.2800 367.8000 1.6200 0.0
cgm_df.head(5)
glucose
participant_id collection_timestamp
0 2020-06-22 00:14:00+03:00 106.2
2020-06-22 00:29:00+03:00 100.8
2020-06-22 00:44:00+03:00 97.2
2020-06-22 00:59:00+03:00 95.4
2020-06-22 01:14:00+03:00 93.6

Next, we will use plot_diet_cgm_sleep to plot the data together.

import seaborn as sns
sns.set_style('whitegrid')

plot_diet_cgm_sleep(diet_df, cgm_df, events_df, channels_df,
                    channel_filter=['heart_rate', 'respiratory_movement', 'spo2'],
                    time_range=('2020-06-22 08:00', '2020-06-23 10:00'))

Each of the types of diet plots can be plotted independently as well. We will use TimeSeriesFigure, plot_nutrient_lollipop, plot_meals_hbars and plot_nutrient_bars to plot them together.

from pheno_utils.timeseries_plots import TimeSeriesFigure

g = TimeSeriesFigure(figsize=(14, 7))

time_range = ('2020-06-22 06:00', '2020-06-23 15:00')
# Each call to the plot() methods adds a new time-synced subplot to the figure
g.plot(plot_nutrient_lollipop, diet_df, size_scale=15,
       time_range=time_range,
       name='diet_pie')
g.plot(plot_meals_hbars, diet_df,
       time_range=time_range,
       name='diet_meals', height=2)
g.plot(plot_nutrient_bars, diet_df,
       time_range=time_range,
       label=None, n_axes=2, nut_exclude=['sodium'],
       name='diet_bars')
g.set_axis_padding(0.03)