Skip to content

Instantly share code, notes, and snippets.

@gloriouslyawkwardlife
Last active October 22, 2024 15:18
Show Gist options
  • Save gloriouslyawkwardlife/82f8855832c33468289e0b0afa3d278e to your computer and use it in GitHub Desktop.
Save gloriouslyawkwardlife/82f8855832c33468289e0b0afa3d278e to your computer and use it in GitHub Desktop.
Wolfram Language - Create Daily Log Notebook
ExternalEvaluate[{"Python",
"Evaluator" -> <|
"PythonRuntime" -> File["/opt/homebrew/bin/python3.12"]|>},
File["/Users/steven/Library/Mobile \
Documents/com~apple~CloudDocs/Scripts/Python/datacollection.py"]];
dbr = DatabaseReference[
URL["mysql://xxx:[email protected]/\
personalinformatics"]];
accessToken =
"xxx";
threadsId = "xxx";
nb = CreateNotebook[];
NotebookWrite[nb, {
Cell["Daily Log", "Title"],
Cell[DateString[Yesterday, "LocaleDateFull"], "Subtitle"],
Cell["Apple Health Data", "Section"],
Cell["These charts are generated from a daily Apple Health export \
file.", "Text"]
}];
DateListPlot[
ExternalEvaluate[dbr,
"SELECT endDate,value FROM applehealth WHERE type LIKE \
'%heartrate%' AND sourceName = 'Steven\[CloseCurlyQuote]s \
Apple Watch' AND DATE(endDate) = DATE_SUB(CURDATE(),INTERVAL 1 \
DAY)"],
PlotLabel ->
"Daily Heart Rate Log \[Bullet] " <>
DateString[Yesterday, "LocaleDateLong"],
PlotTheme -> "Web",
PlotRange -> All,
ImageSize -> {700, 300},
AspectRatio -> 3/7,
Joined -> False,
Filling -> Bottom,
LabelingFunction -> (Callout[IntegerPart[#1[[2]]], Automatic] &)
] // NotebookWrite[nb,
Cell[BoxData[MakeBoxes[#, StandardForm]], "Output"]] &;
DateListPlot[
ExternalEvaluate[dbr,
"SELECT endDate,value FROM applehealth WHERE type LIKE \
'%stepcount%' AND sourceName = 'Steven\[CloseCurlyQuote]s \
Apple Watch' AND DATE(endDate) = DATE_SUB(CURDATE(),INTERVAL 1 \
DAY)"],
PlotLabel ->
"Daily Step Log \[Bullet] " <>
DateString[Yesterday, "LocaleDateLong"],
PlotTheme -> "Web",
PlotRange -> All,
Joined -> False,
Filling -> Bottom,
LabelingFunction -> (Callout[IntegerPart[#1[[2]]], Automatic] &),
ImageSize -> {700, 300},
AspectRatio -> 3/7
] // NotebookWrite[nb,
Cell[BoxData[MakeBoxes[#, StandardForm]], "Output"]] &;
DateListPlot[
ExternalEvaluate[dbr,
"SELECT DATE(endDate),SUM(value) from applehealth WHERE \
DATE(endDate) >= DATE_SUB(CURDATE(),INTERVAL 30 DAY) AND type LIKE \
'%stepcount%' AND sourceName = 'Steven\[CloseCurlyQuote]s \
Apple Watch' GROUP BY DATE(endDate)"],
PlotLabel -> "Daily Step Counts, Last 30 Days",
PlotTheme -> "Web",
PlotRange -> All,
Joined -> False,
Filling -> Bottom,
LabelingFunction -> (Callout[IntegerPart[#1[[2]]], Automatic] &),
ImageSize -> {700, 300},
AspectRatio -> 3/7
] // NotebookWrite[nb,
Cell[BoxData[MakeBoxes[#, StandardForm]], "Output"]] &;
NotebookWrite[nb, {
Cell["Travel & Location Data", "Section"],
Cell["These charts are generated from Bouncie and Swarm \
application data.", "Text"]
}];
NotebookWrite[nb, Cell["Maps", "Subsection"]];
d = ExternalEvaluate[dbr,
"SELECT latitude,longitude,venue,createdAt FROM checkins WHERE \
privacy IS NULL AND DATE(createdAt) = DATE_SUB(CURDATE(),INTERVAL 1 \
DAY)"];
If[
Length[d] > 0,
points =
Table[GeoPosition[{d[[i, "latitude"]], d[[i, "longitude"]]}], {i,
Length[d]}];
labels = Table[d[[i, "venue"]], {i, Length[d]}];
locations = DeleteDuplicates@MapThread[Callout, {points, labels}];
GeoListPlot[
locations,
GeoBackground -> "StreetMap",
GeoRangePadding -> Scaled[0.5],
ImageSize -> {700, 500},
AspectRatio -> 5/7,
GeoScaleBar -> {"Imperial", "Metric"},
PlotLabel ->
"Daily Checkins \[Bullet] " <>
DateString[Yesterday, "LocaleDateLong"] <>
"\n(Checkins at private locations not included on map)"
] // NotebookWrite[nb,
Cell[BoxData[MakeBoxes[#, StandardForm]], "Output"]] &,
Notebookwrite[nb, Cell["No checkins to report.", "Text"]]
]
d = ExternalEvaluate[dbr,
"SELECT gps FROM bouncietrips WHERE DATE(startTime) = \
DATE_SUB(CURDATE(),INTERVAL 1 DAY) OR DATE(endTime) = \
DATE_SUB(CURDATE(),INTERVAL 1 DAY)"];
If[
Length[d] > 0,
gj = <|"type" -> "FeatureCollection", "features" -> {}|>;
Do[
AppendTo[
gj[["features"]], {"type" -> "Feature", "properties" -> <||>,
"geometry" -> ImportString[d[[i, "gps"]], "RawJSON"]}]
, {i, Length[d]}
];
gjout = ExportString[gj, "JSON"];
ImportString[
gjout,
"GeoJSON",
PlotLabel ->
"Bouncie Driving Log\nTrips Start or End on " <>
DateString[Yesterday, "LocaleDateLong"],
GeoBackground -> "StreetMap",
GeoRangePaddding -> Automatic,
GeoScaleBar -> {"Imperial", "Metric"},
ImageSize -> {700, 500},
AspectRatio -> 5/7
] // NotebookWrite[nb,
Cell[BoxData[MakeBoxes[#, StandardForm]], "Output"]] &,
NotebookWrite[nb, Cell["No trips to report.", "Text"]]
]
NotebookWrite[nb, Cell["Travel Log", "Subsection"]];
log = {};
d = ExternalEvaluate[dbr,
"SELECT createdAt,venue,category FROM checkins WHERE privacy IS \
NULL AND DATE(createdAt) = DATE_SUB(CURDATE(),INTERVAL 1 DAY)"];
Do[
AppendTo[
log, <|"startTime" -> d[[i, "createdAt"]],
endTime -> d[[i, "createdAt"]],
"Event" ->
"Checked in at " <> d[[i, "venue"]] <> " (" <>
d[[i, "category"]] <> ")"|>]
, {i, Length[d]}];
d = ExternalEvaluate[dbr,
"SELECT startTime, endTime FROM bouncietrips WHERE DATE(startTime) \
= DATE_SUB(CURDATE(),INTERVAL 1 DAY) OR DATE(endTime) = \
DATE_SUB(CURDATE(),INTERVAL 1 DAY)"];
Do[
AppendTo[
log,
<|
"startTime" -> d[[i, "startTime"]],
"endTime" -> d[[i, "endTime"]], "Event" -> "On the road..."|>
], {i, Length[d]}];
log = SortBy[log, #startTime &];
If[
Length[log] > 0,
TextGrid[Table[
{
If[
MissingQ[log[[i, "endTime"]]],
DateString[log[[i, "startTime"]], "LocaleTimeCompact"],
DateString[log[[i, "startTime"]], "LocaleTimeCompact"] <>
" - " <> DateString[log[[i, "endTime"]], "LocaleTimeCompact"]
],
log[[i, "Event"]]
}
, {i, Length[log]}]] //
NotebookWrite[nb,
Cell[BoxData[MakeBoxes[#, StandardForm]], "Output"]] &,
NotebookWrite[nb, Cell["There was no travel to report.", "Text"]]
];
NotebookWrite[nb,
Cell["The contents of this page are Copyright © " <>
DateString[Now, "Year"] <>
" Steven W. Buehler. All Rights Reserved.\n\
https://gloriouslyawkwardlife.com\n\
https://gloriouslyawkwardlife.notion.site\nGenerated Using Wolfram \
Language.", "Text", CellFrame -> True, Alignment -> Center]];
(* Write/Export Notebook Images and file to Cloud & Local *)
CloudPublish[ExportForm[nb, "PNG"],
DateString[Yesterday, "ISODate"] <> "_dailylog.png",
Permissions -> "Public"];
CloudPublish[nb, "DailyLog.nb",
Permissions -> {"All" -> "Read", "Owner" -> {All}}];
Export["/Users/steven/Downloads/dailylog.png", nb, "PNG"];
NotebookSave[nb,
"/Users/steven/Downloads/" <> DateString[Yesterday, "ISODate"] <>
" Daily Log.nb"];
NotebookClose[nb];
(* Threads Post Part 2: Create Media container *)
postcontainerId = Import[
HTTPRequest[
URL[
"https://graph.threads.net/v1.0/" <> threadsId <> "/threads"],
<|
Method -> "POST",
"Query" -> {
"media_type" -> "IMAGE",
"image_url" ->
"https://www.wolframcloud.com/obj/xxxx/" <>
DateString[Yesterday, "ISODate"] <> "_dailylog.png",
"text" -> "#Lifelogging: Daily Personal Charts, " <>
DateString[Yesterday, "LocaleDateLong"] <>
", generated using the Wolfram Language from \
@wolframresearch. Notebook version at \
https://www.wolframcloud.com/obj/xxxx/DailyLog.nb",
"access_token" -> accessToken
}
|>
]
, "RawJSON"][["id"]];
(* Threads Post Part 3: Post the container *)
post = URLExecute[
HTTPRequest[
URL[
"https://graph.threads.net/v1.0/" <> threadsId <>
"/threads_publish"],
<|
Method -> "POST",
"Query" -> {
"creation_id" -> postcontainerId,
"access_token" -> accessToken
}
|>
]
];
(* Update image block on home page *)
URLExecute[
HTTPRequest[
"https://api.notion.com/v1/blocks/xxxx",
<|
Method -> "PATCH",
"Headers" -> {
"Authorization" ->
"Bearer xxxx",
"Notion-Version" -> "2022-06-28"
},
"ContentType" -> "application/json",
"Body" -> ExportString[{
"image" -> {
"external" -> {
"url" ->
"https://www.wolframcloud.com/obj/xxxx/" <>
DateString[Yesterday, "ISODate"] <> "_dailylog.png"
}
}
}, "JSON"]
|>
]
];
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment