Food and Nutrition III

Andrew Steinacher
Brandon Kocher

Wolfram|Alpha

October 18th, 2017

Join the Conversation #WolframTechConf

Overview

Brief overview of food in the Wolfram Language

Data and features available

Some applications

Improvements

Common inside/outside colors

Barcode support

CompassPlot redesign

LanguaL international food thesaurus alignment

New Wolfram Language food data

PLU codes

pH properties

Packaged food ingredients

Dietary restrictions

Ingredient substitutions

Future goals

Summary

Review: Links to Previous Talks

WTC 2015: “Food and Nutrition in the Wolfram Language”

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

Nutrition, attribute and physical properties

EntityValue features (Implicit entities, EntityInstance, EntityGroup)

WordClouds, ImageCollage, other visualizations

Barcode scanning

WTC 2016: “Food and Nutrition II”

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

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

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

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

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

Review: Nutritional Information

We have nutritional information properties for nearly 150,000 foods and over 150 nutrients:

(Entity["Crustaceans, lobster, northern, raw", Entity["Food","CrustaceansLobsterNorthernRaw::bqdp2"], "Entity[\"Food\", \"CrustaceansLobsterNorthernRaw::bqdp2\"]", "food"])[{(EntityProperty["nutrition label", EntityProperty["Food","NutritionLabel"], "EntityProperty[\"Food\", \"NutritionLabel\"]"]),(EntityProperty["relative omega six fatty acid content", EntityProperty["Food","RelativeTotalOmegaSixFattyAcidContent"], "EntityProperty[\"Food\", \"RelativeTotalOmegaSixFattyAcidContent\"]"]),(EntityProperty["relative omega three fatty acid content", EntityProperty["Food","RelativeTotalOmegaThreeFattyAcidContent"], "EntityProperty[\"Food\", \"RelativeTotalOmegaThreeFattyAcidContent\"]"]),(EntityProperty["relative butyric acid content", EntityProperty["Food","RelativeButyricAcidContent"], "EntityProperty[\"Food\", \"RelativeButyricAcidContent\"]"]),(EntityProperty["relative linoleic acid content", EntityProperty["Food","RelativeLinoleicAcidContent"], "EntityProperty[\"Food\", \"RelativeLinoleicAcidContent\"]"])},"PropertyAssociation"]

Review: Food Classification and Representation

With a growing set of over 10,000 attributes and nearly 50 categories, we can represent a wide range of foods:

EntityValue[{(Entity["Apples, raw, red delicious, with skin", Entity["Food","ApplesRawRedDeliciousWithSkin::v353h"], "Entity[\"Food\", \"ApplesRawRedDeliciousWithSkin::v353h\"]", "food"]),(Entity["Da Vinci Gourmet Vanilla Syrup Sugar Free", Entity["Food","DaVinciGourmetVanillaSyrupSugarFree::ftgm3"], "Entity[\"Food\", \"DaVinciGourmetVanillaSyrupSugarFree::ftgm3\"]", "food"]),(Entity["Weight Watchers Blueberry Muffin", Entity["Food","WeightWatchersBlueberryMuffin::k48q8"], "Entity[\"Food\", \"WeightWatchersBlueberryMuffin::k48q8\"]", "food"])},"CategoricalPropertyValues","Dataset"]

EntityValue[{(Entity["Apples, raw, red delicious, with skin", Entity["Food","ApplesRawRedDeliciousWithSkin::v353h"], "Entity[\"Food\", \"ApplesRawRedDeliciousWithSkin::v353h\"]", "food"]),(Entity["Da Vinci Gourmet Vanilla Syrup Sugar Free", Entity["Food","DaVinciGourmetVanillaSyrupSugarFree::ftgm3"], "Entity[\"Food\", \"DaVinciGourmetVanillaSyrupSugarFree::ftgm3\"]", "food"]),(Entity["Weight Watchers Blueberry Muffin", Entity["Food","WeightWatchersBlueberryMuffin::k48q8"], "Entity[\"Food\", \"WeightWatchersBlueberryMuffin::k48q8\"]", "food"])},"CategoricalPropertyValues","Dataset"]//Rasterize[#,ImageSize->1200]&

Review: Physical Information

We have several non-nutritional properties of curated data for over 1000 food types:

