You are on page 1of 16

ABHINAV ARORA (08) ANKIT KARNA (17)

1714110101 1714110111

PRACTICAL ASSIGNMENT-10
MINI PROJECT
NUTRITION CALCULATOR - CALCULATE NUTRITION
FOR RECIPES

By: - Abhinav Arora (Roll no- 08)


Ankit Karna (Roll no- 17)
Aim: -To develop a mini project in R using shiny libraries.
Title: -
NUTRITION CALCULATOR - CALCULATE NUTRITION FOR RECIPES
Theory:-
Nutrient Calculator is a dashboard where users can easily search and add multiple
ingredients from the CNF database, calculate overall nutrient data such as calories and
sodium, and see nutrient amounts as percentage recommended daily values. Total calorie
count, nutrients amounts which surpass 100% and 50% daily value are highlighted in at
the top. Macronutrients, minerals and vitamins as % daily value are visualized on
separated bar graphs.
When it comes to understanding food, nutrition is one of the most commonly discussed
topics. What foods are good for me? What should I eat to live a long and healthy life?
Therefore, I tend to stay clear from ‘what’s good for you discussions’ and ‘what’s
healthy for you’. That said, I do like understanding my food and its analysis. he energy
content can be determined using a simple calculation.
We know which groups of molecules contribute to the energy content of a food. We also
know how much energy each of these types of molecules contain and will give to your
body.

It has been defined by analysis how much energy one gram of these different groups of
molecules will give to your body (the regulation mentioned above also contains this
information). Calculating energy content is then done as follows:

1. Determine how much of each component is in the food (we’ll come back to
that later)
2. Multiply this value with the energy content for each specific component.
3. Count up all these numbers and voila, you have the energy content of your
food! Let’s do an example here:
This calculator was developed to use food groups to meet your nutritional needs.
However, you can easily use this tool to count grams of protein, fat, or
carbohydrates.
Library used in this project:-
 library(shiny)
The Shiny package comes with eleven built-in examples that demonstrate how Shiny
works. This article reviews the first three examples, which demonstrate the basic
structure of a Shiny app.
Shiny applications have two components, a user interface object and a server function,
that are passed as arguments to the shinyApp function that creates a Shiny app object
from this UI/server pair. The source code for both of these components is listed below.
In subsequent sections of the article we’ll break down Shiny code in detail and explain
the use of “reactive” expressions for generating output.

ui <- fluidPage(

# App title ----


titlePanel("Hello Shiny!"),

# Sidebar layout with input and output definitions ----

sidebarLayout(

# Sidebar panel for inputs ----


sidebarPanel(
ABHINAV ARORA (08) ANKIT KARNA (17)
1714110101 1714110111

# Input: Slider for the number of bins ----


sliderInput(inputId = "bins",
label = "Number of bins:",
min = 1,
max = 50,
value = 30)
),
# Main panel for displaying outputs ----
mainPanel(

# Output: Histogram ----


plotOutput(outputId = "distPlot")
)
)
)

 library(dplyr)
To explore the basic data manipulation verbs of dplyr, we’ll use the dataset starwars.
This dataset contains 87 characters and comes from the Star Wars API, and is
documented in ?
starwars dim(starwars) #> [1] 87 14
starwars
#> # A tibble: 87 x 14
#>name height mass hair_color skin_color eye_color birth_year sexgender

#><chr> <int> <dbl> <chr> <chr><chr> <dbl> <chr> <chr>


#> 1 Luke…172 77 blond fairblue 19male mascu…
#> 2 C-3PO167 75 <NA> gold yellow 112none mascu…
#> 3 R2-D296 32 <NA> white, bl… red 33none mascu…
#> 4 Dart…202 136 none white yellow 41.9 male mascu…
83 more rows, and 5 more variables: homeworld <chr>, species <chr>, #> #films <list>, vehicles <list>, starsh
Single table verbs
dplyr aims to provide a function for each basic verb of data manipulation. These verbs
can be organised into three categories based on the component of the dataset that they
work with:

o Rows:
o filter() chooses rows based on column values.
o slice() chooses rows based on location.
o arrange() changes the order of the rows.
o Columns:
o select() changes whether or not a column is included.
o rename() changes the name of columns.
o mutate() changes the values of columns and creates new columns.
o relocate() changes the order of the columns.
o Groups of rows:
o summarise() collapses a group into a single row.

The pipe
All of the dplyr functions take a data frame (or tibble) as the first argument. Rather than
forcing the user to either save intermediate objects or nest functions, dplyr provides
the %>% operator from magrittr. x %>% f(y) turns into f(x, y) so the result from one
step is then “piped” into the next step. You can use the pipe to rewrite multiple
operations that you can read left-to-right, top-to-bottom (reading the pipe operator as
“then”).
Patterns of operations
The dplyr verbs can be classified by the type of operations they accomplish (we
sometimes speak of their semantics, i.e., their meaning). It’s helpful to have a good
grasp of the difference between select and mutate operations.
Selecting operations
One of the appealing features of dplyr is that you can refer to columns from the tibble as
if they were regular variables. However, the syntactic uniformity of referring to bare

column names hides semantical differences across the verbs. A column symbol supplied
to select() does not have the same meaning as the same symbol supplied to mutate().
ABHINAV ARORA (08) ANKIT KARNA (17)
1714110101 1714110111

Mutating operations
Mutate semantics are quite different from selection semantics. Whereas select() expects
column names or positions, mutate() expects column vectors. We will set up a smaller
tibble to use for our examples.
df <- starwars %>% select(name, height, mass)
When we use select(), the bare column names stand for their own positions in the tibble.
For mutate() on the other hand, column symbols represent the actual column vectors
stored in the tibble.
 library(DT)
DataTables is used ubiquitously to display tabular data interactively within webpages.
DataTables allows entire tables or individual columns to be filtered. DataTables
provides a number of extensions for adding additional features, including responsivenes
Data manipulation operations such as subset, group, update, join etc., are all inherently
related. Keeping these related operations together allows for:
o concise and consistent syntax irrespective of the set of operations you would like
to perform to achieve your end goal.
o performing analysis fluidly without the cognitive burden of having to map each
operation to a particular function from a potentially huge set of functions available
before performing the analysis.
o automatically optimising operations internally, and very effectively, by knowing
precisely the data required for each operation, leading to very fast and memory efficient
code.
Briefly, if you are interested in reducing programming and compute time tremendously,
then this package is for you. The philosophy that data.table adheres to makes this
possible. Our goal is to illustrate it through this series of vignettes.
data.table is an R package that provides an enhanced version of data.frames, which are
the standard data structure for storing data in base R. In the Data section above, we
already created a data.table using fread(). We can also create one using
the data.table() function. Here is an example:

DT = data.table(
ID = c("b","b","b","a","a","c"), a = 1:6,
b = 7:12,

c = 13:18
) DT
#ID a b c # 1: b 1 7 13
# 2: b 2 8 14
# 3: b 3 9 15
# 4: a 4 10 16
# 5: a 5 11 17
# 6: c 6 12 18

class(DT$ID)
# [1] "character"
 library(ggplot2)
ggplot2 is a plotting package that makes it simple to create complex plots from data in a
data frame. It provides a more programmatic interface for specifying what variables to
plot, how they are displayed, and general visual properties. Therefore, we only need
minimal changes if the underlying data change or if we decide to change from a bar plot
to a scatterplot. This helps in creating publication quality plots with minimal amounts of
adjustments and tweaking.
ggplot2 functions like data in the 'long' format, i.e., a column for every dimension, and a
row for every observation. Well-structured data will save you lots of time when making
figures with ggplot2
ggplot graphics are built step by step by adding new elements. Adding layers in this
fashion allows for extensive flexibility and customization of plots.
To build a ggplot, we will use the following basic template that can be used for different
types of plots:

