diff --git a/notebooks/ePix100/Characterize_Darks_ePix100_NBC.ipynb b/notebooks/ePix100/Characterize_Darks_ePix100_NBC.ipynb
index 0f1c2cd3858339186ecda900cdc05f910c73cc03..a1e0069c8afa24a682f42a47ae6312b6987bc0fb 100644
--- a/notebooks/ePix100/Characterize_Darks_ePix100_NBC.ipynb
+++ b/notebooks/ePix100/Characterize_Darks_ePix100_NBC.ipynb
@@ -4,13 +4,14 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "# ePix100 Dark Characterization\n",
-    "\n",
-    "Author: European XFEL Detector Group, Version: 2.0\n",
-    "\n",
-    "The following notebook provides dark image analysis and calibration constants of the ePix100 detector.\n",
-    "\n",
-    "Dark characterization evaluates offset and noise of the detector and gives information about bad pixels. Resulting maps are saved as .h5 files for a latter use and injected to calibration DB."
+    "Updated version of the ePix100 Dark Characterization notebook:\n",
+    "\n",
+    "- Generates the bad pixel map.\n",
+    "- Added badpixel_threshold_sigma input variable: Number of standard deviations considered for bad pixel classification.\n",
+    "- Sensor size is read from hdf5 file instead of being manually input.\n",
+    "- Detector temperature can be read from hdf5 file instead of having a fixed value only.\n",
+    "- Removed the xcal.HistogramCalculator() function, which calculation output was not in use.\n",
+    "- Set db_module to \"\" by default in the first cell (TODO note of previous notebook version)."
    ]
   },
   {
@@ -38,10 +39,8 @@
     "db_output = False # Output constants to the calibration database\n",
     "local_output = True # output constants locally\n",
     "\n",
-    "# Conditions used for injected calibration constants.\n",
-    "bias_voltage = 200 # bias voltage\n",
-    "in_vacuum = False # detector operated in vacuum\n",
-    "fix_temperature = 290. # fix temperature to this value\n",
+    "badpixel_threshold_sigma = 5.  # bad pixels defined by values outside n times this std from median\n",
+    "number_dark_frames = 0 # number of images to be used, if set to 0 all available images are used\n",
     "temp_limits = 5 # limit for parameter Operational temperature\n",
     "\n",
     "# Parameters used during selecting raw data trains.\n",
@@ -203,44 +202,175 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "#**************OFFSET MAP HISTOGRAM***********#\n",
-    "ho, co = np.histogram(constant_maps['Offset'].flatten(), bins=700)\n",
+    "noise_mean = np.mean(constant_maps['Noise'].data.flatten())\n",
+    "noise_sigma = np.std(constant_maps['Noise'].data.flatten())\n",
+    "noise_median = np.median(constant_maps['Noise'].data.flatten())\n",
     "\n",
+    "offset_mean = np.mean(constant_maps['Offset'].data.flatten())\n",
+    "offset_sigma = np.std(constant_maps['Offset'].data.flatten())\n",
+    "offset_median = np.median(constant_maps['Offset'].data.flatten())"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "87b73246-9080-4303-adbd-d8708886e775",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "#************** OFFSET HEAT MAP **************#\n",
+    "plt.figure(1)\n",
+    "fig1 = xana.heatmapPlot(constant_maps['Offset'][:, :, 0].data,\n",
+    "                       lut_label='[ADU]',\n",
+    "                       x_label = 'Column',\n",
+    "                       y_label = 'Row',\n",
+    "                       x_range=(0, sensorSize[1]),\n",
+    "                       y_range=(0, sensorSize[0]), \n",
+    "                       vmin=max(0,offset_median - badpixel_threshold_sigma*offset_sigma), \n",
+    "                       vmax=min(np.power(2,14)-1,offset_median + badpixel_threshold_sigma*offset_sigma))\n",
+    "\n",
+    "fig1.suptitle('Offset Map',x=.48,y=.9,fontsize=16)\n",
+    "fig1.set_size_inches(h=15,w=15)\n",
+    "\n",
+    "#************** OFFSET HISTOGRAM **************#\n",
+    "binwidth = offset_sigma/100\n",
+    "ho, co = np.histogram(constant_maps['Offset'].data.flatten(),\n",
+    "                      bins=np.arange((min(constant_maps['Offset'].data.flatten())),\n",
+    "                                 max(constant_maps['Offset'].data.flatten()) + binwidth,\n",
+    "                                 binwidth))\n",
     "do = {'x': co[:-1],\n",
     "      'y': ho,\n",
     "      'y_err': np.sqrt(ho[:]),\n",
     "      'drawstyle': 'bars',\n",
-    "      'color': 'cornflowerblue',\n",
-    "      }\n",
+    "      'color': 'cornflowerblue'}\n",
+    "\n",
+    "fig2 = xana.simplePlot(do, \n",
+    "                      aspect=1.5,\n",
+    "                      x_label='Offset [ADU]',\n",
+    "                      y_label='Counts',\n",
+    "                      x_range=(max(0,offset_median - badpixel_threshold_sigma*offset_sigma), \n",
+    "                               min(np.power(2,14)-1,offset_median + badpixel_threshold_sigma*offset_sigma)),\n",
+    "                      y_range=(0,max(ho)*1.1),\n",
+    "                      y_log=True)\n",
     "\n",
-    "fig = xana.simplePlot(do, figsize='1col', aspect=2,\n",
-    "                      x_label='Offset (ADU)',\n",
-    "                      y_label=\"Counts\", y_log=True,\n",
-    "                      )\n",
+    "fig2.suptitle('Offset Distribution',x=.5,y=.92,fontsize=16)\n",
     "\n",
-    "#*****NOISE MAP HISTOGRAM FROM THE OFFSET CORRECTED DATA*******#\n",
-    "hn, cn = np.histogram(constant_maps['Noise'].flatten(), bins=200)\n",
+    "stats_str = 'mean   : ' + \"{:.2f}\".format(np.round(offset_mean,2)) \\\n",
+    "          + '\\nstd       : ' + \"{:.2f}\".format(np.round(offset_sigma,2)) \\\n",
+    "          + '\\nmedian: ' + \"{:.2f}\".format(np.round(offset_median,2)) \\\n",
+    "          + '\\nmin:      ' + \"{:.2f}\".format(np.min(constant_maps['Offset'].data.flatten())) \\\n",
+    "          + '\\nmax:     ' + \"{:.2f}\".format(np.max(constant_maps['Offset'].data.flatten()))\n",
+    "fig2.text(s=stats_str,x=.7,y=.7,fontsize=14,bbox=dict(facecolor='yellow', edgecolor='black', alpha=.1));\n",
     "\n",
+    "#************** NOISE HEAT MAP **************#\n",
+    "fig3 = xana.heatmapPlot(constant_maps['Noise'][:, :, 0],\n",
+    "                       x_label='Columns', y_label='Rows',\n",
+    "                       lut_label='Noise [ADU]',\n",
+    "                       x_range=(0, sensorSize[1]),\n",
+    "                       y_range=(0, sensorSize[0]),\n",
+    "                       vmin=max(0,noise_median - badpixel_threshold_sigma*noise_sigma), \n",
+    "                       vmax=noise_median + badpixel_threshold_sigma*noise_sigma)\n",
+    "fig3.suptitle('Noise Map',x=.48,y=.9,fontsize=16)\n",
+    "fig3.set_size_inches(h=15,w=15)\n",
+    "\n",
+    "#************** NOISE HISTOGRAM **************#\n",
+    "binwidth = noise_sigma/100\n",
+    "hn, cn = np.histogram(constant_maps['Noise'].data.flatten(),\n",
+    "                      bins=np.arange((min(constant_maps['Noise'].data.flatten())),\n",
+    "                                 max(constant_maps['Noise'].data.flatten()) + binwidth,\n",
+    "                                 binwidth))\n",
     "dn = {'x': cn[:-1],\n",
     "      'y': hn,\n",
     "      'y_err': np.sqrt(hn[:]),\n",
     "      'drawstyle': 'bars',\n",
-    "      'color': 'cornflowerblue',\n",
-    "      }\n",
-    "\n",
-    "fig = xana.simplePlot(dn, figsize='1col', aspect=2,\n",
-    "                      x_label='Noise (ADU)',\n",
-    "                      y_label=\"Counts\",\n",
+    "      'color': 'cornflowerblue'}\n",
+    "\n",
+    "fig4 = xana.simplePlot(dn,\n",
+    "                      aspect=1.5,\n",
+    "                      x_range=(max(0,noise_median - badpixel_threshold_sigma*noise_sigma), \n",
+    "                               noise_median + badpixel_threshold_sigma*noise_sigma),\n",
+    "                      y_range=(0,max(hn)*1.1),\n",
+    "                      x_label='Noise [ADU]',\n",
+    "                      y_label='Counts',\n",
     "                      y_log=True)\n",
     "\n",
-    "#**************HEAT MAPS*******************#\n",
-    "fig = xana.heatmapPlot(constant_maps['Offset'][:, :, 0],\n",
-    "                       x_label='Columns', y_label='Rows',\n",
-    "                       lut_label='Offset (ADU)',\n",
-    "                       x_range=(0, pixels_y),\n",
-    "                       y_range=(0, pixels_x), vmin=1000, vmax=4000)\n",
+    "fig4.suptitle('Noise Distribution',x=.5,y=.92,fontsize=16);\n",
+    "\n",
+    "stats_str = 'mean   : ' + \"{:.2f}\".format(np.round(noise_mean,2)) \\\n",
+    "          + '\\nstd       : ' + \"{:.2f}\".format(np.round(noise_sigma,2)) \\\n",
+    "          + '\\nmedian: ' + \"{:.2f}\".format(np.round(noise_median,2)) \\\n",
+    "          + '\\nmin      : ' + \"{:.2f}\".format(np.min(constant_maps['Noise'].data.flatten())) \\\n",
+    "          + '\\nmax     : ' + \"{:.2f}\".format(np.max(constant_maps['Noise'].data.flatten()))\n",
+    "fig4.text(s=stats_str,x=.72,y=.7,fontsize=14, bbox=dict(facecolor='yellow', edgecolor='black', alpha=.1));"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "02702ec6-0dbc-4cbf-9421-7cef2a6290c4",
+   "metadata": {},
+   "source": [
+    "## Bad Pixel Map ###\n",
+    "\n",
+    "The bad pixel map is deduced by comparing offset and noise of each pixel ($v_i$) against its median value:\n",
+    "\n",
+    "$$ \n",
+    "v_i > \\mathrm{median}(v_{k}) + n \\sigma_{v_{k}}\n",
+    "$$\n",
+    "or\n",
+    "$$\n",
+    "v_i < \\mathrm{median}(v_{k}) - n \\sigma_{v_{k}} \n",
+    "$$\n",
+    "\n",
+    "Values are encoded in a 32 bit mask, where for the dark image deduced bad pixels the following non-zero entries are relevant:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "0edad7cd-e719-4274-a1f0-9d0ed0937ef2",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def print_bp_entry(bp):\n",
+    "    print(\"{:<30s} {:032b}\".format(bp.name, bp.value))\n",
+    "\n",
+    "print_bp_entry(BadPixels.OFFSET_OUT_OF_THRESHOLD)\n",
+    "print_bp_entry(BadPixels.NOISE_OUT_OF_THRESHOLD)\n",
+    "print_bp_entry(BadPixels.OFFSET_NOISE_EVAL_ERROR)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "b71b82c2-206b-4862-a134-8ae3cc065780",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def eval_bpidx(d):\n",
+    "\n",
+    "    mdn = np.nanmedian(d, axis=(0, 1))\n",
+    "    std = np.nanstd(d, axis=(0, 1))  \n",
+    "    idx = (d > mdn + badpixel_threshold_sigma*std) | (d < mdn - badpixel_threshold_sigma*std)\n",
+    "\n",
+    "    return idx"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "f23ae7ca-cf5b-457c-9457-57e38f12a484",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "constant_maps['BadPixels'] = np.zeros(constant_maps['Offset'].shape, np.uint32)\n",
+    "\n",
+    "constant_maps['BadPixels'][eval_bpidx(constant_maps['Offset'])] = BadPixels.OFFSET_OUT_OF_THRESHOLD.value\n",
+    "constant_maps['BadPixels'][eval_bpidx(constant_maps['Noise'])] = BadPixels.NOISE_OUT_OF_THRESHOLD.value\n",
+    "constant_maps['BadPixels'][~np.isfinite(constant_maps['Offset'])] = BadPixels.OFFSET_NOISE_EVAL_ERROR.value\n",
+    "constant_maps['BadPixels'][~np.isfinite(constant_maps['Noise'])] = BadPixels.OFFSET_NOISE_EVAL_ERROR.value\n",
     "\n",
-    "fig = xana.heatmapPlot(constant_maps['Noise'][:, :, 0],\n",
+    "#************** BAD PIXLES HEAT MAP **************#\n",
+    "fig5 = xana.heatmapPlot(constant_maps['BadPixels'][:, :, 0],\n",
     "                       x_label='Columns', y_label='Rows',\n",
     "                       lut_label='Noise (ADU)',\n",
     "                       x_range=(0, pixels_y),\n",