EntityValue[{(Entity["apple", Entity["FoodType","Apple"], "Entity[\"FoodType\", \"Apple\"]", "food type"]),(Entity["watermelon", Entity["FoodType","Watermelon"], "Entity[\"FoodType\", \"Watermelon\"]", "food type"]),(Entity["bratwurst", Entity["FoodType","Bratwurst"], "Entity[\"FoodType\", \"Bratwurst\"]", "food type"]),(Entity["sweet potato", Entity["FoodType","SweetPotato"], "Entity[\"FoodType\", \"SweetPotato\"]", "food type"])},{(EntityProperty["name", EntityProperty["FoodType","Name"], "EntityProperty[\"FoodType\", \"Name\"]"]),(EntityProperty["image", EntityProperty["FoodType","Image"], "EntityProperty[\"FoodType\", \"Image\"]"]),(EntityProperty["common outside color", EntityProperty["FoodType","CommonOutsideColor"], "EntityProperty[\"FoodType\", \"CommonOutsideColor\"]"]),(EntityProperty["common inside color", EntityProperty["FoodType","CommonInsideColor"], "EntityProperty[\"FoodType\", \"CommonInsideColor\"]"]),(EntityProperty["approximate shape", EntityProperty["FoodType","ApproximateShape"], "EntityProperty[\"FoodType\", \"ApproximateShape\"]"]),(EntityProperty["approximate shape dimensions", EntityProperty["FoodType","ApproximateShapeDimensions"], "EntityProperty[\"FoodType\", \"ApproximateShapeDimensions\"]"])},"PropertyAssociation"];
Grid[Prepend[Values[%],Keys[First[%]]],Frame->All,Background->{Automatic,{LightGray,White}},Alignment->{Center,Center}]

Review: Weighted Image Collages

Vegetables with white or cream interiors weighted by iron content

