Laboratory Notebook & Integrated Task Management System for Bench Scientists

Introduction

Hello all. I am doing a PhD in Genetics & Molecular Biology and thought I’d share my obsidian setup. I use obsidian as an Electronic Laboratory Notebook, a task manager, and a note-taking system. I’ll only touch on the first two in this post, as the note-taking system is pretty standard zettelkasten stuff for academics.

It’s not a very complicated system, but it works well for my purposes and is simple enough to keep up well. Sorry for the redactions - I’m paranoid about scooping :sweat_smile:. Also, I got a lot of inspiration from this post. So definitely check that one out!

One more thing: this is still a work in progress for me, so I welcome any suggestions. I’ll also be updating this post as I change things.

Dashboard

Everything starts with my “Dashboard” (which I assign as my homepage). It doesn’t fit on one page so the second and third images are just scrolling down on the Dashboard.

The Dashboard is what I look at first thing in the morning, and whenever I’m not sure what to do next. At the top is just a link to my slipbox, where I store my zettelkasten notes.

Below that is an index of my ongoing, recently completed, and “someday” experiments. This comes from a dataview query:

>[!Experiments]+
> - # In-Progress
> 	  ```dataview
> 	  LIST FROM "lab_notebook" AND #experiment WHERE contains(status, "in-progress")
> 	  ```
> - # Done (Last 10)
>   ```dataview
>   LIST FROM "lab_notebook" AND #experiment 
>   WHERE contains(status, "done") OR contains(status, "failed")
>   LIMIT 10
> - # Someday
> 	  ```dataview
> 	  LIST FROM "lab_notebook" AND #experiment WHERE contains(status, "someday")
> 	  ```

Experiments are the fundamental unit of my notebook. Each major assay or cloning project I run has an Experiment page. I also use the Supercharged Links plugin to add an emoji based on the tags associated with each experiment, as well as their status (In-Progress, Done, Failed). Clicking on any of them takes me to the page for that experiment.

Below that is the “Todo” section. Again, I make use of dataview to query my notebook for tasks. This is broken in two categories: “TODAY” and “Inbox”. Today are all of the tasks in my notebook which have been assigned to… you guessed it, today. “Inbox” is for tasks which have not been assigned a date.

For each section, I group by the filename. This is a very important part of the system for me. This is due to the nature of my tasks. I might have three separate tasks which all say “Start overnight cultures at 16:30”. Which overnight cultures should I be starting? I need to know which experiment each task is associated with, and since each experiment is in its own file, grouping by filename lets me know (I have other views that allow me to look at the tasks to be done per experiment that I’ll explain later).

I use the following dataview query to generate this box:

> [!Todo]+
> - # TODAY
> 	  ```tasks 
> 	  not done 
> 	  due today 
> 	  group by filename
> 	  ```
>- # Inbox
> 	 ```tasks
> 	 not done
> 	 path does not include templates
> 	 no due date
> 	 group by filename

After that section is the “Week Ahead”. This is another dataview query which takes in all of my scheduled tasks and groups them by day and experiment. This view is really helpful to see what’s going on that week and if I need to move things around to make my week more manageable, if I have assays scheduled which overlap with meetings, etc. The logic in this query was a little more involved just because I wanted it to show overdue tasks that were scheduled on any date (but not show done tasks before today), and also to show all tasks (done or not) due in the next seven days. This is accomplished with the following dataview query:

>[!Week Ahead]+
>```tasks
>((due before in 7 days) AND (due after yesterday)) OR ((due before today) AND (not done))
>group by due
>group by filename

Experiments

As I mentioned before, Experiments are the funamental unit of my lab notebook. I create a new experiment using a template, with the Templater plugin.

The start and end date are recorded, and each experiment also has a unique ID associated with it, which is generated using the following script:

function adler32_str(str, seed) {
	var a = 1, b = 0, L = str.length, M = 0, c = 0, d = 0;
	if(typeof seed === 'number') { a = seed & 0xFFFF; b = seed >>> 16; }
	for(var i = 0; i < L;) {
		M = Math.min(L-i, 2918);
		while(M>0) {
			c = str.charCodeAt(i++);
			if(c < 0x80) { a += c; }
			else if(c < 0x800) {
				a += 192|((c>>6)&31);             b += a; --M;
				a += 128|(c&63);
			} else if(c >= 0xD800 && c < 0xE000) {
				c = (c&1023)+64; d = str.charCodeAt(i++) & 1023;
				a += 240|((c>>8)&7);              b += a; --M;
				a += 128|((c>>2)&63);             b += a; --M;
				a += 128|((d>>6)&15)|((c&3)<<4);  b += a; --M;
				a += 128|(d&63);
			} else {
				a += 224|((c>>12)&15);            b += a; --M;
				a += 128|((c>>6)&63);             b += a; --M;
				a += 128|(c&63);
			}
			b += a; --M;
		}
		a = (15*(a>>>16)+(a&65535));
		b = (15*(b>>>16)+(b&65535));
	}
	return ((b%65521) << 16) | (a%65521);
}

function decimalToHexString(number)
{
  if (number < 0)
  {
    number = 0xFFFFFFFF + number + 1;
  }

  return number.toString(16).toUpperCase();
}

// Returns hashes the current ISO8061 with adler32 and returns the number formatted in hexadecimal
function foo () {
    let date = new Date().toISOString();
    return decimalToHexString(adler32_str(date));
}

module.exports = foo;

The Adler32 algorithm was stolen from somewhere on the internet. As the comments in the script indicate, the script gets the current datetime formatted as ISO 8601 and runs it through the Adler-32 checksum algorithm. This results in strings that look like this: 3C250502.

Each experiment needs a unique ID so that I can easily tie physical objects to my electronic lab notebook. For instance, I frequently print out protocols that I follow on the bench and check off and scribble notes on with a pen. I keep these printed protocols in a folder we store in the lab. I then write the experiment ID on the printed protocol so that in the future, if I or anyone else wants to view all of my notes associated with that experiment, along with the results, etc., all they have to do is search for that ID and the appropriate experiment comes up.

Next, status and tags facilitate dataview queries and link prettification.

Each experiment has a “purpose”, and then each date that I work on the experiment gets a header associated with it. What I really love about this system is that as I’m working on each experiment and tasks come up, I just write that task down in that day’s entry for that experiment and it gets sucked up into my Dashboard for me to look at later. Very convenient!

Future Directions

Inventory Management

I’d love to integrate an inventory management system. For example, much of what I do is molecular cloning, whereby I use bacteria and some enzymes as factories to engineer pieces of DNA (called plasmids), which I use for later experiments. It shouldn’t be too hard to use obsidian to keep these plasmids in a database, so that I can (a) refer to the cloning Experiment which generated any given plasmid, (b) see all of the Experiments which make use of that plasmid (c) see the physical location of the plasmid (e.g. which freezer box it is stored in and where in that box I can find the plasmid).

The same inventory management system would be useful for engineered strains of animals I generate, PCR primers I use, and probably other things I haven’t thought of.

Meetings

I’d like a better meeting system with notions of people I’m meeting with, but that is still in the works. It seems like this is a common use-case and shouldn’t be too difficult. As you might have noticed, any tasks that come up in meetings do come up in the Dashboard, which is quite nice.

2 Likes

Thank you so much for posting this. You really helped me to complete one of the unrefined parts of my workflow - the lab notes!

I do have one question about the code that pulls every task to the dashboard in your lab note template. What does the call-out part serve in that code?

Glad it is of some help to someone! The callout is just to visually organize things into blocks. I also like that I can collapse the callouts.

1 Like