ggplot(data = <DATA>, mapping = aes(<MAPPINGS>)) + <GEOM_FUNCTION>()

 use the ggplot() function and bind the plot to a specific data frame using
the data argument

ggplot(data = surveys_complete)
ggplot(data = surveys_complete, mapping = aes(x = weight, y = hindfoot_length))
 add 'geoms' – graphical representations of the data in the plot (points, lines,
bars). ggplot2 offers many different geoms; we will use some common ones today,
including:
 geom_point() for scatter plots, dot plots, etc.
 geom_boxplot() for, well, boxplots!
 geom_line() for trend lines, time series, etc.
To add a geom to the plot use + operator. Because we have two continuous variables,
let's use geom_point() first:

ggplot(data = surveys_complete, aes(x = weight, y = hindfoot_length)) +


ABHINAV ARORA (08) ANKIT KARNA (17)
1714110101 1714110111

geom_point()

 library(shinydashboard)
At this point comes into the light the most simple and open source way of creating
dashboards, i.e. RShiny dashboards.
You can create amazing interactive dashboards using any sort of data imported or created
using R programming. The most important thing about Shiny dashboards are that they are
simple to create with reusing the templates and moulding the designs by tweaking the
codes.

A dashboard has three parts: a header, a sidebar, and a body.


library(shiny)
library(shinydashboard)
ui <-
dashboardPage( dashbo
ardHeader(),
dashboardSidebar(),
dashboardBody()
)
server <- function(input, output) { }
shinyApp(ui, server)

You can also create two different files such as ui.R and app.R and then calling through R
console by using shinyApp() function.

Sidebar

Here comes a very interesting part of the dashboard UI where you can create different
styles of widgets for taking in the inputs or filtering the data.

Radio button Input Widget —