imageCollageData=Rule[QuantityMagnitude[#1],#2]&@@@Select[EntityValue[,{(EntityProperty["relative iron content", EntityProperty["FoodType","RelativeIronContent"], "EntityProperty[\"FoodType\", \"RelativeIronContent\"]"]),(EntityProperty["image", EntityProperty["FoodType","Image"], "EntityProperty[\"FoodType\", \"Image\"]"])}],FreeQ[_Missing]];
ImageCollage[imageCollageData,"Fit",Background->White,ImagePadding->4,ImageSize->1200]

Review: Natural Language Processing

The Wolfram Language offers several ways to harness the NLP capabilities of Wolfram|Alpha:

Interpreter[“Food”]

Implicit entities allow for representing and querying for foods with implicit entity syntax:

AssociationMap[Interpreter["Food"],{"red delicious apple","big mac","pepsi"}]

Interpreter[“FoodType”]

Food types give a “fuzzier” way to navigate the food data that is available:

AssociationMap[Interpreter["FoodType"],{"soda","yam","rapini"}]

Improved: Number of Foods

We’ve added data for ~50,000 foods each year since 2015:

BarChart[
KeyMap[Style[#,18]&,<|2015->38000,2016->100000,2017->148000|>],
ChartLabels->Placed[Automatic,Top],
PlotTheme->"Detailed",
FrameLabel->(Style[#,25]&/@{"WTC Year","Food entities"}),
ImageSize->Large,
FrameStyle->Directive[18]
]

Improved: Curated Inside and Outside Colors

Previously, we only had a set of possible colors. Now, we also have a curated single common color for each FoodType:

EntityValue[(Entity["apple", Entity["FoodType","Apple"], "Entity[\"FoodType\", \"Apple\"]", "food type"]),{(EntityProperty["possible outside colors", EntityProperty["FoodType","PossibleOutsideColors"], "EntityProperty[\"FoodType\", \"PossibleOutsideColors\"]"]),(EntityProperty["common outside color", EntityProperty["FoodType","CommonOutsideColor"], "EntityProperty[\"FoodType\", \"CommonOutsideColor\"]"]),(EntityProperty["common inside color", EntityProperty["FoodType","CommonInsideColor"], "EntityProperty[\"FoodType\", \"CommonInsideColor\"]"])},"PropertyAssociation"]//viz

viz=(#/.KeyValueMap[Rule[#1,Column[{#1,#2},Spacer[1],Alignment->Center]]&,EntityValue["ColorSet","TypicalColorValue","EntityAssociation"]])&;
EntityValue[(Entity["apple", Entity["FoodType","Apple"], "Entity[\"FoodType\", \"Apple\"]", "food type"]),{(EntityProperty["possible outside colors", EntityProperty["FoodType","PossibleOutsideColors"], "EntityProperty[\"FoodType\", \"PossibleOutsideColors\"]"]),(EntityProperty["common outside color", EntityProperty["FoodType","CommonOutsideColor"], "EntityProperty[\"FoodType\", \"CommonOutsideColor\"]"]),(EntityProperty["common inside color", EntityProperty["FoodType","CommonInsideColor"], "EntityProperty[\"FoodType\", \"CommonInsideColor\"]"])},"PropertyAssociation"]//viz

This takes the guesswork out of choosing colors for food type entities in an application:

rawData=EntityValue[,{(EntityProperty["relative vitamin A (RAE) content", EntityProperty["FoodType","RelativeVitaminAContent"], "EntityProperty[\"FoodType\", \"RelativeVitaminAContent\"]"]),(EntityProperty["name", EntityProperty["FoodType","Name"], "EntityProperty[\"FoodType\", \"Name\"]"]),(EntityProperty["common outside color", EntityProperty["FoodType","CommonOutsideColor"], "EntityProperty[\"FoodType\", \"CommonOutsideColor\"]"])}]//DeleteMissing[#,1,2]&;
colorSetToColor=EntityValue["ColorSet","TypicalColorValue","EntityAssociation"];
WordCloud[(#1->Style[#2,colorSetToColor[#3]])&@@@rawData]

Improved: Barcode Support

UPC lookups now automatically compute the check digit for you if you leave it out (similar to BarcodeImage):

EntityValue[,"UniversalProductCodes","EntityAssociation"]

We also support various versions of GTIN (a superset of UPC):

EntityValue[,(EntityProperty["global trade identification numbers", EntityProperty["Food","GlobalTradeIdentificationNumbers"], "EntityProperty[\"Food\", \"GlobalTradeIdentificationNumbers\"]"]),"NonMissingEntityAssociation"]

You can easily make barcodes:

Map[Column[{BarcodeImage[#,"EAN8"],#},Alignment->Center]&]/@EntityValue[,(EntityProperty["global trade identification numbers", EntityProperty["Food","GlobalTradeIdentificationNumbers"], "EntityProperty[\"Food\", \"GlobalTradeIdentificationNumbers\"]"]),"EntityAssociation"]

Improved: CompassPlot

Previously, our “compass plot” property was a bit difficult to read and understand, especially with small amounts of nutrition:

Rasterize[({{(Entity["estimated average requirement", Entity["DietaryReferenceIntakeType","EstimatedAverageRequirement"], "Entity[\"DietaryReferenceIntakeType\", \"EstimatedAverageRequirement\"]", "dietary reference intake type"]), (Entity["recommended dietary allowance", Entity["DietaryReferenceIntakeType","RecommendedDietaryAllowance"], "Entity[\"DietaryReferenceIntakeType\", \"RecommendedDietaryAllowance\"]", "dietary reference intake type"]), (Entity["daily value", Entity["DietaryReferenceIntakeType","DailyValue"], "Entity[\"DietaryReferenceIntakeType\", \"DailyValue\"]", "dietary reference intake type"]), (Entity["tolerable upper intake level", Entity["DietaryReferenceIntakeType","TolerableUpperIntakeLevel"], "Entity[\"DietaryReferenceIntakeType\", \"TolerableUpperIntakeLevel\"]", "dietary reference intake type"])}, {, , , }}),ImageSize->1200]

After some redesign, a legend was added and the plot scales (or “zooms in”) based on the largest nutrient’s amount:

GraphicsRow[EntityValue[EntityInstance[,#],]/.g_Graphics:>Append[g,PlotLabel->#]&/@{(Quantity[200, "g", grams, "Grams"]),(Quantity[400, "g", grams, "Grams"]),(Quantity[600, "g", grams, "Grams"])},ImageSize->1000,Frame->All
]

Improved: LanguaL International Food Thesaurus

We have data for more than 25,000 international foods from more than 20 countries:

EntityValue[,"EntityCount"]

countryCounts=AssociationMap[EntityValue[Entity["Food","DataSourceCountries"->#],"EntityCount"]&,Union@@EntityValue["FoodDataSource","Countries"]];
GeoRegionValuePlot[KeyDrop[countryCounts,{(Entity["United States", Entity["Country","UnitedStates"], "Entity[\"Country\", \"UnitedStates\"]", "country"]),(Entity["Canada", Entity["Country","Canada"], "Entity[\"Country\", \"Canada\"]", "country"])}],GeoLabels->(Tooltip[#1,Row[{#2,": ",#4, " foods"},Frame->All]]&)]

Improved: LanguaL International Food Thesaurus

LanguaL has nearly 7000 detailed terms for cooking methods, food sources, product types and more, many of which are translated into several languages:

(Entity["BOILED", Entity["LanguaLTerm","G0014"], "Entity[\"LanguaLTerm\", \"G0014\"]", "LanguaL term"])[{(EntityProperty["descriptor", EntityProperty["LanguaLTerm","Descriptor"], "EntityProperty[\"LanguaLTerm\", \"Descriptor\"]"]),(EntityProperty[(RowDefault["descriptor", " | ", (RowWithSeparators[;, ";", (Entity["French", Entity["Language","French"], "Entity[\"Language\", \"French\"]", "language"])])]), EntityProperty["LanguaLTerm","Descriptor",{"Language"->Entity["Language","French"]}], "EntityProperty[\"LanguaLTerm\", \"Descriptor\", {\"Language\" -> Entity[\"Language\", \"French\"]}]"]),(EntityProperty["description", EntityProperty["LanguaLTerm","Description"], "EntityProperty[\"LanguaLTerm\", \"Description\"]"]),(EntityProperty[(RowDefault["description", " | ", (RowWithSeparators[;, ";", (Entity["German", Entity["Language","German"], "Entity[\"Language\", \"German\"]", "language"])])]), EntityProperty["LanguaLTerm","Description",{"Language"->Entity["Language","German"]}], "EntityProperty[\"LanguaLTerm\", \"Description\", {\"Language\" -> Entity[\"Language\", \"German\"]}]"]),(EntityProperty["languages", EntityProperty["LanguaLTerm","Languages"], "EntityProperty[\"LanguaLTerm\", \"Languages\"]"])},"PropertyAssociation"]

Compilers manually tag foods with LanguaL terms:

(Entity["Giouvarlakia soup (minced meat and rice balls)", Entity["Food","GiouvarlakiaSoupMincedMeatAndRiceBalls::ns3m9"], "Entity[\"Food\", \"GiouvarlakiaSoupMincedMeatAndRiceBalls::ns3m9\"]", "food"])[(EntityProperty["LanguaL terms", EntityProperty["Food","LanguaLTerms"], "EntityProperty[\"Food\", \"LanguaLTerms\"]"])]

Improved: LanguaL International Food Thesaurus

Previously, LanguaL terms had to be used to do lookups on our international foods:

cheeseCountryData=EntityValue[,(EntityProperty["data source countries", EntityProperty["Food","DataSourceCountries"], "EntityProperty[\"Food\", \"DataSourceCountries\"]"])];

With[{cheeseCounts=KeyDrop[Counts[Flatten[cheeseCountryData]],{(Entity["Canada", Entity["Country","Canada"], "Entity[\"Country\", \"Canada\"]", "country"])}]},
GeoRegionValuePlot[cheeseCounts,GeoLabels->(Tooltip[#1,Row[{#2,": ",#4, " cheeses"},Frame->All]]&)]
]

Improved: LanguaL International Food Thesaurus

With recent alignment efforts to the LanguaL international food thesaurus, we can instead query using the usual food attributes:

fishCountryData=EntityValue[,(EntityProperty["data source countries", EntityProperty["Food","DataSourceCountries"], "EntityProperty[\"Food\", \"DataSourceCountries\"]"])];

With[{fishCounts=KeyDrop[Counts[Flatten[fishCountryData]],{(Entity["Canada", Entity["Country","Canada"], "Entity[\"Country\", \"Canada\"]", "country"])}]},
GeoRegionValuePlot[fishCounts,GeoLabels->(Tooltip[#1,Row[{#2,": ",#4, " fish"},Frame->All]]&)]
]

New: PLU Code Alignment

We have support for PLU (Price Look-Up) codes, which are widely used around the world for produce items in grocery stores.

EntityProperties["PLUCode"]

PLUs help grocery stores maintain prices and inventory for hundreds of varieties of fruits and vegetables:

EntityValue[{(Entity["4186", Entity["PLUCode","4186"], "Entity[\"PLUCode\", \"4186\"]", "product lookup code"]),(Entity["4521", Entity["PLUCode","4521"], "Entity[\"PLUCode\", \"4521\"]", "product lookup code"]),(Entity["3283", Entity["PLUCode","3283"], "Entity[\"PLUCode\", \"3283\"]", "product lookup code"]),(Entity["4582", Entity["PLUCode","4582"], "Entity[\"PLUCode\", \"4582\"]", "product lookup code"]),(Entity["4093", Entity["PLUCode","4093"], "Entity[\"PLUCode\", \"4093\"]", "product lookup code"])},{(EntityProperty["category", EntityProperty["PLUCode","Category"], "EntityProperty[\"PLUCode\", \"Category\"]"]),(EntityProperty["commodity", EntityProperty["PLUCode","Commodity"], "EntityProperty[\"PLUCode\", \"Commodity\"]"]),(EntityProperty["variety", EntityProperty["PLUCode","Variety"], "EntityProperty[\"PLUCode\", \"Variety\"]"]),(EntityProperty["size", EntityProperty["PLUCode","Size"], "EntityProperty[\"PLUCode\", \"Size\"]"])},"EntityPropertyAssociation"]//niceGrid

PLUs frequently have size information, which is typically determined by how many fit in a standard container in the US, or a mass/diameter for elsewhere in the world:

EntityValue[{(Entity["4225", Entity["PLUCode","4225"], "Entity[\"PLUCode\", \"4225\"]", "product lookup code"]),(Entity["4958", Entity["PLUCode","4958"], "Entity[\"PLUCode\", \"4958\"]", "product lookup code"])},{(EntityProperty["commodity", EntityProperty["PLUCode","Commodity"], "EntityProperty[\"PLUCode\", \"Commodity\"]"]),(EntityProperty["variety", EntityProperty["PLUCode","Variety"], "EntityProperty[\"PLUCode\", \"Variety\"]"]),(EntityProperty["count size", EntityProperty["PLUCode","CountSize"], "EntityProperty[\"PLUCode\", \"CountSize\"]"]),(EntityProperty["mass", EntityProperty["PLUCode","Mass"], "EntityProperty[\"PLUCode\", \"Mass\"]"]),(EntityProperty["diameter", EntityProperty["PLUCode","Diameter"], "EntityProperty[\"PLUCode\", \"Diameter\"]"])},"NonMissingPropertyAssociation"]

New: PLU Code Alignment

With a little bit of code, you can get PLU code entities from images and also find how they’re represented in our food system:

ClearAll[getPLUCode];
getPLUCode[image_Image]:=With[{barcode=BarcodeRecognize[image]},
Replace[
StringTake[barcode,{-5,-2}],
s_String/;StringMatchQ[s,Repeated[DigitCharacter,{4}]]:>With[{plu=Entity["PLUCode",s]},plu->plu["ImplicitFood"]]]
];

Association[getPLUCode/@{,}]

New: Approximate pH Data

We now have pH values for many food types:

EntityValue[{(Entity["apple", Entity["FoodType","Apple"], "Entity[\"FoodType\", \"Apple\"]", "food type"]),(Entity["bean", Entity["FoodType","Bean"], "Entity[\"FoodType\", \"Bean\"]", "food type"]),(Entity["orange", Entity["FoodType","Orange"], "Entity[\"FoodType\", \"Orange\"]", "food type"])},(EntityProperty["approximate pH", EntityProperty["FoodType","ApproximatepH"], "EntityProperty[\"FoodType\", \"ApproximatepH\"]"]),"EntityAssociation"]

Find alkaline (basic) food types:

EntityValue[,(EntityProperty["approximate pH", EntityProperty["FoodType","ApproximatepH"], "EntityProperty[\"FoodType\", \"ApproximatepH\"]"]),"EntityAssociation"]

There are many more acidic food types:

EntityValue[,"EntityCount"]

Find food types within a certain pH range:

EntityValue[,"Entities"]

New: Detailed pH Data

There are more detailed values that can be given in an association:

EntityValue[(Entity["apple", Entity["FoodType","Apple"], "Entity[\"FoodType\", \"Apple\"]", "food type"]),(EntityProperty["pH association", EntityProperty["FoodType","pHAssociation"], "EntityProperty[\"FoodType\", \"pHAssociation\"]"])]

New: Approximate pH Visualization

Use NumberLinePlot to visualize pH of various food type groups:

phData=EntityValue["FoodType","ApproximatepH","NonMissingEntityAssociation"];
ftgToFT=EntityValue["FoodTypeGroup","FoodTypes","EntityAssociation"];
foodTypeGroupings=GroupBy[Keys[phData],EntityValue[Entity["FoodTypeGroup","FoodTypes"->#],"Entities"]&];
simplifiedGroupedData=Interval[MinMax[Lookup[phData,#]]]&/@KeyMap[First,KeySelect[foodTypeGroupings,Length[#]>0&]];
simplifiedGroupedData=(*Reverse@*)SortBy[simplifiedGroupedData,Mean[First@#]&];
plot=NumberLinePlot[
KeyValueMap[Tooltip[#2,Column[{#1,#2},Alignment->Center]]&,simplifiedGroupedData],
PlotRange->{0,14},
PlotTheme->"Marketing",
Epilog->{Thick,Dashed,Red,Opacity[0.75],InfiniteLine[{{7,0},{7,2}}]},
ImageSize->Large,
FrameTicks->{Range[0,14],None},
FrameLabel->{"Approximate pH",None}
];
plot=plot/.list:{{Point[{l_,y_}]},{Point[{r_,y_}]},Line[{{l_,y_},{r_,y_}}]}:>Append[list,{(*Thin,Dashed,Line[{{r+0.5,y},{11,y}}],*)Text[Style[Keys[simplifiedGroupedData][[y,-1]],20],{11.25,y},{-1,0}]}]

New: Packaged Food Ingredients

Last year, we introduced packaging information for tens of thousands of foods.
Now we have data for over 100,000 packaged foods:

Warning Labels

EntityValue[{(Entity["Tropicana Trop50 Lemonade", Entity["Food","TropicanaTrop50Lemonade::372n5"], "Entity[\"Food\", \"TropicanaTrop50Lemonade::372n5\"]", "food"]),(Entity["Van de Kamp's Fillets Beer Battered", Entity["Food","VanDeKampsFilletsBeerBattered::rx25p"], "Entity[\"Food\", \"VanDeKampsFilletsBeerBattered::rx25p\"]", "food"]),(Entity["Coca-Cola Zero", Entity["Food","CocaColaZero::9627g"], "Entity[\"Food\", \"CocaColaZero::9627g\"]", "food"])},(EntityProperty["product warning", EntityProperty["Food","ProductWarning"], "EntityProperty[\"Food\", \"ProductWarning\"]"]),"EntityAssociation"];
Grid[List@@@Normal[%],Frame->All,Background->{1->LightGray}]

Ingredient lists

EntityValue[(Entity["Zoi Greek Yogurt Honey", Entity["Food","ZoiGreekYogurtHoney::34d68"], "Entity[\"Food\", \"ZoiGreekYogurtHoney::34d68\"]", "food"]),(EntityProperty["ingredient list", EntityProperty["Food","IngredientList"], "EntityProperty[\"Food\", \"IngredientList\"]"])]

EntityValue[(Entity["Nabisco Ritz Crackerfuls Garlic Herb Filled Crackers", Entity["Food","NabiscoRitzCrackerfulsGarlicHerbFilledCrackers::66rgv"], "Entity[\"Food\", \"NabiscoRitzCrackerfulsGarlicHerbFilledCrackers::66rgv\"]", "food"]),(EntityProperty["ingredient list", EntityProperty["Food","IngredientList"], "EntityProperty[\"Food\", \"IngredientList\"]"])]

New: Packaged Food Ingredients

Problem: Raw strings are not (easily) computable

Frequently all capital letters (displeasing to look at)

Hierarchical structure (nested sets, hard to get top-level ingredients)

Lookups not easily supported (allergens, dietary restrictions, etc...)

New: Packaged Food Ingredients

Solution: Ingredient Entities

We’ve processed the ingredient lists and created new entities for the ingredients used in packaged foods:

EntityValue["FoodIngredient","SampleEntities"]

EntityValue["FoodIngredient","EntityCount"]

With a simple property call, we can get a list of computable ingredient entities back:

EntityValue[(Entity["Van de Kamp's Fillets Beer Battered", Entity["Food","VanDeKampsFilletsBeerBattered::rx25p"], "Entity[\"Food\", \"VanDeKampsFilletsBeerBattered::rx25p\"]", "food"]),(EntityProperty["ingredients", EntityProperty["Food","Ingredients"], "EntityProperty[\"Food\", \"Ingredients\"]"])]

Compare with the same food’s raw text ingredient string:

EntityValue[(Entity["Van de Kamp's Fillets Beer Battered", Entity["Food","VanDeKampsFilletsBeerBattered::rx25p"], "Entity[\"Food\", \"VanDeKampsFilletsBeerBattered::rx25p\"]", "food"]),(EntityProperty["ingredient list", EntityProperty["Food","IngredientList"], "EntityProperty[\"Food\", \"IngredientList\"]"])]

New: Packaged Food Ingredients

Ingredient lookups

Now it’s easy to find foods with specific ingredients using implicit entity syntax:

EntityValue[,"EntityCount"]

Variants of the “Contains*” family of functions are supported:

EntityValue[,"Entities"]

Use ContainsNone to find foods without a specific ingredient:

EntityValue[,"EntityCount"]

New: Packaged Food Ingredients

Main ingredients

Ingredients listed between parentheses or after statements like “contains less than 2% of...” are not included in the top-level main ingredients:

EntityValue[(Entity["Van de Kamp's Fillets Beer Battered", Entity["Food","VanDeKampsFilletsBeerBattered::rx25p"], "Entity[\"Food\", \"VanDeKampsFilletsBeerBattered::rx25p\"]", "food"]),(EntityProperty["main ingredients", EntityProperty["Food","MainIngredients"], "EntityProperty[\"Food\", \"MainIngredients\"]"])]

First listed ingredient

The first listed ingredient is helpful, since ingredient lists are typically listed in descending order of predominance:

EntityValue[(Entity["Van de Kamp's Fillets Beer Battered", Entity["Food","VanDeKampsFilletsBeerBattered::rx25p"], "Entity[\"Food\", \"VanDeKampsFilletsBeerBattered::rx25p\"]", "food"]),(EntityProperty["first ingredient", EntityProperty["Food","FirstIngredient"], "EntityProperty[\"Food\", \"FirstIngredient\"]"])]

Ingredient counts

Some people prefer to avoid foods with large numbers of ingredients, so we have a property which allows that:

EntityValue[(Entity["Van de Kamp's Fillets Beer Battered", Entity["Food","VanDeKampsFilletsBeerBattered::rx25p"], "Entity[\"Food\", \"VanDeKampsFilletsBeerBattered::rx25p\"]", "food"]),(EntityProperty["ingredient count", EntityProperty["Food","IngredientCount"], "EntityProperty[\"Food\", \"IngredientCount\"]"])]

New: Dietary Restrictions

Solution: Dietary restriction entities

By having computational entities for dietary restrictions, dealing with various diets and allergies is much simpler:

EntityList["DietaryRestriction"]

Food types and ingredients to avoid

We have curated lists of food types and ingredients to avoid:

RandomSample[#,5]&/@EntityValue[(Entity["peanut free", Entity["DietaryRestriction","PeanutFree"], "Entity[\"DietaryRestriction\", \"PeanutFree\"]", "dietary restriction"]),{(EntityProperty["incompatible food types", EntityProperty["DietaryRestriction","IncompatibleFoodTypes"], "EntityProperty[\"DietaryRestriction\", \"IncompatibleFoodTypes\"]"]),(EntityProperty["incompatible food ingredients", EntityProperty["DietaryRestriction","IncompatibleFoodIngredients"], "EntityProperty[\"DietaryRestriction\", \"IncompatibleFoodIngredients\"]"])},"PropertyAssociation"]

New: Dietary Restrictions

Food type compatibility

We provide compatibility information for food types to give a rough idea of what is allowed, what is not, as well as “gray areas”:

Dataset[Take[#,4]&/@EntityValue[(Entity["gluten free", Entity["DietaryRestriction","GlutenFree"], "Entity[\"DietaryRestriction\", \"GlutenFree\"]", "dietary restriction"]),{(EntityProperty["compatible food types", EntityProperty["DietaryRestriction","CompatibleFoodTypes"], "EntityProperty[\"DietaryRestriction\", \"CompatibleFoodTypes\"]"]),(EntityProperty["questionably compatible food types", EntityProperty["DietaryRestriction","QuestionablyCompatibleFoodTypes"], "EntityProperty[\"DietaryRestriction\", \"QuestionablyCompatibleFoodTypes\"]"]),(EntityProperty["incompatible food types", EntityProperty["DietaryRestriction","IncompatibleFoodTypes"], "EntityProperty[\"DietaryRestriction\", \"IncompatibleFoodTypes\"]"])},"PropertyAssociation"]]

Dataset[Take[#,4]&/@EntityValue[(Entity["gluten free", Entity["DietaryRestriction","GlutenFree"], "Entity[\"DietaryRestriction\", \"GlutenFree\"]", "dietary restriction"]),{(EntityProperty["compatible food types", EntityProperty["DietaryRestriction","CompatibleFoodTypes"], "EntityProperty[\"DietaryRestriction\", \"CompatibleFoodTypes\"]"]),(EntityProperty["questionably compatible food types", EntityProperty["DietaryRestriction","QuestionablyCompatibleFoodTypes"], "EntityProperty[\"DietaryRestriction\", \"QuestionablyCompatibleFoodTypes\"]"]),(EntityProperty["incompatible food types", EntityProperty["DietaryRestriction","IncompatibleFoodTypes"], "EntityProperty[\"DietaryRestriction\", \"IncompatibleFoodTypes\"]"])},"PropertyAssociation"]]//Rasterize[#,ImageSize->1200]&

Food compatibility

Using the new ingredient entities, it was fairly easy to tag up thousands of foods with the same level of dietary restriction compatibility information:

EntityValue[,"EntityCount"]

EntityValue[,"EntityCount"]

New: Dietary Restrictions

Detailed descriptions

Frequently, people get confused about the differences between dietary restrictions, so we tried to make things clearer with a property for detailed descriptions:

(Entity["egg free", Entity["DietaryRestriction","EggFree"], "Entity[\"DietaryRestriction\", \"EggFree\"]", "dietary restriction"])["Description"]

Implied dietary restrictions

To further capture the differences, we have a property to show relations between dietary restrictions (e.g. “a vegan diet is also a vegetarian diet”):

EntityValue[{(Entity["gluten free", Entity["DietaryRestriction","GlutenFree"], "Entity[\"DietaryRestriction\", \"GlutenFree\"]", "dietary restriction"])},(EntityProperty["implied dietary restrictions", EntityProperty["DietaryRestriction","ImpliedDietaryRestrictions"], "EntityProperty[\"DietaryRestriction\", \"ImpliedDietaryRestrictions\"]"]),"EntityAssociation"]

EntityValue[{(Entity["vegan", Entity["DietaryRestriction","Vegan"], "Entity[\"DietaryRestriction\", \"Vegan\"]", "dietary restriction"])},(EntityProperty["implied dietary restrictions", EntityProperty["DietaryRestriction","ImpliedDietaryRestrictions"], "EntityProperty[\"DietaryRestriction\", \"ImpliedDietaryRestrictions\"]"]),"EntityAssociation"]

New: Possible Ingredient Substitutions

We have a growing database of ~2000 curated ingredient substitutions with explicit quantities:

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

New: Possible Ingredient Substitutions

More easily visualize substitutions with images:

Row[visualizeReplacements[#[(EntityProperty["possible ingredient substitutions", EntityProperty["FoodType","PossibleIngredientSubstitutions"], "EntityProperty[\"FoodType\", \"PossibleIngredientSubstitutions\"]"])]]&/@{(Entity["allspice", Entity["FoodType","Allspice"], "Entity[\"FoodType\", \"Allspice\"]", "food type"]),(Entity["avocado", Entity["FoodType","Avocado"], "Entity[\"FoodType\", \"Avocado\"]", "food type"])},Spacer[1]]

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->Round[0.75*ImageDimensions[First[foodTypeImages]]]],ent,ImageSize->All,Alignment->{Center,Bottom}],
ent
]
]

]
},
replace/@KeyMap[replace,substitutions]
];

visualizeEntityInstance[EntityInstance[ent_,q_Quantity]]:=Row[{q,"of",ent},Spacer[1]];
visualizeEntityGroup[EntityGroup[group_List]]:=Column[group/.ei_EntityInstance:>visualizeEntityInstance[ei],Frame->All,Alignment->Center,FrameStyle->Thick];

makeGridData[substitutions_Association]:=KeyValueMap[
{#1/.ei_EntityInstance:>visualizeEntityInstance[ei],Style["->",30],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,Frame->All]
];

Row[visualizeReplacements[#[(EntityProperty["possible ingredient substitutions", EntityProperty["FoodType","PossibleIngredientSubstitutions"], "EntityProperty[\"FoodType\", \"PossibleIngredientSubstitutions\"]"])]]&/@{(Entity["allspice", Entity["FoodType","Allspice"], "Entity[\"FoodType\", \"Allspice\"]", "food type"]),(Entity["avocado", Entity["FoodType","Avocado"], "Entity[\"FoodType\", \"Avocado\"]", "food type"])},Spacer[1]]

New: Possible Ingredient Substitution Ratios

Sometimes, you want substitutions in a more generic, “unit less” form when possible:

Row[visualizeReplacements[#[(EntityProperty["possible ingredient substitution ratios", EntityProperty["FoodType","PossibleIngredientSubstitutionRatios"], "EntityProperty[\"FoodType\", \"PossibleIngredientSubstitutionRatios\"]"])]]&/@{(Entity["allspice", Entity["FoodType","Allspice"], "Entity[\"FoodType\", \"Allspice\"]", "food type"]),(Entity["avocado", Entity["FoodType","Avocado"], "Entity[\"FoodType\", \"Avocado\"]", "food type"])},Spacer[1]]

New: Possible Ingredient Substitution Food Types

Sometimes you want to see which foods can be qualitatively replaced by other foods:

EntityValue[(Entity["açai berry", Entity["FoodType","AcaiBerry"], "Entity[\"FoodType\", \"AcaiBerry\"]", "food type"]),(EntityProperty["possible ingredient substitution food types", EntityProperty["FoodType","PossibleIngredientSubstitutionFoodTypes"], "EntityProperty[\"FoodType\", \"PossibleIngredientSubstitutionFoodTypes\"]"])]

EntityValue[(Entity["belgian endive", Entity["FoodType","BelgianEndive"], "Entity[\"FoodType\", \"BelgianEndive\"]", "food type"]),(EntityProperty["possible ingredient substitution food types", EntityProperty["FoodType","PossibleIngredientSubstitutionFoodTypes"], "EntityProperty[\"FoodType\", \"PossibleIngredientSubstitutionFoodTypes\"]"])]

This also allows reverse lookups (e.g. “I have this ingredient, which foods can be replaced by it?”):

EntityValue[,"Entities"]

EntityValue[,"Entities"]

Future goals

Coming soon: Updated Wolfram|Alpha scanner and API

GraphicsRow[{,},ImageSize->Full]

Future goals

Better food and nutrition coverage for the rest of the world (Next: Asia)

Add more packaged foods and handle more available data (storage temperatures/times, packaging dimensions/materials)

Align ingredient entities to chemical entities

Handle new FDA nutrition labels (support multiple sizes/styles)

Computational recipes (food & nutrition + actions + equipment + substitutions)

Summary

Brief overview of food in the Wolfram Language

Data and features available

Some applications

Improvements

Common inside/outside colors

Barcode support

CompassPlot redesign

LanguaL international food thesaurus alignment

New Wolfram Language food data

PLU codes

pH properties

Packaged food ingredients

Dietary restrictions

Ingredient substitutions

Future goals

Summary