diff --git a/ggir-use-case-1.ipynb b/ggir-use-case-1.ipynb new file mode 100644 index 0000000..4a94c91 --- /dev/null +++ b/ggir-use-case-1.ipynb @@ -0,0 +1,313 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# GGIR use case 1\n", + "\n", + "This use case requires the generation of two types of related sleep signals: rest and main bed period. Both signals appear in a time signal between 12:00 noon and 12:00 next day. Each signal consists of two binary signals: period starts and period ends. For reference, there is a larger [description of this use case](https://github.com/sequgen/sequgen/issues/21) as well as a [visualization](https://cran.r-project.org/web/packages/GGIR/vignettes/GGIR.html#42_Output_part_4) of the time signals (click on the tab `4.2.3 visualisation_sleep.pdf`)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1. Peak generation\n", + "\n", + "The required time signals consist a series of peaks which can be generated with the sequgen functions. Let's start with importing the required functions." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import random\n", + "from sequgen.dimension import Dimension\n", + "from sequgen.parameter_space import ParameterSpace" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "sequgen only provides signals with a single peak, so we need to create our own function for generating signals with several peaks. Furthermore, the peaks need to satisfy two requirements: 1. peaks can not overlap each other, and 2. peaks cannot extend beyond the end of the available time frame. We need functions to check these constraints as well.\n", + "\n", + "If a peak does not satisfy a constraint, it will be discarded and another peak will be generated. However, it is possible that there is no more room in the time frame for another peak that satifies the required constraints. To avoid entering an infinitive loop, we will only allow for 100 successive failed peak generation attempts." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "MAXIMUM_FAILED_TRIES = 100\n", + "\n", + "\n", + "def peaks_overlap(peaks):\n", + " peaks = peaks_sort(peaks)\n", + " for i in range(0, len(peaks)-1):\n", + " if peaks[i]['location'] + peaks[i]['width'] >= peaks[i+1]['location']:\n", + " return(True)\n", + " return(False)\n", + "\n", + "\n", + "def peaks_sort(peaks):\n", + " return([ peak for peak in sorted(peaks, key=lambda p:p['location']) ])\n", + "\n", + "\n", + "def peak_extends_maximum(peak):\n", + " return('maximum' in peak and peak['maximum'] < peak['location'] + peak['width']) \n", + "\n", + "\n", + "def peaks_generate(parameter_space):\n", + " peaks = []\n", + " failed_tries = 0\n", + " iterations = parameter_space.sample()[\"iterations\"]\n", + " while len(peaks) < iterations and failed_tries < MAXIMUM_FAILED_TRIES:\n", + " new_peak = parameter_space.sample()\n", + " if peak_extends_maximum(new_peak) or peaks_overlap(peaks + [new_peak]):\n", + " failed_tries += 1\n", + " else:\n", + " peaks.append(new_peak)\n", + " peaks = peaks_sort(peaks)\n", + " failed_tries = 0\n", + " return peaks" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2. Signal functions\n", + "\n", + "A signal consists of two main parts: main bed time, the time at night that a person is in bed, and resting times, several periods during the day when a person is resting. The function has six parameters: start and end point of the available start frame, minimum and maximum start of bed time and minimum and maximum length of the bed time period. The resting times are divided in three groups: pre-bed time rests, bed time rests and post-bed time rests." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "def make_signal(profile):\n", + " bed_time = make_bed_time(profile['bed_time_start'][0], profile['bed_time_start'][1], profile['bed_time_width'][0], profile['bed_time_width'][1])\n", + " pre_bed_time_rests = make_rests(profile['time_frame'][0] * 60, bed_time[0]['location'], \n", + " profile['other_rest_width'][0] * 60, profile['other_rest_width'][1] * 60, \n", + " profile['pre_bed_time_iterations'][0], profile['pre_bed_time_iterations'][1])\n", + " bed_time_rests = make_rests(bed_time[0]['location'], bed_time[0]['location']+bed_time[0]['width'],\n", + " profile['bed_time_rest_width'][0] * 60, profile['bed_time_rest_width'][1] * 60,\n", + " profile['bed_time_iterations'][0], profile['bed_time_iterations'][1])\n", + " post_bed_time_rests = make_rests(bed_time[0]['location']+bed_time[0]['width'], profile['time_frame'][1]*60,\n", + " profile['other_rest_width'][0] * 60, profile['other_rest_width'][1] * 60,\n", + " profile['post_bed_time_iterations'][0], profile['post_bed_time_iterations'][1])\n", + " return(bed_time, (pre_bed_time_rests + bed_time_rests + post_bed_time_rests))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We create a function for generating an arbitrary bed time period that satisfies the constraints" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "def make_bed_time(bed_time_start_minimum, bed_time_start_maximum, bed_time_minimum, bed_time_maximum, maximum=None, iterations=1):\n", + " if maximum == None:\n", + " maximum = bed_time_start_maximum + bed_time_maximum\n", + " parameter_space = ParameterSpace([\n", + " Dimension(\"location\", bed_time_start_minimum * 60, bed_time_start_maximum * 60),\n", + " Dimension(\"width\", bed_time_minimum * 60, bed_time_maximum * 60),\n", + " Dimension(\"maximum\", maximum * 60),\n", + " Dimension(\"iterations\", iterations),\n", + " ])\n", + " bed_time = peaks_generate(parameter_space)\n", + " return(bed_time)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, we define a function for generating the rest times:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "def make_rests(start_time, end_time, width_minimum, width_maximum, iterations_minimum, iterations_maximum):\n", + " parameter_space = ParameterSpace([\n", + " Dimension(\"location\", start_time, end_time),\n", + " Dimension(\"width\", width_minimum, width_maximum),\n", + " Dimension(\"maximum\", end_time),\n", + " Dimension(\"iterations\", iterations_minimum, iterations_maximum),\n", + " ])\n", + " rests = peaks_generate(parameter_space)\n", + " return(rests)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 3. Plotting functions\n", + "\n", + "We use these functions for plotting the time series." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "\n", + "\n", + "def plot_draw_graph(ax, start_time, end_time, data, color, label, height=1):\n", + " for i in range(0, len(data)):\n", + " period = data[i]\n", + " if i == 0:\n", + " ax.bar([period['location'] + 0.5 * period['width']], [height], width=period['width'], color=color, label=label)\n", + " else:\n", + " ax.bar([period['location'] + 0.5 * period['width']], [height], width=period['width'], color=color)\n", + " ax.set_xlim(start_time, end_time)\n", + " ax.set_ylim(min(0, 1.5*height), max(0, 1.5*height))\n", + " ax.tick_params(left=False, labelleft=False)\n", + " ax.tick_params(bottom=False, labelbottom=False)\n", + " ax.legend()\n", + "\n", + " \n", + "def plot(start_time, end_time, bed_time, rests):\n", + " fig, axs = plt.subplots(2, 1, figsize=(10,3))\n", + " plot_draw_graph(axs[0], start_time, end_time, rests, \"C8\", \"rest periods\")\n", + " plot_draw_graph(axs[1], start_time, end_time, bed_time, \"C7\", \"main bed time\", height=-1)\n", + " plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 4. Export functions\n", + "\n", + "And these functions convert the start and end points in the time series to a human-readable format." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "def number2time(number):\n", + " hours = int(number / 60)\n", + " minutes = int(number - (hours*60))\n", + " return(str(hours)+\":\"+str(minutes).zfill(2))\n", + " \n", + "\n", + "def print_data(data, data_name):\n", + " print(data_name+ \" starts:\", end=\" \")\n", + " for peak in data:\n", + " print(number2time(round(peak['location'])), end=\" \")\n", + " print(\"\\n\" + data_name + \" ends: \", end=\" \")\n", + " for peak in data:\n", + " print(number2time(round(peak['location'] + peak['width'])), end=\" \")\n", + " print()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 5. Generate, plot and export\n", + "\n", + "Finally we generate the time series from a person profile which is defined like this: the main time frame runs from noon (12:00) until noon next day (36:00) with bed time starting between 22:00 and 02:00 (26:00) and lasting between six and nine hours. Bed time include between one and three rest periods while before bed time there can be up to five rest periods and after bed time at most one. Bed time rests last between two and eight hours while other rests last between 0.2 hours and 0.5 hours. We check the time series by plotting it and inspecting the start and end points of the different periods." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Rest starts: 13:22 19:47 22:03 26:13 30:33 34:43 \n", + " Rest ends: 13:51 20:11 22:22 28:25 32:37 35:08 \n", + "Bed time starts: 24:51 \n", + "Bed time ends: 32:59 \n" + ] + } + ], + "source": [ + "profile = { 'time_frame': [12, 36],\n", + " 'bed_time_start': [22, 26],\n", + " 'bed_time_width': [6, 9],\n", + " 'bed_time_iterations': [1, 3],\n", + " 'pre_bed_time_iterations': [0, 5],\n", + " 'post_bed_time_iterations': [0, 1],\n", + " 'bed_time_rest_width': [2, 8],\n", + " 'other_rest_width': [0.2, 0.5]\n", + " }\n", + "\n", + "bed_time, rests = make_signal(profile)\n", + "\n", + "plot(12 * 60, 36*60, bed_time, rests)\n", + "\n", + "print_data(rests, \" Rest\")\n", + "print_data(bed_time, \"Bed time\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "python37", + "language": "python", + "name": "python37" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +}