Food in the Wolfram Language IV

Micah Lindley, Wolfram|Alpha
Andrew Steinacher, Wolfram|Alpha

Join the Conversation #WolframTechConf

Abstract

The best kitchen tools are simple to use, clean up easily, and most importantly, are multitaskers. The Wolfram Language happens to be all three and so much more. With detailed knowledge of hundreds of thousands of ingredients and branded foods, the Wolfram Language can answer queries about nutrient values, common allergens, cooking times, and even ingredient substitutions. New visualization tools such as FeatureSpacePlot visualize large, complex data sets using intuitive, elegant designs. And by harnessing the power of the Wolfram Language and the Wolfram Cloud, open-source applications like meal trackers can be developed and deployed using data already baked in to the Wolfram Knowledgebase.

SetDirectory[NotebookDirectory[]];
porkChopImage=Import["PorkChopImageRestyle.mx"];
lambChopsImage=Import["LambChopsImageRestyle.mx"];
Print@Grid[
{
Insert[Show[#,ImageSize->Scaled[0.35]]&/@{porkChopImage,lambChopsImage},Spacer[100],2]
}
]

Overview

Computational Gastronomy

Dinner Survey hosted in the Wolfram Cloud

European Holiday Foods Map

Ingredient Substitutions

Cooking Times

New Wolfram|Alpha Output

Comparison to previous system, New Pods

Food Ontology Graph

Construction, website

Open-Source Meal Tracker

Features

Results

Advanced Features

Summary

Links to Previous Talks

WTC 2015: Food and Nutrition in the Wolfram Language

Nutrition, attribute and physical properties; EntityValue features (implicit entities, EntityInstance, EntityGroup)

WordClouds, ImageCollage, and other visualizations; barcode scanning

WTC 2015 Notebook: http://library.wolfram.com/infocenter/Conferences/9330/

WTC 2016: Food and Nutrition II

Alignment to nutrient entities (dietary reference standards), cooking equipment and actions, more packaged food information

Customizable labels/visualizations, international foods (LanguaL thesaurus), meal tracking with Data Drop and the Wolfram Cloud

WTC 2016 Blog: http://blog.wolfram.com/2016/06/30/comparing-apples-and-oranges-with-the-wolfram-language/

WTC 2016 Notebook: http://wac .36f4.edgecastcdn.net/0036F4/pub/www.wolfram.com/technology-conference/2016/Andrew_Steinacher.nb

WTC 2016 Video: http://www.wolfram.com/broadcast/video.php?v=1673

WTC 2016 YouTube: https://www.youtube.com/watch?v=DFP4TGXinFI

WTC 2017: Food and Nutrition III

Common inside/outside colors, barcode support, CompassPlot redesign, LanguaL international food thesaurus alignment

PLU codes, pH properties, packaged food ingredients, dietary restrictions, ingredient substitutions

WTC 2017 Notebook: http://wac .36f4.edgecastcdn.net/0036F4/pub/www.wolfram.com/technology-conference/2017/AndrewSteinacherFoodintheWolframLanguage.nb

WTC 2017 Video: https://www.wolfram.com/broadcast/video.php?v=2024

WTC 2017 YouTube: https://www.youtube.com/watch?v=Vz-_ 31GT_Kw

WTC 2017 Presentations: https://www.wolfram.com/events/technology-conference/2017/presentations/#wednesday

Computational Gastronomy: Blog

Data Drop + Wolfram Cloud + FormFunction = Christmas dinner survey

Print@Style[Hyperlink[StringTrim[#,"http://"],#],15,FontFamily->"Source Sans Pro"]&["http://blog.wolfram.com/2017/12/22/computational-gastronomy-using-the-wolfram-language-to-prepare-a-sumptuous-holiday-feast/"]

dataDropImage= ;
christmasDinnerSurvey=;
Print@Grid[
{
Insert[Show[#,ImageSize->Scaled[0.4]]&/@{ImageCrop[dataDropImage],christmasDinnerSurvey},Spacer[50],2],
{
Column[
{
Hyperlink[Style[StringTrim[#,"https://"],30,FontFamily->"Source Sans Pro"],#],
Show[BarcodeImage[#,"QR",300],ImageSize->Scaled[0.15]]
},
Alignment->Center
]&[URLShorten@"http://blog.wolfram.com/2017/12/22/computational-gastronomy-using-the-wolfram-language-to-prepare-a-sumptuous-holiday-feast/"],
SpanFromAbove
}
},
Alignment->Top
]

Computational Gastronomy: European Holiday Food Map

SetDirectory[NotebookDirectory[]];
Import["EuropeanHolidayFoodMap_Smaller.mx"]

Computational Gastronomy: Ingredient Substitutions

Definitions

openImplicitEntityBoxes[expr_]:=ReplaceAll[
MakeBoxes[expr],
DynamicModuleBox[{EntityFramework`Formatting`Private`open=False},rest___]:>DynamicModuleBox[{EntityFramework`Formatting`Private`open=True},rest]
]//RawBoxes;

addMouseoverImages[substitutions_Association]:=With[{replace=ReplaceAll[ent:Entity["Food",{__Rule}]:>With[{foodTypeImages=Cases[ent,ft:Entity["FoodType",_String]:>ft["Image"],Infinity,1]},If[MatchQ[foodTypeImages,{_Image}],Mouseover[Image[First[foodTypeImages],ImageSize->{UpTo[160],120}],ent,ImageSize->All,Alignment->{Center,Bottom}],ent]]]},replace/@KeyMap[replace,substitutions]];

visualizeEntityInstance[EntityInstance[ent_,q_Quantity]]:=Row[{Framed[Row[{q,Text[" of  "],ent}],FrameStyle->GrayLevel[0.9],RoundingRadius->15],Spacer[1]}];
visualizeEntityGroup[EntityGroup[group_List]]:=Row[Riffle[group/.ei_EntityInstance:>visualizeEntityInstance[ei]," + "],Frame->All,Alignment->Center,FrameStyle->Thick];

makeGridData[substitutions_Association]:=KeyValueMap[{#1/.ei_EntityInstance:>visualizeEntityInstance[ei],Style["⟹",25,Bold],Column[Riffle[#2/.eg_EntityGroup:>visualizeEntityGroup[eg],"— OR —"],Frame->None,Alignment->Center,FrameStyle->Dashed]}&,substitutions];

visualizeReplacements[substitutions_Association]:=With[{gridData=makeGridData[addMouseoverImages[substitutions]]},
Grid[gridData/.e_Entity:>openImplicitEntityBoxes[e]]
];

Examples

(Entity["allspice", Entity["FoodType","Allspice"], "Entity[\"FoodType\", \"Allspice\"]", "food type"])[(EntityProperty["possible ingredient substitutions", EntityProperty["FoodType","PossibleIngredientSubstitutions"], "EntityProperty[\"FoodType\", \"PossibleIngredientSubstitutions\"]"])]//visualizeReplacements

(Entity["baking powder", Entity["FoodType","BakingPowder"], "Entity[\"FoodType\", \"BakingPowder\"]", "food type"])[(EntityProperty["possible ingredient substitutions", EntityProperty["FoodType","PossibleIngredientSubstitutions"], "EntityProperty[\"FoodType\", \"PossibleIngredientSubstitutions\"]"])]//visualizeReplacements

Computational Gastronomy: Ingredient Substitutions

Arugula and Bear

Grid[
{
Insert[visualizeReplacements/@{
(Entity["arugula", Entity["FoodType","Arugula"], "Entity[\"FoodType\", \"Arugula\"]", "food type"])[(EntityProperty["possible ingredient substitutions", EntityProperty["FoodType","PossibleIngredientSubstitutions"], "EntityProperty[\"FoodType\", \"PossibleIngredientSubstitutions\"]"])],
(Entity["bear", Entity["FoodType","Bear"], "Entity[\"FoodType\", \"Bear\"]", "food type"])[(EntityProperty["possible ingredient substitutions", EntityProperty["FoodType","PossibleIngredientSubstitutions"], "EntityProperty[\"FoodType\", \"PossibleIngredientSubstitutions\"]"])]//Map[Drop[#,-3]&]
},Spacer[100],2]
}
]

Computational Gastronomy: Cooking Times

Definition

ClearAll[cookingTimeBarChart];
cookingTimeBarChart[foodType_Entity,{color1_RGBColor,color2_RGBColor,color3_RGBColor}]:=BarChart3D[
KeyValueMap[
Tooltip[Labeled[
MinMax@QuantityMagnitude[#2,"Minutes"],
Style[
#1,
FontFamily->"Impact",
FontSize->18,
FontColor->color1
]
],
Style[
StringTrim[ToString@QuantityMagnitude[#2,"Minutes"][[1,1]],"."]<>" to "<>StringTrim[ToString@QuantityMagnitude[#2,"Minutes"][[1,2]],"."]<>" minutes",
FontFamily->"Impact",
FontSize->18,
FontColor->color1
]
]&,
KeyDrop[(Entity["StirFry", Entity["CookingAction","StirFry"], "Entity[\"CookingAction\", \"StirFry\"]", "cooking action"])]@EntityValue[foodType,"ApproximateCookingTimeAssociation"][[1,All,"Typical"]]
]//SortBy[First],
PlotTheme->"Detailed",
BarOrigin->Left,
AspectRatio->1/3,
ImageSize->Scaled[0.8],
PlotLabel->Style[
StringTemplate["Cooking times for ``"][Capitalize@foodType["Name"]],
FontFamily->"Impact",
FontSize->30,
FontColor->color2
],
ChartStyle->{color2,Blend[{color2,color3},3/4]},
ChartLegends->(
Style[
#,
FontFamily->"Impact",
FontSize->18,
FontColor->color1
]&/@{"Minimum Time","Maximum Time"})
];

Example

broccoliRaabColors=DominantColors[Entity["FoodType","BroccoliRaab"]["Image"]]

cookingTimeBarChart[(Entity["broccoli raab", Entity["FoodType","BroccoliRaab"], "Entity[\"FoodType\", \"BroccoliRaab\"]", "food type"]),{Darker@,,}]

Computational Gastronomy: Cooking Times

cornColors=DominantColors[(Entity["corn", Entity["FoodType","Corn"], "Entity[\"FoodType\", \"Corn\"]", "food type"])["Image"]]

cookingTimeBarChart[(Entity["corn", Entity["FoodType","Corn"], "Entity[\"FoodType\", \"Corn\"]", "food type"]),{Darker@,,}]

Computational Gastronomy: Cooking Times

baconColors=DominantColors[(Entity["bacon", Entity["FoodType","Bacon"], "Entity[\"FoodType\", \"Bacon\"]", "food type"])["Image"]]

cookingTimeBarChart[(Entity["bacon", Entity["FoodType","Bacon"], "Entity[\"FoodType\", \"Bacon\"]", "food type"]),{,,}]

New Wolfram|Alpha Output: Overview

Access to ~150k foods

The new system has about 10 times as many foods as the previous system:

BarChart[
Reverse[
KeyValueMap[
Labeled[#2,Style[#,16]&/@{#1,Row[{Ceiling[#2,2000]," foods"}]},{Before,After}]&,
<|"Old"->11886,"New"->EntityValue["Food","EntityCount"]|>
]
],
PlotTheme->"Detailed",
ChartLabels->Automatic,
BarSpacing->Large,
BarOrigin->Left,
PlotRange->190000,
AspectRatio->1/3,
ImageSize->Scaled[0.6]
]

New Wolfram|Alpha Output: Overview

More Visually Appealing

Print@Row[{,Column[{,}]}/.i_Image:>Show[i,ImageSize->Scaled[0.4]],Style["  ->  ",36,Bold]]

New Wolfram|Alpha Output: Nutrition Label

Ranges

Print@Row[{,}/.i_Image:>Show[i,ImageSize->Scaled[0.4]],Style[" -> ",36,Bold]]

New Wolfram|Alpha Output: Compass Plot

Choose Nutrient Groups

Print@Grid[
{
{,},
{,}
}/.i_Image:>Show[i,ImageSize->Scaled[0.4]]
]

New Wolfram|Alpha Output: Nutrition Distributions

“saltine crackers vs refried beans”

Print@Grid[{Show[#,ImageSize->Scaled[0.46]]&/@{,}}]

New Wolfram|Alpha Output: Activity Times

Caloric Equivalent Times (“big mac”)

Print@Show[,ImageSize->Scaled[0.45]]

New Wolfram|Alpha Output: In Development

Packaged Food Ingredients

Cake

Print@Show[,ImageSize->Scaled[0.6]]

Miso Soup

Print@Show[,ImageSize->Scaled[0.6]]

New Wolfram|Alpha Output: In Development

Dietary Restrictions (“refried  beans”)

Print@Show[,ImageSize->Scaled[0.6]]

Food Ontology Graph: Overview

Print@Row[{Show[,ImageSize->Scaled[0.45]],Column[{Style[Hyperlink[#],36,FontFamily->"Source Sans Pro"],Show[BarcodeImage[#,"QR"],ImageSize->Scaled[0.2]]},Alignment->Center]&["wolfr.am/foodgraph"]},Spacer[20]]

Food Ontology Graph: Overview

Larger images, PDFs, etc...

Food Ontology Graph: Construction

Gather Entities

foodEntityTypes=Select[EntityValue[],StringContainsQ["Food"]]

Gather Property Metadata

Takes a bit to run as it gathers metadata for all properties for all Food entity types:

getPropertyMetadata[entityType_String]:=EntityPropertyClass[entityType,All][{"Label","OutputType","Definition","PhysicalQuantity","Unit"},"Association"];
entityTypeToPropertyMetaData0=AssociationMap[getPropertyMetadata,foodEntityTypes];

entityTypeToPropertyMetaData0["Food"][[;;10]]//Values//Dataset

Other processing steps (notebooks available on the website)

Food Ontology Graph: Construction

Create basic graph, cleanup redundant and messy structures

Use properties to connect an entity type to another entity type or data type:

Print@Row[MapAt[Framed,Show[#,ImageSize->Scaled[0.28]]&/@{,,},-1],Style["->",36,Bold]]

Food Ontology Graph: Construction

Define useful node groups, use CommunityGraphPlot, add colors, minor styling tweaks...

Print@Row[Show[#,ImageSize->Scaled[0.4]]&/@{,},Style[" -> ",Bold,FontSize->36]]

Food Ontology Graph: Website

Print@Style[Hyperlink["github.com/drewsteinacher/FoodOntologyGraph","https://www.github.com/drewsteinacher/FoodOntologyGraph"],30,FontFamily->"Source Sans Pro"]

Print@Row[
{
Show[,ImageSize->Scaled[0.4]],
Column[
{
Style[Hyperlink[StringTrim[#,"https://"],#],36,FontFamily->"Source Sans Pro"],
Show[BarcodeImage[#,"QR"],ImageSize->Scaled[0.2]]
},
Alignment->Center
]&["https://wolfr.am/ydmY8xxf"]
},
Spacer[100]
]

Open Source Meal Tracker: Overview

Print@Style[Hyperlink["github.com/drewsteinacher/Meal-Tracker","https://github.com/drewsteinacher/Meal-Tracker"],30,FontFamily->"Source Sans Pro"]

Print@Row[
{
Show[,ImageSize->Scaled[0.5]],
Column[
{
Style[Hyperlink[StringTrim[#,"https://"],#],36,FontFamily->"Source Sans Pro"],
Show[BarcodeImage[#,"QR"],ImageSize->Scaled[0.2]]
},
Alignment->Center
]&["https://wolfr.am/uDQfLgI7"]
},
Spacer[10]
]

Open Source Meal Tracker: Features

Simple Food/Meal Entry

Print@Grid[{
Style[#,25,FontFamily->"Source Sans Pro"]&/@{"Natural Language","Enter a Code","Scan a Barcode"},
Rasterize[#,ImageSize->Scaled[0.3],RasterSize->2000]&/@{,,}
},Alignment->{Center,Top}]

Open Source Meal Tracker: Features

Nutrition Entry

Print[
Grid[
{
Style[#,24,FontFamily->"Source Sans Pro"]&/@{"Automatically added","Manual entry/editing"},
{
Grid[List[Rasterize[#,ImageSize->Scaled[0.3],RasterSize->2000]&/@{,}],Alignment->Top],
Rasterize[#,ImageSize->Scaled[0.3],RasterSize->2000]&@
}
},
Alignment->Top
]
]

Open Source Meal Tracker: Features

Meal Entry

Print@Grid[
{
Style[#,24,FontFamily->"Source Sans Pro"]&/@{"Select Foods","","Enter Serving Sizes"},
Insert[Rasterize[#,ImageSize->Scaled[0.45],RasterSize->1000]&/@{,},Style[" -> ",36, Bold],2]
}
]

Open Source Meal Tracker: Features

Log Meals

Print@Grid[
Insert[#,Spacer[50],2]&/@{
Style[#,24,FontFamily->"Source Sans Pro"]&/@{"Select Meals","Edit Serving Sizes"},
Rasterize[#,ImageSize->Scaled[0.4],RasterSize->2000]&/@{,}},Alignment->Top]

Open Source Meal Tracker: Features

View history

Print@Grid[
Insert[#,Spacer[75],2]&/@{
Style[#,24,FontFamily->"Source Sans Pro"]&/@{"Radar Plots","Time Series"},
Rasterize[#,ImageSize->Scaled[0.4],RasterSize->1000]&/@{,}
}
]

Open Source Meal Tracker: Results

Custom Data Analysis

Open Source Meal Tracker: Results

Custom Data Analysis

({{({{"Full Day (Median)"}, {}}), ({{"Full Day (Mean)"}, {}})}})/.i_Graphics:>Show[i,ImageSize->Scaled[0.3]]

Open Source Meal Tracker: Advanced Features

Reminders

Print@Grid[
{
Style[#,24,FontFamily->"Source Sans Pro"]&/@{"Setup","","Examples"},
Insert[Rasterize[#,ImageSize->Scaled[0.4],RasterSize->1000]&/@{,},Style[" -> ",36,Bold],2]
}
]

Open Source Meal Tracker: Advanced Features

Meal Recommendations (via LinearProgramming)

Print@Grid[
{
{
Show[Import["C:\\Users\\andrews\\WolframWorkspaces\\Base\\ExpandedFoodData\\Construction\\FoodDataCloud\\IFT\\MealTracker_Suggestion.PNG"],ImageSize->Scaled[0.43]],Show[Import["C:\\Users\\andrews\\WolframWorkspaces\\Base\\ExpandedFoodData\\Construction\\FoodDataCloud\\IFT\\MealSuggestion_Basic.PNG"],ImageSize->Scaled[0.45]]
}
}
]

Open Source Meal Tracker: Advanced Features

Meal Recommendations (via LinearProgramming)

Print@Grid[
{
{
Item[Show[,ImageSize->Scaled[0.45]],Alignment->Center],
Item[Style["->",36,Bold],Alignment->Center],
Show[Import["C:\\Users\\andrews\\WolframWorkspaces\\Base\\ExpandedFoodData\\Construction\\FoodDataCloud\\IFT\\MealTracker_Suggestion_2.PNG"],ImageSize->Scaled[0.45]]
},
{SpanFromAbove,SpanFromAbove,Show[Import["C:\\Users\\andrews\\WolframWorkspaces\\Base\\ExpandedFoodData\\Construction\\FoodDataCloud\\IFT\\MealSuggestion_EditFood.PNG"],ImageSize->Scaled[0.45]]}
}
]

Open Source Meal Tracker: Implementation Details

History tracking based on Data Drop

?CreateDatabin

Documentation: https://reference.wolfram.com/language/ref/Databin.html

Quick start guide: http://www.wolfram.com/datadrop/quick-reference/home/

Example where I use it: http://blog.wolfram.com/2017/06/22/create-a-tracker-to-analyze-gas-mileage-using-wolfram-tech/

Foods and meals based on WL EntityStore

?EntityStore

Easily extend entity types that are already in the Wolfram Knowledgebase

Documentation: reference.wolfram.com/language/ref/EntityStore.html

See Toni’s Custom Entities talk from WTC 2016: http://wac .36f4.edgecastcdn.net/0036F4/pub/www.wolfram.com/technology-conference/2016/2016CustomEntities.nb

Summary

Computational Gastronomy

Dinner Survey hosted in the Wolfram Cloud

European Holiday Foods Map

Ingredient Substitutions

Cooking Times

New Wolfram|Alpha Output

Comparison to previous system, New Pods

Food Ontology Graph

Construction, website

Open-Source Meal Tracker

Features

Results

Advanced Features

Summary