This widget maps each value with an operation in the main body or filtering out the data
with help of functions defined in server app.
Note: The interactive part of dashboard that changes on based of these inputs will be
explained in the subsequent
articles. sidebar <-
dashboardSidebar( sidebarMenu(
sidebarSearchForm(textId = "searchText",buttonId = "searchButton",
label = "Search..."),
menuItem("List of Data Classification", tabName = "list", icon = icon("list")),
radioButtons("rtype","Choose Categories :",
choiceNames = c('By Sources', 'By Data Types','By Modeling', 'By Processing',
'Data at Rest vs Data in Motion'),
choiceValues = c(1,2,3,4,5))

 library(plotly)
Plotly is a technical computing company headquartered in Montreal, Quebec, that
develops online data analytics and visualization tools. Plotly provides online graphing,
analytics, and statistics tools for individuals and collaboration, as well as scientific
graphing libraries for Python, R, MATLAB, Perl, Julia, Arduino, and REST.

Python Plotly Library

Plotly’s Python graphing library makes interactive graphs online and allows us to save
them offline if need be.

Why Plotly

Plotly has got some amazing features that make it better than other graphing libraries:

Using Plotly

To use plotly in any of the Python scripts, we will need to import plotly as: import plotly

A few more steps and you are ready to use plotly. For Online usage, you need to set up
credentials. This can be done as:

plotly.tools.set_credentials_file(username='YourUsernameHere',
api_key='YourAPIkeyHere')

For offline usage, we need to call plot like the following for offline usage:

plotly.offline.plot()
ABHINAV ARORA (08) ANKIT KARNA (17)
1714110101 1714110111

Code :-

library(shiny)
library(dplyr)
library(DT)
library(ggplot2)
library(shinydashboard)
library(plotly)

# load files from Canada Nutrient File

nutr_files <- list.files(pattern = "*.rda")


lapply(nutr_files,load,.GlobalEnv)
# format quantities for ingredients

# take everything before parenthesis


ca_measure_name$units <- regmatches(ca_measure_name$MeasureDescription, regexpr("^([^(]+)",
ca_measure_name$MeasureDescription, perl = T))
# only take what is in parenthesis
ca_measure_name$description <- gsub("^([^(]+)", "", ca_measure_name$MeasureDescription, perl =
T)
# extract numeric values
r <- regexpr("^[[:digit:]]+[\\/\\.][[:digit:]]", ca_measure_name$units)
out <- rep(NA,nrow(ca_measure_name))
out[r!=-1] <- regmatches(ca_measure_name$units, r)
ca_measure_name$numeric <- out
# convert fractions to decimal
fractions <- grep("\\/", ca_measure_name$numeric)
ca_measure_name$numeric[fractions] <- sapply(ca_measure_name$numeric[fractions], function(x)
eval(parse(text=x)))
# fill in blank numeric values
ca_measure_name$numeric[is.na(ca_measure_name$numeric)] <- 1
# everything numberic
ca_measure_name$numeric <- round(as.numeric(ca_measure_name$numeric), 5)
# now remove numbers from units
ca_measure_name$units <- gsub("^[[:digit:]]+[\\/\\.][[:digit:]]", "", ca_measure_name$units)

# format ingredient choices


ca_food_choices <- ca_food_name$FoodID
names(ca_food_choices) <- ca_food_name$FoodDescription

# format daily values

daily_value <- read.table("daily_values.txt", sep = "\t", header=T, stringsAsFactors = F)

ui <- dashboardPage(
dashboardHeader(title = "Nutrition Calculator"),
dashboardSidebar(
selectizeInput(
'food_id', '1. Ingredient', choices = ca_food_choices,
options = list(
placeholder = 'Type to search for ingredient',
onInitialize = I('function() { this.setValue(""); }')
)
),
conditionalPanel('input.food_id != ""',
selectizeInput('measure_unit', '2. Measure Unit', choices = c("Select an ingredient" = "")),
numericInput('quantity', '3. Quantity', value = 1, min = 0, step = 1)),
actionButton("add", "Add ingredient"),
actionButton("remove", "Remove ingredient"),
numericInput("serving", "Number of servings contained", min = 0.01, step = 1, value = 1),
tags$p("Note: All nutrient information is based on the Canadian Nutrient File. Nutrient amounts do
not account for variation in nutrient retention and yield losses of ingredients during preparation. %
daily values (DV) are taken from the Table of Daily Values from the Government of Canada. This data
should not be used for nutritional labeling.")
),
dashboardBody(
fluidRow(
valueBoxOutput("calories"),
valueBoxOutput("over_nutrient"),
valueBoxOutput("rich_nutrient")
),
fluidRow(
box(title = "Ingredients",
solidHeader = T,
width = 4,
collapsible = T,
div(DT::DTOutput("ing_df"), style = "font-size: 70%;")),
box(title = "Macronutrients", solidHeader = T,
width = 8, collapsible = T,
plotlyOutput("macro_plot"))

), # row
fluidRow(
box(title = "Nutrition Table",
solidHeader = T,
width = 4,
collapsible = T,
collapsed = F,
tags$p(textOutput("serving", inline = T)),
div(DT::DTOutput("nutrient_table"), style = "font-size: 70%;")),
box(title = "Minerals", solidHeader = T,
width = 8, collapsible = T,
plotlyOutput("mineral_plot"))
),# row
fluidRow(
box(title = "Vitamins", solidHeader=T,
width = 12, collapsible = T,
plotlyOutput("vitamin_plot"))
) # row
) # body
)
ABHINAV ARORA (08) ANKIT KARNA (17)
1714110101 1714110111

# Define server logic required to draw a histogram


server <- function(input, output, session) {
# make reactive to store ingredients
ing_df <- shiny::reactiveValues()
ing_df$df <- data.frame("quantity" = numeric(),
"units" = character(),
"ingredient_name" = character(),
"FoodID" = numeric(),
stringsAsFactors = F)
ing_df$measure <- data.frame("numeric" = numeric(),
"units" = character(),
"description" = character(),
"ConversionFactorValue" = numeric(),
"MeasureID" = numeric(),
"FoodID" = numeric(),
stringsAsFactors = F)
# step 1 get singular ingredient
measure_df <- eventReactive(input$food_id,{
measure_df <- ca_food_name[ca_food_name$FoodID==input$food_id, "FoodID"] %>%
left_join(ca_conversion_factor) %>%
left_join(ca_measure_name) %>%
select(numeric, units, description, ConversionFactorValue, MeasureID, FoodID)
# measure_df <- rbind(measure_df, c(numeric = 100, units = "g", description = "",
ConversionFactorValue = 1, MeasureID = ""))
measure_df
})
# step 2 update the measure unit for singular ingredient
observe({
units <- unique(paste(measure_df()$units, measure_df()$description))
updateSelectInput(session, "measure_unit", "2. Measure Unit", choices = units)
})
# step 3 update the ingredient dataframe
observeEvent(input$remove, {
isolate(ing_df$df<-ing_df$df[-(nrow(ing_df$df)),])
isolate(ing_df$measure <- ing_df$measure[-nrow(ing_df$measure),])
})
observeEvent(input$add, {
isolate(ing_df$df[nrow(ing_df$df) + 1,] <- c(input$quantity,
input$measure_unit,
names(ca_food_choices[ca_food_choices == input$food_id]),
as.numeric(input$food_id)))
# get actual working ingredient dataframe for dplyr
input_measure <- measure_df()
input_measure <- input_measure[paste(measure_df()$units, measure_df()$description) ==
input$measure_unit, ]
if(nrow(input_measure) > 1){
input_measure <-
input_measure[which(abs(input_measure$numeric-
input$quantity)==min(abs(input_measure$numeric-input$quantity))),]
}
isolate(ing_df$measure[nrow(ing_df$measure) + 1, ] <- input_measure)
# update choices
updateNumericInput(session, 'quantity', '3. Quantity', 1)
updateSelectizeInput(session, 'measure_unit', '2. Measure Unit')
updateSelectInput(session, 'food_id', '1. Ingredient', choices = ca_food_choices)
})
# main nutrition data frame
nutrition_df <- reactive({
measure_food_df <- ing_df$measure
ing_quant <- ing_df$df
measure_food_df$quantity <- ing_quant$quantity
measure_food_df <- measure_food_df %>%
left_join(ca_nutrient_amount) %>%
left_join(ca_nutrient_name) %>%
# filter(NutrientID %in% select_nutrients) %>%
mutate(NutrientName = tolower(NutrientName)) %>%
mutate(NutrientValue = as.numeric(NutrientValue) * as.numeric(ConversionFactorValue)
* as.numeric(quantity) / as.numeric(numeric) / input$serving) %>%
select(NutrientName, NutrientValue, NutrientID, NutrientUnit, ConversionFactorValue, quantity,
FoodID) %>%
group_by(NutrientName) %>%
summarize(Value = round(sum(NutrientValue, na.rm = T),2),
Unit = first(NutrientUnit),
NutrientID = first(NutrientID))
measure_food_df
})
# display nutrients necessary for label
nutrient_table <- reactive({
select_nutrients <- c(208, 204, 606, 605, 601, 307, 205, 291, 269, 203, 814, 401, 301, 303)
measure_food_df <- nutrition_df() %>% filter(NutrientID %in% select_nutrients)
measure_food_df <- measure_food_df[order(match(measure_food_df$NutrientID,
select_nutrients)),] %>%
select(NutrientName, Value, Unit)
measure_food_df
}) # df with dv%
dv_df <- reactive({
dv_df <- daily_value %>% left_join(nutrition_df())
# hack for total sat fats and trans fats
dv_df$Value[2] <- sum(nutrition_df()$Value[nutrition_df()$NutrientID %in% c(605, 606)], na.rm =
T)
dv_df$Unit[2] <- "g"
dv_df$pct_dv <- round(dv_df$Value / dv_df$DV, 3) * 100
dv_df
})
output$macro_plot <- renderPlotly({
df_macro <- dv_df() %>% filter(Group == "macronutrients")
plot_macro <- ggplot(df_macro) +
geom_col(aes(x = Nutrient, y = pct_dv, fill = pct_dv)) +
labs(x = "Nutrient", y = "% Daily Value") +
theme_gray() + ylim(0, NA) + geom_hline(yintercept = 100) + scale_fill_gradient(low
= "green",
high = "red",
limits = c(0, 100),
na.value = "darkred",
name = "% Daily Value") +
ABHINAV ARORA (08) ANKIT KARNA (17)
1714110101 1714110111

theme(panel.background = element_rect(fill = "mintcream"),


legend.position = "none") +
scale_x_discrete(labels = c("Cholesterol", "Fat", "Fibre", "Sodium", "Sugars", "Saturated and \n
Trans Fats"))
ggplotly(plot_macro)
})
output$mineral_plot <- renderPlotly({
df_min <- dv_df() %>% filter(Group == "mineral")
plot_min <- ggplot(df_min) +
geom_col(aes(x = Nutrient, y = pct_dv, fill = pct_dv)) +
labs(x = "Nutrient", y = "% Daily Value") +
theme_gray() +
ylim(0, NA) +
geom_hline(yintercept = 100) +
scale_fill_gradient(low = "red",
high = "green",
limits = c(0, 100),
na.value = "khaki1",
name = "% Daily Value") +
theme(
legend.position = "none",
panel.background = element_rect(fill = "lightyellow"))
ggplotly(plot_min)
})
output$vitamin_plot <- renderPlotly({
df_vit <- dv_df() %>% filter(Group == "vitamin")
req(input$quantity)
plot_vit <- ggplot(df_vit) +
geom_col(aes(x = Nutrient, y = pct_dv, fill = pct_dv)) +
geom_hline(yintercept = 100) +
labs(x = "Nutrient", y = "% Daily Value") +
theme_gray() +
ylim(0, NA) +
scale_fill_gradient(low = "red",
high = "green",
limits = c(0, 100),
na.value = "khaki1") +
theme(legend.position = "none",
panel.background = element_rect(fill = "aliceblue"),
axis.text.x = element_text(angle = 45, vjust = 1, hjust=1))
ggplotly(plot_vit)
})
# dt indicator
output$ing_df <- DT::renderDataTable(ing_df$df[,1:3],
# colnames = c("Quantity", "Units", "Ingredient"),
rownames=F, options = list(pageLength = 5))
output$nutrient_table <- DT::renderDataTable(nutrient_table())
# value boxes
output$calories <- renderValueBox({
valueBox(paste0(nutrition_df()$Value[nutrition_df()$NutrientID == 208], "kcal"),
"Calories", icon = icon("fire"), color = "yellow")
})
output$over_nutrient <- renderValueBox({
nutrition_df <- dv_df() %>%
# filter(NutrientID %in% c(601, 204, 307, 269, 0)) %>%
tidyr::drop_na(pct_dv) %>% filter(pct_dv > 100)
if(nrow(nutrition_df) > 0){
valueBox("Over Daily Value", HTML(paste0(nutrition_df$Nutrient, sep="<br>")), icon
= icon("exclamation-triangle"), color = "red")
} else {
if(nrow(nutrition_df) > 0){
valueBox("High levels* of ", HTML(paste0(c(nutrition_df$Nutrient,"*above 50%
recommended DV"), sep="<br>")), icon = icon("exclamation-triangle"), color = "green")
} else {
valueBox(HTML("All nutrients"), "below 50% recommended DV", icon =
icon("exclamation- triangle"), color = "orange")
}
})
output$serving <- renderText(paste("for 1 serving (", input$serving, "servings in recipe)"))
}
# Run the application
shinyApp(ui = ui, server =
server)
ABHINAV ARORA (08) ANKIT KARNA (17)
1714110101 1714110111

Output:-

Application In Viewer:-

You might also like