|
|
|
#+options: ':nil *:t -:t ::t <:t H:3 \n:nil ^:t arch:headline author:t
|
|
|
|
#+options: broken-links:nil c:nil creator:nil d:(not "LOGBOOK") date:t e:t
|
|
|
|
#+options: email:nil f:t inline:t num:t p:nil pri:nil prop:nil stat:t tags:t
|
|
|
|
#+options: tasks:t tex:t timestamp:t title:t toc:t todo:t |:t
|
|
|
|
#+title: Meal Planner
|
|
|
|
#+date: \today
|
|
|
|
#+author: Craig Oates
|
|
|
|
#+email: craig@craigoates.net
|
|
|
|
#+language: en
|
|
|
|
#+select_tags: export
|
|
|
|
#+exclude_tags: noexport
|
|
|
|
#+creator: Emacs 29.1.90 (Org mode 9.6.10)
|
|
|
|
#+cite_export:
|
|
|
|
|
|
|
|
* Setup Common Lisp Environment
|
|
|
|
|
|
|
|
I’ve copied the following code block over from other files. Run it if this is
|
|
|
|
your first file open in the session.
|
|
|
|
|
|
|
|
#+begin_src lisp :session :results silent
|
|
|
|
(ql:quickload :com.inuoe.jzon) ; JSON parser.
|
|
|
|
(ql:quickload :dexador) ; HTTP requests.
|
|
|
|
(ql:quickload :plump) ; HTML/XML parser.
|
|
|
|
(ql:quickload :lquery) ; HTML/DOM manipulation.
|
|
|
|
(ql:quickload :lparallel) ; Parallel programming.
|
|
|
|
(ql:quickload :cl-ppcre) ; RegEx. library.
|
|
|
|
(ql:quickload :plot/vega) ; Vega plotting library.
|
|
|
|
(ql:quickload :lisp-stat) ; Stat's library.
|
|
|
|
(ql:quickload :data-frame) ; Data frame library eqv. to Python's Numpy.
|
|
|
|
(ql:quickload :str) ; String library, expands on 'string' library.
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
* Seven Day Meal Planner (AI Generated)
|
|
|
|
|
|
|
|
The plan below was formed using [[https://www.bing.com/][Bing Copilot]], and copied verbatim. I've decided
|
|
|
|
to go this route because I don't know enough about nutrition and I don't really
|
|
|
|
want to spend the time looking into the various websites/resources and what they
|
|
|
|
recommend. I did give Copilot my height and weight when it built out this
|
|
|
|
plan. I don't know if that changes things too much. The thing I'm most concerned
|
|
|
|
with it how much it'll cost.
|
|
|
|
|
|
|
|
:drawer:
|
|
|
|
#+begin_quote
|
|
|
|
Day 1:
|
|
|
|
|
|
|
|
Breakfast: Scrambled eggs with smoked salmon and a slice of whole grain toast.
|
|
|
|
Lunch: Grilled chicken salad with lots of mixed vegetables.
|
|
|
|
Dinner: Steak with quinoa and steamed broccoli.
|
|
|
|
Snacks: Greek yogurt, a handful of almonds.
|
|
|
|
Day 2:
|
|
|
|
|
|
|
|
Breakfast: Protein smoothie with banana, spinach, and a scoop of protein powder.
|
|
|
|
Lunch: Tuna salad with a side of whole grain crackers.
|
|
|
|
Dinner: Baked salmon with sweet potato and asparagus.
|
|
|
|
Snacks: Cottage cheese, a piece of fruit.
|
|
|
|
Day 3:
|
|
|
|
|
|
|
|
Breakfast: Oatmeal with a scoop of protein powder and a handful of berries.
|
|
|
|
Lunch: Turkey wrap with whole grain tortilla and lots of veggies.
|
|
|
|
Dinner: Grilled shrimp with brown rice and green beans.
|
|
|
|
Snacks: Hard-boiled eggs, a handful of walnuts.
|
|
|
|
Day 4:
|
|
|
|
|
|
|
|
Breakfast: Greek yogurt with granola and a handful of berries.
|
|
|
|
Lunch: Chicken stir-fry with lots of mixed vegetables.
|
|
|
|
Dinner: Baked cod with quinoa and steamed zucchini.
|
|
|
|
Snacks: Protein shake, a piece of fruit.
|
|
|
|
Day 5:
|
|
|
|
|
|
|
|
Breakfast: Scrambled eggs with turkey bacon and a slice of whole grain toast.
|
|
|
|
Lunch: Quinoa salad with grilled chicken and lots of mixed vegetables.
|
|
|
|
Dinner: Steak with sweet potato and steamed Brussels sprouts.
|
|
|
|
Snacks: Greek yogurt, a handful of almonds.
|
|
|
|
Day 6:
|
|
|
|
|
|
|
|
Breakfast: Protein smoothie with banana, spinach, and a scoop of protein powder.
|
|
|
|
Lunch: Tuna salad with a side of whole grain crackers.
|
|
|
|
Dinner: Baked salmon with brown rice and asparagus.
|
|
|
|
Snacks: Cottage cheese, a piece of fruit.
|
|
|
|
Day 7:
|
|
|
|
|
|
|
|
Breakfast: Oatmeal with a scoop of protein powder and a handful of berries.
|
|
|
|
Lunch: Turkey wrap with whole grain tortilla and lots of veggies.
|
|
|
|
Dinner: Grilled shrimp with quinoa and green beans.
|
|
|
|
Snacks: Hard-boiled eggs, a handful of walnuts.
|
|
|
|
#+end_quote
|
|
|
|
:END:
|
|
|
|
|
|
|
|
* Breakdown of Meal Planner
|
|
|
|
|
|
|
|
Below is a list of each item in the meal planner.
|
|
|
|
|
|
|
|
#+begin_src shell :results silent
|
|
|
|
DATA="Eggs
|
|
|
|
Salmon
|
|
|
|
Whole Grain Toast
|
|
|
|
Chicken
|
|
|
|
Vegetables
|
|
|
|
Steak
|
|
|
|
Quinoa
|
|
|
|
Broccoli
|
|
|
|
Greek Yogurt
|
|
|
|
Almonds
|
|
|
|
Banana Protein Smoothie
|
|
|
|
Spinach
|
|
|
|
Scoop Protein Powder
|
|
|
|
Tuna
|
|
|
|
Salad
|
|
|
|
Whole Grain Crackers
|
|
|
|
Salmon
|
|
|
|
Sweet Potato
|
|
|
|
Asparagus
|
|
|
|
Cottage Cheese
|
|
|
|
Fruit
|
|
|
|
Oatmeal
|
|
|
|
Protein Powder
|
|
|
|
Berries
|
|
|
|
Turkey
|
|
|
|
Whole Grain Tortilla
|
|
|
|
Vegetables
|
|
|
|
Prawns
|
|
|
|
Brown Rice
|
|
|
|
Green Beans
|
|
|
|
Eggs
|
|
|
|
Walnuts
|
|
|
|
Greek Yogurt
|
|
|
|
Granola
|
|
|
|
Berries
|
|
|
|
Chicken
|
|
|
|
Vegetables
|
|
|
|
Cod
|
|
|
|
Quinoa
|
|
|
|
Courgette
|
|
|
|
Protein Shake
|
|
|
|
Fruit
|
|
|
|
Eggs
|
|
|
|
Turkey
|
|
|
|
Bacon
|
|
|
|
Whole Grain Toast
|
|
|
|
Quinoa
|
|
|
|
Salad
|
|
|
|
Chicken
|
|
|
|
Vegetables
|
|
|
|
Steak
|
|
|
|
Sweet Potato
|
|
|
|
Brussels Sprouts
|
|
|
|
Greek Yogurt
|
|
|
|
Almonds
|
|
|
|
Protein Smoothie
|
|
|
|
Banana
|
|
|
|
Spinach
|
|
|
|
Protein Powder
|
|
|
|
Tuna
|
|
|
|
Salad
|
|
|
|
Whole Grain Crackers
|
|
|
|
Salmon
|
|
|
|
Brown Rice
|
|
|
|
Asparagus
|
|
|
|
Cottage Cheese
|
|
|
|
Fruit
|
|
|
|
Oatmeal
|
|
|
|
Protein Powder
|
|
|
|
Berries
|
|
|
|
Turkey
|
|
|
|
Whole Grain Tortilla
|
|
|
|
Vegetables
|
|
|
|
Prawns
|
|
|
|
Quinoa
|
|
|
|
Green Beans
|
|
|
|
Eggs
|
|
|
|
Walnuts"
|
|
|
|
echo "$DATA" > working-data/meal-planner-ingredients.txt
|
|
|
|
sort working-data/meal-planner-ingredients.txt \
|
|
|
|
| uniq -c > working-data/meal-planner-servings.txt
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
Having written that out to a file, I can see have many times each item was
|
|
|
|
listed. /Note/, this quantity value represents the number of serving in a given
|
|
|
|
week. It doesn't specify the quantity of the serving for each item. For example,
|
|
|
|
~1 Bacon~ doesn't mean /one strip of bacon/, it means /one serving/ of bacon in the
|
|
|
|
week.
|
|
|
|
|
|
|
|
#+begin_src shell :results output
|
|
|
|
head working-data/meal-planner-servings.txt
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
#+RESULTS:
|
|
|
|
#+begin_example
|
|
|
|
2 Almonds
|
|
|
|
2 Asparagus
|
|
|
|
1 Bacon
|
|
|
|
1 Banana
|
|
|
|
1 Banana Protein Smoothie
|
|
|
|
3 Berries
|
|
|
|
1 Broccoli
|
|
|
|
2 Brown Rice
|
|
|
|
1 Brussels Sprouts
|
|
|
|
3 Chicken
|
|
|
|
#+end_example
|
|
|
|
|
|
|
|
#+begin_src shell :results output raw
|
|
|
|
echo "SERVING,INGREDIENT" > working-data/meal-planner-servings.csv
|
|
|
|
while IFS= read -r line
|
|
|
|
do
|
|
|
|
csv_line=$(echo "$line" | awk '{$1=$1; print $1 "," substr($0, index($0,$2))}')
|
|
|
|
echo "$csv_line"
|
|
|
|
done < working-data/meal-planner-servings.txt >> working-data/meal-planner-servings.csv
|
|
|
|
echo "[[file:./working-data/meal-planner-servings.csv]]"
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
#+RESULTS:
|
|
|
|
[[file:./working-data/meal-planner-servings.csv]]
|
|
|
|
|
|
|
|
* Manually Adjust Serving Quantities
|
|
|
|
|
|
|
|
The original version of this file has /semantically duplicated/ data in it, which
|
|
|
|
the code isn't really great at detecting. So, I've made minor adjustments, like
|
|
|
|
bundling up the ’Protein’ entries into one. I, also, replace ’Whole Grain’ with
|
|
|
|
’Wholemeal’ because I don't think I've ever seen anything labelled as ’Whole
|
|
|
|
Grain’ in the UK, making it harder to search for these types of items on the
|
|
|
|
various shopping websites.
|
|
|
|
|
|
|
|
#+NAME: servings-adjusted
|
|
|
|
| INGREDIENT | SERVING |
|
|
|
|
|-------------------------+---------|
|
|
|
|
| Almonds | 2 |
|
|
|
|
| Asparagus | 2 |
|
|
|
|
| Bacon | 1 |
|
|
|
|
| Banana | 1 |
|
|
|
|
| Banana Protein Smoothie | 1 |
|
|
|
|
| Berries | 3 |
|
|
|
|
| Broccoli | 1 |
|
|
|
|
| Brown Rice | 2 |
|
|
|
|
| Brussels Sprouts | 1 |
|
|
|
|
| Chicken | 3 |
|
|
|
|
| Cod | 1 |
|
|
|
|
| Cottage Cheese | 2 |
|
|
|
|
| Courgette | 1 |
|
|
|
|
| Eggs | 4 |
|
|
|
|
| Fruit | 3 |
|
|
|
|
| Granola | 1 |
|
|
|
|
| Greek Yogurt | 3 |
|
|
|
|
| Green Beans | 2 |
|
|
|
|
| Porridge | 2 |
|
|
|
|
| Prawns | 2 |
|
|
|
|
| Protein Powder | 6 |
|
|
|
|
| Quinoa | 4 |
|
|
|
|
| Salad | 3 |
|
|
|
|
| Salmon | 3 |
|
|
|
|
| Spinach | 2 |
|
|
|
|
| Steak | 2 |
|
|
|
|
| Sweet Potato | 2 |
|
|
|
|
| Tuna | 2 |
|
|
|
|
| Turkey | 3 |
|
|
|
|
| Vegetables | 5 |
|
|
|
|
| Walnuts | 2 |
|
|
|
|
| Wholemeal Crackers | 2 |
|
|
|
|
| Wholemeal Bread | 2 |
|
|
|
|
| Wholemeal Tortilla | 2 |
|
|
|
|
|
|
|
|
#+begin_src lisp :var table=servings-adjusted :results output raw
|
|
|
|
(let ((filepath #P"working-data/meal-planner-servings-adjusted.csv"))
|
|
|
|
(with-open-file (stream filepath :direction :output :if-exists :supersede)
|
|
|
|
(format stream "INGREDIENT,SERVING~%")
|
|
|
|
(dolist (row table)
|
|
|
|
(format stream "~{~a~^,~}~%" row)))
|
|
|
|
(format t "[[file:./~a]]" filepath))
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
#+RESULTS:
|
|
|
|
[[file:./working-data/meal-planner-servings-adjusted.csv]]
|
|
|
|
|
|
|
|
#+begin_src lisp :session
|
|
|
|
(lisp-stat:defdf *ingredient-servings*
|
|
|
|
(lisp-stat:read-csv #P"working-data/meal-planner-servings-adjusted.csv"))
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
#+RESULTS:
|
|
|
|
: #<DATA-FRAME:DATA-FRAME (34 observations of 2 variables)>
|
|
|
|
|
|
|
|
#+begin_src lisp :session :results output
|
|
|
|
(format t "~d servings of ~d ingredients."
|
|
|
|
(lisp-stat:sum *ingredient-servings*:serving)
|
|
|
|
(lisp-stat:length *ingredient-servings*:ingredient))
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
#+RESULTS:
|
|
|
|
: 78 servings of 34 ingredients.
|
|
|
|
|
|
|
|
#+begin_src calc :results output
|
|
|
|
78 / 7
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
#+RESULTS:
|
|
|
|
: 11.1428571429
|
|
|
|
|
|
|
|
I can't tell if 11 items a day is a lot or not (2024-03-04 Mon).
|
|
|
|
|
|
|
|
#+begin_src lisp :session :results file
|
|
|
|
(vega:defplot ing-serv
|
|
|
|
`(:title "Weekly Ingredient Servings"
|
|
|
|
:description "Percentage of how much each ingredient is served in a week."
|
|
|
|
:data ,*ingredient-servings*
|
|
|
|
:width 600
|
|
|
|
:height 300
|
|
|
|
:mark (:type :bar)
|
|
|
|
:encoding (:x (:field :serving :title "No. of Servings in Week." :type :quantitative)
|
|
|
|
:color (:field :ingredient :type :nominal :title "Ingredient" :legend (:symbol-limit 100))
|
|
|
|
:tooltip (:field :ingredient))))
|
|
|
|
(vega:write-html ing-serv "renders/ingredient-servings.html")
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
#+RESULTS:
|
|
|
|
[[file:renders/ingredient-servings.html]]
|
|
|
|
|
|
|
|
#+begin_src shell :results silent
|
|
|
|
mv ~/Downloads/visualization.png ./renders/ingredient-servings.png
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
[[file:./renders/ingredient-servings.png]]
|
|
|
|
|
|
|
|
The chart above shows the diet is fairly well balanced. With that said, the
|
|
|
|
chicken and vegetable servings are noticeably bigger than the others – followed
|
|
|
|
by eggs.
|
|
|
|
|
|
|
|
* Ingredients Availability
|
|
|
|
|
|
|
|
I'm going to use ~csvlook~ to output the data into a org-mode table, which I will
|
|
|
|
then manipulate manually. The ~csvlook~ snippet is to just get me started.
|
|
|
|
|
|
|
|
#+begin_src shell :results output drawer
|
|
|
|
csvlook working-data/meal-planner-servings.csv
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
- Merged ~Scoop Protein Powder~, ~Protein Powder~, ~Protein Shake~ and ~Protein
|
|
|
|
Smoothie~ into one ingredient.
|
|
|
|
- I replaced ~Whole Grain Toast~ with ~Wholemeal Bread~, I think this is a UK
|
|
|
|
branding issue (I’ve only ever seen ’wholemeal’, never ’wholegrain’).
|
|
|
|
- Replaced ~Whole Grain Tortilla~ with ~Wholemeal Tortilla~, for the same reason
|
|
|
|
as the bread.
|
|
|
|
- ~0~ = ~False~ (i.e. Not sold by that supermarket)
|
|
|
|
- ~1~ = ~True~
|
|
|
|
- Used =C-c +=, =C-y= to provide the column totals (instead of using formulas).
|
|
|
|
|
|
|
|
#+NAME: food-availability
|
|
|
|
| INGREDIENT | TESCO | SAINSBURYS | MARKS-AND-SPENCER | ASDA | CO-OP | WAITROSE | BOOTHS | MORRISONS |
|
|
|
|
|---------------------------+-------+------------+-------------------+------+-------+----------+--------+-----------|
|
|
|
|
| Almonds | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 1 |
|
|
|
|
| Asparagus | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 1 |
|
|
|
|
| Bacon | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 1 |
|
|
|
|
| Banana | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 1 |
|
|
|
|
| Berries | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 1 |
|
|
|
|
| Broccoli | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 1 |
|
|
|
|
| Brown Rice | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 1 |
|
|
|
|
| Brussels Sprouts | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 1 |
|
|
|
|
| Chicken | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 1 |
|
|
|
|
| Cod | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 1 |
|
|
|
|
| Cottage Cheese | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 1 |
|
|
|
|
| Courgette | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 1 |
|
|
|
|
| Eggs | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 1 |
|
|
|
|
| Fruit | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 1 |
|
|
|
|
| Granola | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 1 |
|
|
|
|
| Greek Yogurt | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 1 |
|
|
|
|
| Green Beans | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 1 |
|
|
|
|
| Oatmeal (Porridge) | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 1 |
|
|
|
|
| Prawns | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 1 |
|
|
|
|
| Protein Powder | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 1 |
|
|
|
|
| Quinoa | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 1 |
|
|
|
|
| Salad (in mixed bag) | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 1 |
|
|
|
|
| Salmon | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 1 |
|
|
|
|
| Spinach | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 1 |
|
|
|
|
| Steak | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 1 |
|
|
|
|
| Sweet Potato | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 1 |
|
|
|
|
| Tuna | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 1 |
|
|
|
|
| Turkey | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 1 |
|
|
|
|
| Vegetables (in mixed bag) | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 1 |
|
|
|
|
| Walnuts | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 1 |
|
|
|
|
| Wholegrain Crackers | 1 | 0 | 0 | 0 | 1 | 1 | 0 | 1 |
|
|
|
|
| Wholemeal Bread | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 1 |
|
|
|
|
| Wholemeal Tortilla | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 0 |
|
|
|
|
|---------------------------+-------+------------+-------------------+------+-------+----------+--------+-----------|
|
|
|
|
| Total | 33 | 32 | 0 | 32 | 23 | 31 | 0 | 32 |
|
|
|
|
|
|
|
|
*Looks like Tesco is the only one selling all the ingredients.* Sainsburys, Asda
|
|
|
|
and Morrisons are viable alternatives.
|
|
|
|
|
|
|
|
Marks and Spencer uses [[https://www.ocado.com/][Ocado]] to provide it online shopping service. Having a
|
|
|
|
quick look on their website, I noticed it say there is a ’Minimum spend of
|
|
|
|
£40’. For now, I'm going to not include them in the availability table
|
|
|
|
above. The reason why is because their prices seem more expensive than the
|
|
|
|
others in the table. If the totals for the shops listed above are above £40,
|
|
|
|
I'll come back to Ocado and see how much their prices differ.
|
|
|
|
|
|
|
|
Booths just seems to sell recipes or fully prepared /stuff/ from what I can
|
|
|
|
gather on their website… and lots of wine.
|
|
|
|
|
|
|
|
* Ingredients Quantity Breakdown
|
|
|
|
|
|
|
|
I expect I will need to use these values as base values and come back to this
|
|
|
|
file after I've got an idea about what quantities are good and what need
|
|
|
|
changing.
|
|
|
|
|
|
|
|
- ~0.25~ like values refer to using 1/4 of a pack, of said item (i.e. 0.25 of a
|
|
|
|
packet of nuts).
|
|
|
|
- ~CHICKEN~ and ~TURKEY~ like ingredients refer to chicken breasts, I don’t like
|
|
|
|
cooking whole chickens.
|
|
|
|
- ~EGGS~ refers to the number of eggs in the serving, not the number of
|
|
|
|
boxes/packs.
|
|
|
|
|
|
|
|
#+NAME: ingredient-quantities
|
|
|
|
| DAY | ALMONDS | ASPARAGUS | BACON | BANANA | BERRIES | BROCCOLI | BROWN RICE | BRUSSELS SPROUTS | CHICKEN | COD | COTTAGE CHEESE | COURGETTE | EGGS | FRUIT | GRANOLA | GREEK YOGURT | GREEN BEANS | OATMEAL (PORRIDGE) | PRAWNS | PROTEIN POWDER | QUINOA | SALAD (IN MIXED BAG) | SALMON | SPINACH | STEAK | SWEET POTATO | TUNA | TURKEY | VEGETABLES (IN MIXED BAG) | WALNUTS | WHOLEGRAIN CRACKERS | WHOLEMEAL BREAD (TOAST) | WHOLEMEAL TORTILLA |
|
|
|
|
|-----------+---------+-----------+-------+--------+---------+----------+------------+------------------+---------+-----+----------------+-----------+------+-------+---------+--------------+-------------+--------------------+--------+----------------+--------+----------------------+--------+---------+-------+--------------+------+--------+---------------------------+---------+---------------------+-------------------------+--------------------|
|
|
|
|
| Monday | 0.25 | 0 | 0 | 0 | 0 | 0.25 | 0 | 0 | 2 | 0 | 0 | 0 | 2 | 0 | 0 | 0.25 | 0 | 0 | 0 | 0 | 0.25 | 0.25 | 1 | 0 | 1 | 0 | 0 | 0 | 0.25 | 0 | 0 | 2 | 0 |
|
|
|
|
| Tuesday | 0 | 0.25 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0.25 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0.1 | 0 | 0.25 | 1 | 0.25 | 0 | 1 | 1 | 0 | 0 | 0 | 1 | 2 | 0 |
|
|
|
|
| Wednesday | 0 | 0 | 0 | 0 | 0 | 0 | 0.5 | 0 | 0 | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0.25 | 0.2 | 0.5 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0.25 | 0.25 | 0 | 0 | 2 |
|
|
|
|
| Thursday | 0 | 0 | 0 | 0 | 0.25 | 0 | 0 | 0 | 2 | 1 | 0 | 0.5 | 0 | 1 | 0.25 | 0.25 | 0 | 0 | 0 | 0.1 | 0.25 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0.25 | 0 | 0 | 0 | 0 |
|
|
|
|
| Friday | 0.25 | 0 | 4 | 0 | 0 | 0 | 0 | 0.25 | 2 | 0 | 0 | 0 | 2 | 0 | 0 | 0.25 | 0 | 0 | 0 | 0 | 0.25 | 0.25 | 0 | 0 | 1 | 1 | 0 | 2 | 0.25 | 0 | 0 | 2 | 0 |
|
|
|
|
| Saturday | 0 | 0.25 | 0 | 1 | 0 | 0 | 0.5 | 0 | 0 | 0 | 0.25 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0.1 | 0 | 0.25 | 1 | 0.25 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 0 |
|
|
|
|
| Sunday | 0 | 0 | 0 | 0 | 0.25 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0.25 | 0.2 | 0.5 | 0.1 | 0.25 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0.25 | 0.25 | 0 | 0 | 2 |
|
|
|
|
|-----------+---------+-----------+-------+--------+---------+----------+------------+------------------+---------+-----+----------------+-----------+------+-------+---------+--------------+-------------+--------------------+--------+----------------+--------+----------------------+--------+---------+-------+--------------+------+--------+---------------------------+---------+---------------------+-------------------------+--------------------|
|
|
|
|
| Total | 0.5 | 0.5 | 4 | 2 | 0.5 | 0.25 | 1. | 0.25 | 6 | 1 | 0.5 | 0.5 | 8 | 3 | 0.25 | 0.75 | 0.5 | 0.4 | 1. | 0.4 | 1. | 1. | 3 | 0.5 | 2 | 2 | 2 | 6 | 1.25 | 0.5 | 2 | 6 | 4 |
|
|
|
|
#+TBLFM: @>$2..$34=vsum(@I..@II)
|
|
|
|
|
|
|
|
#+begin_quote
|
|
|
|
*2024-03-04 Mon:* Going to write this file to disk and work with the CSV file
|
|
|
|
going forward. This table is a bit unwieldy in this ORG file. *I've kept this
|
|
|
|
table for reference. Do not expect it to be accurate as I will not update it.*
|
|
|
|
All updates will be in the CSV file moving forward.
|
|
|
|
#+end_quote
|
|
|
|
|
|
|
|
#+begin_src lisp :var table=ingredient-quantities :results output raw
|
|
|
|
(let ((filepath #P"working-data/meal-planner-quantities.csv"))
|
|
|
|
(with-open-file (stream filepath :direction :output :if-exists :supersede)
|
|
|
|
(dolist (row table)
|
|
|
|
(format stream "~{~a~^,~}~%" row)))
|
|
|
|
(format t "[[file:./~a]]" filepath))
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
#+RESULTS:
|
|
|
|
[[file:./working-data/meal-planner-quantities.csv]]
|
|
|
|
|
|
|
|
I need to transform the =meal-planner-quantities.csv= file so I can work out how
|
|
|
|
many of each item I need to buy. For example, the ~almonds~ total is ~0.5~ (at
|
|
|
|
time of writing), this means the nearest package quantity is ~1~. I can do it
|
|
|
|
using the file above, but I can transform it and build a template, of sorts, so
|
|
|
|
I can quickly run through various shopping websites and compare prices (if I
|
|
|
|
need to).
|
|
|
|
|
|
|
|
#+begin_src shell :results output raw
|
|
|
|
# Input CSV file path
|
|
|
|
input_csv_file="working-data/meal-planner-quantities.csv"
|
|
|
|
# Output CSV file path
|
|
|
|
output_csv_file="working-data/meal-planner-quantities-adj.csv"
|
|
|
|
# Extract header (first row) and footer (last row)
|
|
|
|
header=$(head -n 1 "$input_csv_file")
|
|
|
|
footer=$(tail -n 1 "$input_csv_file")
|
|
|
|
# Split header and footer into arrays
|
|
|
|
IFS=',' read -ra header_array <<< "$header"
|
|
|
|
IFS=',' read -ra footer_array <<< "$footer"
|
|
|
|
# Create a new CSV file with rows containing header and footer entries
|
|
|
|
echo "INGREDIENT,QUANTITY" > "$output_csv_file"
|
|
|
|
for ((i = 0; i < ${#header_array[@]}; i++)); do
|
|
|
|
echo "${header_array[i]},${footer_array[i]}" >> "$output_csv_file"
|
|
|
|
done
|
|
|
|
# Remove the 'Total' and 'Day' parts from the CSV file.
|
|
|
|
sed -i '2d' "$output_csv_file"
|
|
|
|
# Print out link to the CSV file.
|
|
|
|
echo "[[file:./$output_csv_file]]"
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
#+RESULTS:
|
|
|
|
[[file:./working-data/meal-planner-quantities-adj.csv]]
|
|
|
|
|
|
|
|
Having transformed the data, you should see something along the lines of the
|
|
|
|
table below.
|
|
|
|
|
|
|
|
#+begin_src shell :results output raw
|
|
|
|
# The output will need minor adjustments to its formatting, for org-mode.
|
|
|
|
head -n 4 working-data/meal-planner-quantities-adj.csv | csvlook
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
#+RESULTS:
|
|
|
|
| INGREDIENT | QUANTITY |
|
|
|
|
|------------+----------|
|
|
|
|
| ALMONDS | 0.5 |
|
|
|
|
| ASPARAGUS | 0.5 |
|
|
|
|
| BACON | 4.0 |
|
|
|
|
|
|
|
|
* Explore Data and Total Costs for Tesco
|
|
|
|
|
|
|
|
I'm going to build out the CSV file outside of this file. The reason why is it
|
|
|
|
requires quite a number of function cells to calculate totals, and quite
|
|
|
|
frankly, using org-mode table-formulas can get unwieldy quickly.
|
|
|
|
|
|
|
|
[[file:./working-data/meal-planner-totals-tesco.csv]]
|
|
|
|
|
|
|
|
#+begin_src shell :results output raw
|
|
|
|
csvlook working-data/meal-planner-totals-tesco.csv
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
The table below was derived from =working-data/meal-planner-totals-tesco.csv=. I
|
|
|
|
used ~csvlook~ to output the table and I've worked on it since then.
|
|
|
|
|
|
|
|
#+RESULTS:
|
|
|
|
| INGREDIENT | QUANTITY | PACKET-QUANTITY | TOTAL-PACKETS | PRICE-PER-PACKET | ITEM-TOTAL |
|
|
|
|
|---------------------------+----------+-----------------+---------------+------------------+------------|
|
|
|
|
| ALMONDS | 0.50 | 250 g | 1 | 3.1 | 3.10 |
|
|
|
|
| ASPARAGUS | 0.50 | 180 g | 1 | 1.6 | 1.60 |
|
|
|
|
| BACON | 4.00 | 10 | 1 | 2.25 | 2.25 |
|
|
|
|
| BANANA | 2.00 | 5 | 1 | 0.78 | 0.78 |
|
|
|
|
| BERRIES | 0.50 | 200 g | 1 | 2.75 | 2.75 |
|
|
|
|
| BROCCOLI | 0.25 | 1 | 1 | 0.82 | 0.82 |
|
|
|
|
| BROWN RICE | 1.00 | 1 kg | 1 | 1.85 | 1.85 |
|
|
|
|
| BRUSSELS SPROUTS | 0.25 | 300 g | 1 | 0.58 | 0.58 |
|
|
|
|
| CHICKEN | 6.00 | 2 | 3 | 2.6 | 7.80 |
|
|
|
|
| COD | 1.00 | 2 | 1 | 5.6 | 5.60 |
|
|
|
|
| COTTAGE CHEESE | 0.50 | 300 g | 1 | 1.55 | 1.55 |
|
|
|
|
| COURGETTE | 0.50 | 1 | 1 | 0.56 | 0.56 |
|
|
|
|
| EGGS | 8.00 | 10 | 1 | 2.9 | 2.90 |
|
|
|
|
| FRUIT | 3.00 | 6 | 1 | 0.95 | 0.95 |
|
|
|
|
| GRANOLA | 0.25 | 1 kg | 1 | 2.5 | 2.50 |
|
|
|
|
| GREEK YOGURT | 0.75 | 500 g | 1 | 1.1 | 1.10 |
|
|
|
|
| GREEN BEANS | 0.50 | 220 g | 1 | 0.89 | 0.89 |
|
|
|
|
| OATMEAL (PORRIDGE) | 0.40 | 1 kg | 1 | 0.9 | 0.90 |
|
|
|
|
| PRAWNS | 1.00 | 250 g | 1 | 2.69 | 2.69 |
|
|
|
|
| PROTEIN POWDER | 0.40 | 500 g | 1 | 18 | 18.00 |
|
|
|
|
| QUINOA | 1.00 | 300 g | 1 | 2.8 | 2.80 |
|
|
|
|
| SALAD (IN MIXED BAG) | 1.00 | 90 g | 1 | 1.35 | 1.35 |
|
|
|
|
| SALMON | 3.00 | 4 | 1 | 4 | 4.00 |
|
|
|
|
| SPINACH | 0.50 | 250 g | 1 | 1.15 | 1.15 |
|
|
|
|
| STEAK | 2.00 | 2 | 1 | 4.15 | 4.15 |
|
|
|
|
| SWEET POTATO | 2.00 | 1 | 2 | 0.42 | 0.84 |
|
|
|
|
| TUNA | 2.00 | 1 | 2 | 0.55 | 1.10 |
|
|
|
|
| TURKEY | 6.00 | 3 | 2 | 4.5 | 9.00 |
|
|
|
|
| VEGETABLES (IN MIXED BAG) | 1.25 | 1 kg | 1 | 1.65 | 1.65 |
|
|
|
|
| WALNUTS | 0.50 | 200 g | 1 | 2.75 | 2.75 |
|
|
|
|
| WHOLEGRAIN CRACKERS | 2.00 | 160 g | 1 | 2 | 2.00 |
|
|
|
|
| WHOLEMEAL BREAD (TOAST) | 6.00 | 400 g | 1 | 1 | 1.00 |
|
|
|
|
| WHOLEMEAL TORTILLA | 4.00 | 8 | 1 | 1.4 | 1.40 |
|
|
|
|
|---------------------------+----------+-----------------+---------------+------------------+------------|
|
|
|
|
| | | | | TOTAL | 92.36 |
|
|
|
|
|
|
|
|
£92.36 is way too high for my liking. £92.36 to feed a single person? I know
|
|
|
|
it's 2024 in the UK but that seems excessive.
|
|
|
|
|
|
|
|
#+begin_src calc :results output
|
|
|
|
92.36 / 7
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
#+RESULTS:
|
|
|
|
: 13.1942857143
|
|
|
|
|
|
|
|
Saying that, £13.19/day, on food, doesn't seem that unrealistic. On top of that,
|
|
|
|
the £13.19/day covers all three meals. Looks like I haven't been paying
|
|
|
|
attention, or I’m naturally finding ways to keep my food costs down.
|
|
|
|
|
|
|
|
#+begin_src calc :results output
|
|
|
|
92.36 - 18
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
#+RESULTS:
|
|
|
|
: 74.36
|
|
|
|
|
|
|
|
Taking away the protein powder (£18 is the cheapest) leaves the total still to
|
|
|
|
high. The quantities the protein powder was listed at suggests this is not a
|
|
|
|
weekly item. On top of that, there are quite a few items which will produce
|
|
|
|
excess waste at the end of the week, if sticking to the meal planner. +So, maybe+
|
|
|
|
+the next step is to work out how much is weekly, fortnightly and monthly?+ The
|
|
|
|
quantities are accounted for on a weekly basis. The amount of waste isn't
|
|
|
|
enough to carry me into the next week.
|
|
|
|
|
|
|
|
#+begin_src calc :results output
|
|
|
|
74.36 / 7
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
#+RESULTS:
|
|
|
|
: 10.6228571429
|
|
|
|
|
|
|
|
Removing the protein powder from the day spent, brings it down to
|
|
|
|
£10.62/day. Because of how likely I would be buying protein powder, maybe this
|
|
|
|
is a more realistic figure than the £13.92 one above?
|
|
|
|
|
|
|
|
#+begin_src calc :results output
|
|
|
|
92.36 * 4
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
#+RESULTS:
|
|
|
|
: 369.44
|
|
|
|
|
|
|
|
The total spend on food for the month (including weekly protein powder) is going
|
|
|
|
to be around £369.44/month, give-or-take a few days for the uneven amount of
|
|
|
|
days in each month.
|
|
|
|
|
|
|
|
#+begin_src calc :results output
|
|
|
|
74.36 * 4
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
#+RESULTS:
|
|
|
|
: 297.44
|
|
|
|
|
|
|
|
The monthly spend without the weekly protein powder is £297.44, give-or-take a
|
|
|
|
few days. I would still need to buy at least one protein powder a month,
|
|
|
|
though.
|
|
|
|
|
|
|
|
#+begin_src calc :results output
|
|
|
|
297.44 + 18
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
#+RESULTS:
|
|
|
|
: 315.44
|
|
|
|
|
|
|
|
That brings the total (with monthly purchase of protein powder) to £315.44,
|
|
|
|
give-or-take a few days.
|