diff --git a/notebooks/AGIPD/Chracterize_AGIPD_Gain_PC_NBC.ipynb b/notebooks/AGIPD/Chracterize_AGIPD_Gain_PC_NBC.ipynb
index 672e8e9bc089a6abf787658d52d2e70e3624c006..4185ab714d4a91cf10990ac4be728f1ab1d0e5a7 100644
--- a/notebooks/AGIPD/Chracterize_AGIPD_Gain_PC_NBC.ipynb
+++ b/notebooks/AGIPD/Chracterize_AGIPD_Gain_PC_NBC.ipynb
@@ -36,7 +36,6 @@
     "out_folder = \"/gpfs/exfel/data/scratch/jsztuk/test/pc\" # path to output to, required\n",
     "metadata_folder = \"\"  # Directory containing calibration_metadata.yml when run by xfel-calibrate\n",
     "runs = [92, 93, 94, 95, 96, 97, 98, 99] # runs to use, required, range allowed\n",
-    "n_sequences = 5 # number of sequence files, starting for 0 to evaluate\n",
     "\n",
     "modules = [-1] # modules to work on, required, range allowed\n",
     "karabo_da = [\"all\"]\n",
@@ -47,9 +46,11 @@
     "instrument_source_template = '{}/DET/{}:xtdf'  # path in the HDF5 file to images\n",
     "receiver_template = \"{}CH0\" # inset for receiver devices\n",
     "\n",
-    "use_dir_creation_date = True\n",
-    "delta_time = 0 # offset to the creation time (e.g. useful in case we want to force the system to use diff. dark constants)\n",
+    "creation_time = \"\" # To overwrite the measured creation_time. Required Format: YYYY-MM-DD HR:MN:SC e.g. \"2022-06-28 13:00:00\"\n",
+    "creation_date_offset = \"00:00:00\" # add an offset to creation date, e.g. to get different constants\n",
+    "cal_db_timeout = 3000000 # timeout on caldb requests\"\n",
     "cal_db_interface = \"tcp://max-exfl-cal001:8019\"  # the database interface to use\n",
+    "\n",
     "local_output = True # output constants locally\n",
     "db_output = False # output constants to database\n",
     "\n",
@@ -62,6 +63,7 @@
     "\n",
     "fit_hook = False # fit a hook function to medium gain slope --> run without hook\n",
     "high_res_badpix_3d = False # set this to True if you need high-resolution 3d bad pixel plots. Runtime: ~ 1h\n",
+    "save_plots = False # set to True if you desire saving plots to output folder\n",
     "\n",
     "hg_range = [30,210]#[0,-150] # range for linear fit. If upper edge is negative use clustering result (bound_hg - 20)\n",
     "mg_range = [-277,600]#[-350,600] # range for linear fit. If lower edge is negative use clustering result (bound_mg + 20)\n",
@@ -80,10 +82,10 @@
     "import warnings\n",
     "from datetime import datetime, timedelta\n",
     "from functools import partial\n",
+    "from dateutil import parser\n",
     "\n",
     "warnings.filterwarnings('ignore')\n",
     "\n",
-    "import dateutil.parser\n",
     "import h5py\n",
     "import matplotlib\n",
     "import numpy as np\n",
@@ -91,7 +93,7 @@
     "\n",
     "import matplotlib.pyplot as plt\n",
     "from matplotlib import gridspec\n",
-    "from matplotlib.colors import LogNorm, PowerNorm\n",
+    "from matplotlib.colors import LogNorm\n",
     "import matplotlib.patches as patches\n",
     "from mpl_toolkits.axes_grid1 import AxesGrid\n",
     "\n",
@@ -102,19 +104,14 @@
     "\n",
     "from cal_tools.agipdlib import AgipdCtrl\n",
     "from cal_tools.enums import BadPixels\n",
-    "from cal_tools.plotting import plot_badpix_3d, show_overview\n",
+    "from cal_tools.plotting import plot_badpix_3d\n",
     "from cal_tools.tools import (\n",
-    "    gain_map_files,\n",
+    "    calcat_creation_time,\n",
     "    get_constant_from_db_and_time,\n",
     "    get_dir_creation_date,\n",
-    "    get_notebook_name,\n",
-    "    get_pdu_from_db,\n",
-    "    get_report,\n",
     "    module_index_to_qm,\n",
-    "    parse_runs,\n",
-    "    send_to_db,\n",
     ")\n",
-    "from iCalibrationDB import Conditions, ConstantMetaData, Constants, Detectors, Versions\n",
+    "from iCalibrationDB import Conditions, Constants\n",
     "\n",
     "# make sure a cluster is running with ipcluster start --n=32, give it a while to start\n",
     "view = Client(profile=cluster_profile)[:]\n",
@@ -182,11 +179,12 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "# Define creation time\n",
-    "creation_time = None\n",
-    "if use_dir_creation_date:\n",
-    "    creation_time = get_dir_creation_date(in_folder, first_run)\n",
-    "    creation_time = creation_time + timedelta(hours=delta_time)\n",
+    "# Evaluate creation time\n",
+    "creation_time = calcat_creation_time(in_folder, runs[0], creation_time)\n",
+    "offset = parser.parse(creation_date_offset)\n",
+    "delta = timedelta(hours=offset.hour, minutes=offset.minute, seconds=offset.second)\n",
+    "creation_time += delta\n",
+    "print(f\"Creation time: {creation_time}\\n\")\n",
     "\n",
     "# Read AGIPD parameter conditions.\n",
     "if acq_rate < 0.:\n",
@@ -886,10 +884,10 @@
     "        fig1.show()\n",
     "        fig2.show()\n",
     "        fig3.show()\n",
-    "\n",
-    "        fig1.savefig(\"{}/module_{}_{}_pixel_plot.png\".format(out_folder, mod, roi))\n",
-    "        fig2.savefig(\"{}/module_{}_{}_pixel_plot_gain.png\".format(out_folder, mod, roi))\n",
-    "        fig3.savefig(\"{}/module_{}_{}_pixel_plot_fits.png\".format(out_folder, mod, roi))"
+    "        if save_plots:\n",
+    "            fig1.savefig(\"{}/module_{}_{}_pixel_plot.png\".format(out_folder, mod, roi))\n",
+    "            fig2.savefig(\"{}/module_{}_{}_pixel_plot_gain.png\".format(out_folder, mod, roi))\n",
+    "            fig3.savefig(\"{}/module_{}_{}_pixel_plot_fits.png\".format(out_folder, mod, roi))"
    ]
   },
   {
@@ -1415,35 +1413,6 @@
     "    mask[bad_fits_med]  |= BadPixels.CI_EVAL_ERROR.value\n"
    ]
   },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "def slope_dict_to_arr(d):\n",
-    "    key_to_index = {\n",
-    "        \"ml\": 0,\n",
-    "        \"bl\": 1,\n",
-    "        \"devl\": 2,\n",
-    "        \"mh\": 3,\n",
-    "        \"bh\": 4,\n",
-    "        \"oh\": 5,\n",
-    "        \"ch\": 6,\n",
-    "        \"ah\": 7,\n",
-    "        \"devh\": 8,\n",
-    "        \"tresh\": 9,\n",
-    "    }\n",
-    "\n",
-    "    arr = np.zeros([11]+list(d[\"ml\"].shape), np.float32)\n",
-    "    for key, item in d.items():\n",
-    "        if key not in key_to_index:\n",
-    "            continue\n",
-    "        arr[key_to_index[key],...] = item\n",
-    "        \n",
-    "    return arr"
-   ]
-  },
   {
    "cell_type": "code",
    "execution_count": null,
@@ -1461,65 +1430,6 @@
     "    store_file.close()"
    ]
   },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "# Read report path and create file location tuple to add with the injection\n",
-    "proposal = list(filter(None, in_folder.strip('/').split('/')))[-2]\n",
-    "file_loc = proposal + ' ' + ' '.join(list(map(str,runs)))\n",
-    "\n",
-    "report = get_report(metadata_folder)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "md = None\n",
-    "\n",
-    "# set the operating condition\n",
-    "condition = Conditions.Dark.AGIPD(memory_cells=mem_cells, \n",
-    "                                  bias_voltage=bias_voltage,\n",
-    "                                  acquisition_rate=acq_rate, \n",
-    "                                  gain_setting=gain_setting,\n",
-    "                                  integration_time=integration_time)\n",
-    "\n",
-    "db_modules = get_pdu_from_db(karabo_id, karabo_da, Constants.AGIPD.SlopesPC(),\n",
-    "                             condition, cal_db_interface,\n",
-    "                             snapshot_at=creation_time)\n",
-    "\n",
-    "for pdu, (qm, r) in zip(db_modules, fres.items()):\n",
-    "    for const in [\"SlopesPC\", \"BadPixelsPC\"]:\n",
-    "\n",
-    "        dbconst = getattr(Constants.AGIPD, const)()\n",
-    "\n",
-    "        if const == \"SlopesPC\":\n",
-    "            dbconst.data = slope_dict_to_arr(r)\n",
-    "        else:\n",
-    "            dbconst.data = bad_pixels[qm]\n",
-    "\n",
-    "        if db_output:\n",
-    "            md = send_to_db(pdu, karabo_id, dbconst, condition,\n",
-    "                            file_loc, report, cal_db_interface,\n",
-    "                            creation_time=creation_time,\n",
-    "                           variant=1)\n",
-    "        # TODO: check if this can replace other written function of this notebook.\n",
-    "        #if local_output:\n",
-    "        #    md = save_const_to_h5(pdu, karabo_id, dconst, condition, dconst.data, \n",
-    "        #                          file_loc, report, creation_time, out_folder)\n",
-    "\n",
-    "print(\"Constants parameter conditions are:\\n\")\n",
-    "print(f\"• memory_cells: {mem_cells}\\n• bias_voltage: {bias_voltage}\\n\"\n",
-    "      f\"• acquisition_rate: {acq_rate}\\n• gain_setting: {gain_setting}\\n\"\n",
-    "      f\"• integration_time: {integration_time}\\n\"\n",
-    "      f\"• creation_time: {md.calibration_constant_version.begin_at if md is not None else creation_time}\\n\")"
-   ]
-  },
   {
    "cell_type": "markdown",
    "metadata": {},
@@ -1944,13 +1854,6 @@
     "    ax.set_xlabel(\"PC scan point (#)\")\n",
     "    ax.grid(lw=1.5)"
    ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": []
   }
  ],
  "metadata": {
diff --git a/notebooks/AGIPD/Chracterize_AGIPD_Gain_PC_Summary.ipynb b/notebooks/AGIPD/Chracterize_AGIPD_Gain_PC_Summary.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..a690dc0c5662465ea645e4ba44859736cb6ba42a
--- /dev/null
+++ b/notebooks/AGIPD/Chracterize_AGIPD_Gain_PC_Summary.ipynb
@@ -0,0 +1,740 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Pulse Capacitor Characterisation Summary\n",
+    "\n",
+    "This notebook is used as a dependency notebook for a pulse capacitor characterisation to provide summary for all modules of the AGIPD."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "in_folder = \"/gpfs/exfel/d/raw/SPB/202331/p900376/\" # path to input data, required\n",
+    "out_folder = \"/gpfs/exfel/exp/SPB/202331/p900376/usr/PC/agipd12/202cells0.5MHz_gs0_20clk/\" # path to output to, required\n",
+    "metadata_folder = \"\"  # Directory containing calibration_metadata.yml when run by xfel-calibrate\n",
+    "runs = [] # runs to use, required, range allowed\n",
+    "\n",
+    "karabo_id_control = \"SPB_IRU_AGIPD1M1\"  # karabo-id for the control device e.g. \"MID_EXP_AGIPD1M1\", or \"SPB_IRU_AGIPD1M1\"\n",
+    "karabo_id = \"SPB_DET_AGIPD1M-1\"\n",
+    "ctrl_source_template = '{}/MDL/FPGA_COMP' # path to control information\n",
+    "\n",
+    "creation_time = \"\" # To overwrite the measured creation_time. Required Format: YYYY-MM-DD HR:MN:SC e.g. \"2022-06-28 13:00:00\"\n",
+    "creation_date_offset = \"00:00:00\" # add an offset to creation date, e.g. to get different constants\n",
+    "cal_db_timeout = 3000000 # timeout on caldb requests\"\n",
+    "cal_db_interface = \"tcp://max-exfl-cal001:8015#8045\"\n",
+    "db_output = False\n",
+    "\n",
+    "bias_voltage = -1  # detector bias voltage, negative values for auto-detection.\n",
+    "mem_cells = -1  # number of memory cells used, negative values for auto-detection.\n",
+    "acq_rate = -1.  # the detector acquisition rate, negative values for auto-detection.\n",
+    "gain_setting = -1  # gain setting can have value 0 or 1, negative values for auto-detection.\n",
+    "integration_time = -1  # integration time, negative values for auto-detection."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import warnings\n",
+    "warnings.filterwarnings('ignore')\n",
+    "\n",
+    "import os\n",
+    "from dateutil import parser\n",
+    "from datetime import timedelta\n",
+    "\n",
+    "import h5py\n",
+    "import matplotlib.pyplot as plt\n",
+    "import matplotlib.gridspec as gridspec\n",
+    "import matplotlib.cm as cm\n",
+    "import numpy as np\n",
+    "import tabulate\n",
+    "import multiprocessing\n",
+    "\n",
+    "from cal_tools.agipdlib import AgipdCtrl\n",
+    "from cal_tools.ana_tools import get_range\n",
+    "from cal_tools.tools import (\n",
+    "    calcat_creation_time,\n",
+    "    module_index_to_qm,\n",
+    "    get_from_db,\n",
+    "    get_pdu_from_db,\n",
+    "    get_report,\n",
+    "    send_to_db\n",
+    ")\n",
+    "\n",
+    "from extra_data import RunDirectory\n",
+    "from extra_geom import AGIPD_1MGeometry, AGIPD_500K2GGeometry\n",
+    "from IPython.display import Latex, display\n",
+    "from XFELDetAna.plotting.simpleplot import simplePlot\n",
+    "\n",
+    "from iCalibrationDB import Conditions, Constants\n",
+    "\n",
+    "%matplotlib inline"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Evaluate creation time\n",
+    "creation_time = calcat_creation_time(in_folder, runs[0], creation_time)\n",
+    "offset = parser.parse(creation_date_offset)\n",
+    "delta = timedelta(hours=offset.hour, minutes=offset.minute, seconds=offset.second)\n",
+    "creation_time += delta\n",
+    "print(f\"Creation time: {creation_time}\\n\")\n",
+    "\n",
+    "# Get operation conditions\n",
+    "ctrl_source = ctrl_source_template.format(karabo_id_control)\n",
+    "run_folder = f'{in_folder}/r{runs[0]:04d}/'\n",
+    "raw_dc = RunDirectory(run_folder)\n",
+    "\n",
+    "# Read operating conditions from AGIPD00 files\n",
+    "instrument_src_mod = [\n",
+    "    s for s in list(raw_dc.all_sources) if \"0CH\" in s][0]\n",
+    "ctrl_src = [\n",
+    "    s for s in list(raw_dc.all_sources) if ctrl_source in s][0]\n",
+    "\n",
+    "agipd_cond = AgipdCtrl(\n",
+    "    run_dc=raw_dc,\n",
+    "    image_src=instrument_src_mod,\n",
+    "    ctrl_src=ctrl_src,\n",
+    "    raise_error=False,  # to be able to process very old data without mosetting value\n",
+    ")\n",
+    "if mem_cells == -1:\n",
+    "    mem_cells = agipd_cond.get_num_cells()\n",
+    "if mem_cells is None:\n",
+    "    raise ValueError(f\"No raw images found in {run_folder}\")\n",
+    "if acq_rate == -1.:\n",
+    "    acq_rate = agipd_cond.get_acq_rate()\n",
+    "if gain_setting == -1:\n",
+    "    gain_setting = agipd_cond.get_gain_setting(creation_time)\n",
+    "if bias_voltage == -1:\n",
+    "    bias_voltage = agipd_cond.get_bias_voltage(karabo_id_control)\n",
+    "if integration_time == -1:\n",
+    "    integration_time = agipd_cond.get_integration_time()\n",
+    "\n",
+    "# Evaluate detector instance for mapping\n",
+    "instrument = karabo_id.split(\"_\")[0]\n",
+    "if instrument == \"HED\":\n",
+    "    nmods = 8\n",
+    "else:\n",
+    "    nmods = 16\n",
+    "\n",
+    "print(f\"Using {creation_time} as creation time\\n\")\n",
+    "print(f\"Operating conditions are:\\n• Bias voltage: {bias_voltage}\\n• Memory cells: {mem_cells}\\n\"\n",
+    "      f\"• Acquisition rate: {acq_rate}\\n• Gain setting: {gain_setting}\\n• Integration time: {integration_time}\\n\"\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [],
+   "source": [
+    "# ml - high gain slope\n",
+    "# bl - high gain intercept\n",
+    "# devl - absolute relative deviation from linearity for high gain\n",
+    "# mh - medium gain slope\n",
+    "# bh - medium gain intercept\n",
+    "# oh, ch, ah - parameters of hook function fit to medium gain (only if requested)\n",
+    "# devh - absolute relative deviation from linearity for linear part of medium gain\n",
+    "\n",
+    "keys = ['ml', 'bl', 'mh', 'bh', 'BadPixelsPC']\n",
+    "keys_file = [\"ml\", \"bl\", \"devl\", \"mh\", \"bh\", \"oh\", \"ch\", \"ah\", \"devh\"]\n",
+    "    \n",
+    "fit_data = {}\n",
+    "bad_pixels = {}\n",
+    "modules = []\n",
+    "karabo_da = []\n",
+    "\n",
+    "for mod in range(nmods):\n",
+    "    qm = module_index_to_qm(mod)\n",
+    "    fit_data[mod] = {}\n",
+    "    constants_file = f'{out_folder}/agipd_pc_store_{\"_\".join([str(run) for run in runs])}_{mod}_{mod}.h5'\n",
+    "    \n",
+    "    if os.path.exists(constants_file):\n",
+    "        print(f'Trying to find: {constants_file}')\n",
+    "        print(f'Data available for module {qm}\\n')\n",
+    "        with h5py.File(constants_file, 'r') as hf:\n",
+    "            bad_pixels[mod] = hf[f'/{qm}/BadPixelsPC/0/data'][()]\n",
+    "            for key in keys_file:\n",
+    "                fit_data[mod][key]= hf[f'/{qm}/{key}/0/data'][()]\n",
+    "        \n",
+    "        modules.append(mod)\n",
+    "        karabo_da.append(f\"AGIPD{mod:02d}\")\n",
+    "    else:\n",
+    "        print(f\"No fit data available for module {qm}\\n\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def slope_dict_to_arr(d):\n",
+    "    key_to_index = {\n",
+    "                    \"ml\": 0,\n",
+    "                    \"bl\": 1,\n",
+    "                    \"devl\": 2,\n",
+    "                    \"mh\": 3,\n",
+    "                    \"bh\": 4,\n",
+    "                    \"oh\": 5,\n",
+    "                    \"ch\": 6,\n",
+    "                    \"ah\": 7,\n",
+    "                    \"devh\": 8,\n",
+    "                    \"tresh\": 9\n",
+    "    }\n",
+    "\n",
+    "    arr = np.zeros([11]+list(d[\"ml\"].shape), np.float32)\n",
+    "    for key, item in d.items():\n",
+    "        if key not in key_to_index:\n",
+    "            continue\n",
+    "        arr[key_to_index[key],...] = item\n",
+    "        \n",
+    "    return arr"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# set the operating condition\n",
+    "condition = Conditions.Dark.AGIPD(memory_cells=mem_cells, \n",
+    "                                  bias_voltage=bias_voltage,\n",
+    "                                  acquisition_rate=acq_rate, \n",
+    "                                  gain_setting=gain_setting,\n",
+    "                                  integration_time=integration_time)\n",
+    "\n",
+    "db_modules = get_pdu_from_db(karabo_id, karabo_da, Constants.AGIPD.SlopesPC(),\n",
+    "                             condition, cal_db_interface,\n",
+    "                             snapshot_at=creation_time)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [],
+   "source": [
+    "proposal = list(filter(None, in_folder.strip('/').split('/')))[-2]\n",
+    "file_loc = proposal + ' ' + ' '.join(list(map(str,runs)))\n",
+    "\n",
+    "report = get_report(metadata_folder)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "md = None\n",
+    "\n",
+    "if db_output:\n",
+    "    for mod, pdu in zip(modules, db_modules):\n",
+    "        for const in [\"SlopesPC\", \"BadPixelsPC\"]:\n",
+    "\n",
+    "            dbconst = getattr(Constants.AGIPD, const)()\n",
+    "\n",
+    "            if const == \"SlopesPC\":\n",
+    "                dbconst.data = slope_dict_to_arr(fit_data[mod])\n",
+    "            else:\n",
+    "                dbconst.data = bad_pixels[mod]\n",
+    "\n",
+    "\n",
+    "            md = send_to_db(pdu, karabo_id, dbconst, condition,\n",
+    "                            file_loc, report, cal_db_interface,\n",
+    "                            creation_time=creation_time,\n",
+    "                           variant=1)\n",
+    "\n",
+    "    print(\"Constants injected with the following conditions:\\n\")\n",
+    "    print(f\"• memory_cells: {mem_cells}\\n• bias_voltage: {bias_voltage}\\n\"\n",
+    "          f\"• acquisition_rate: {acq_rate}\\n• gain_setting: {gain_setting}\\n\"\n",
+    "          f\"• integration_time: {integration_time}\\n\"\n",
+    "          f\"• creation_time: {md.calibration_constant_version.begin_at if md is not None else creation_time}\\n\")\n",
+    "else:\n",
+    "    print('Injection to DB not requested.')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Remove keys which won't be used for comparison plots and add BP to the rest of data \n",
+    "for mod in modules:\n",
+    "    fit_data[mod]['BadPixelsPC'] = bad_pixels[mod]\n",
+    "    \n",
+    "    for key in keys_file:\n",
+    "        if key not in keys:\n",
+    "            del fit_data[mod][key]\n",
+    "            \n",
+    "    for key in keys:\n",
+    "        fit_data[mod][key] = fit_data[mod][key].swapaxes(1,2) "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def retrieve_old_PC(mod):\n",
+    "    dconst = getattr(Constants.AGIPD, 'SlopesPC')()\n",
+    "    old_PC = get_from_db(karabo_id=karabo_id,\n",
+    "            karabo_da=karabo_da[mod],\n",
+    "            constant=dconst,\n",
+    "            condition=condition,\n",
+    "            empty_constant=None,\n",
+    "            cal_db_interface=cal_db_interface,\n",
+    "            creation_time=creation_time-timedelta(seconds=1) if creation_time else None,\n",
+    "            strategy=\"pdu_prior_in_time\",\n",
+    "            verbosity=1,\n",
+    "            timeout=cal_db_timeout)\n",
+    "    return old_PC\n",
+    "\n",
+    "with multiprocessing.Pool(processes=len(modules)) as pool:\n",
+    "    old_PC_consts = pool.map(retrieve_old_PC, range(len(modules)))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Create the arrays that will be used for figures.\n",
+    "# Each array correponds to the data for all processed modules.\n",
+    "\n",
+    "pixel_range = [0,0,512,128]\n",
+    "const_data = {}\n",
+    "old_const = {}\n",
+    "const_order = [0, 1, 3, 4]\n",
+    "\n",
+    "for (key, c) in zip(keys, const_order):\n",
+    "    const_data[key] = np.full((nmods, mem_cells, 512, 128), np.nan)\n",
+    "    old_const[key] = np.full((nmods, mem_cells, 512, 128), np.nan)\n",
+    "    for cnt, i in enumerate(modules):\n",
+    "        if key in fit_data[i]:\n",
+    "            const_data[key][i,:,pixel_range[0]:pixel_range[2],\n",
+    "                               pixel_range[1]:pixel_range[3]] = fit_data[i][key]\n",
+    "            if old_PC_consts[0][0]:\n",
+    "                old_const[key][i,:,pixel_range[0]:pixel_range[2],\n",
+    "                               pixel_range[1]:pixel_range[3]] = old_PC_consts[cnt][0][c].swapaxes(1,2)\n",
+    "\n",
+    "const_data['BadPixelsPC'] = np.full((nmods, mem_cells, 512, 128), np.nan)\n",
+    "for i in modules:\n",
+    "    const_data['BadPixelsPC'][i,:,pixel_range[0]:pixel_range[2],\n",
+    "                              pixel_range[1]:pixel_range[3]] = fit_data[i]['BadPixelsPC']"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "#Define AGIPD geometry\n",
+    "if instrument == \"HED\":\n",
+    "    geom = AGIPD_500K2GGeometry.from_origin()\n",
+    "else:\n",
+    "    geom = AGIPD_1MGeometry.from_quad_positions(quad_pos=[\n",
+    "        (-525, 625),\n",
+    "        (-550, -10),\n",
+    "        (520, -160),\n",
+    "        (542.5, 475),\n",
+    "    ])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Summary across pixels ##\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "gain_data = {'HG': {},\n",
+    "             'MG': {},\n",
+    "             'BP': {}\n",
+    "            }\n",
+    "\n",
+    "old_gain_data = {'HG': {},\n",
+    "                 'MG': {}\n",
+    "                }\n",
+    "      \n",
+    "for key in ['ml', 'bl']:\n",
+    "    gain_data['HG'][key] = const_data[key]\n",
+    "    old_gain_data['HG'][key] = old_const[key]\n",
+    "for key in ['mh', 'bh']:\n",
+    "    gain_data['MG'][key] = const_data[key]\n",
+    "    old_gain_data['MG'][key] = old_const[key]\n",
+    "gain_data['BP']['BadPixelsPC'] = const_data['BadPixelsPC']"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def plot_definition(data, g, key):\n",
+    "    titel = ['Difference to previous', 'Percentage difference']\n",
+    "    gs = gridspec.GridSpec(1, 2)\n",
+    "    fig = plt.figure(figsize=(15, 7))\n",
+    "    plt.suptitle(f'{g}', fontsize=16)\n",
+    "    \n",
+    "    for pos in range(0,2):\n",
+    "        vmin, vmax = get_range(data[pos], 2)\n",
+    "        vmax = max(vmax, abs(vmin))\n",
+    "        ax = fig.add_subplot(gs[0, pos])\n",
+    "        ticks = [-1, 0, 1] if np.isnan(vmin) else [vmin, (vmin+vmax)/2, vmax]\n",
+    "        geom.plot_data_fast(data[pos],\n",
+    "                                vmin=vmin, vmax=vmax, ax=ax, cmap=\"RdBu\", figsize=(13,7),\n",
+    "                                colorbar={'shrink': 1,\n",
+    "                                          'pad': 0.04,\n",
+    "                                          'fraction': 0.1,\n",
+    "                                          \n",
+    "                                         })\n",
+    "        colorbar = ax.images[0].colorbar\n",
+    "        colorbar.ax.set_yticklabels([\"{:.1f}\".format(tk) for tk in colorbar.get_ticks()])\n",
+    "        if pos == 1:\n",
+    "            colorbar.set_label('%')\n",
+    "        ax.set_title(f\"{titel[pos]}: {key}\", fontsize=14)\n",
+    "        ax.set_xlabel(\"Columns\", fontsize=13)\n",
+    "        ax.set_ylabel(\"Rows\", fontsize=13)\n",
+    "\n",
+    "def plot_diff_consts(old_const, new_const, g, ratio=False):\n",
+    "    if ratio:\n",
+    "        old_data = old_const['HG']['ml'] / old_const['MG']['mh']\n",
+    "        new_data = new_const['HG']['ml'] / new_const['MG']['mh']\n",
+    "        data1 = np.nanmean((new_data - old_data), axis=1)\n",
+    "        data2 = np.nanmean((new_data - old_data)/old_data*100, axis=1)\n",
+    "        data = [data1, data2]\n",
+    "        key ='Slopes ratio HG/MG'\n",
+    "        plot_definition(data, g, key)\n",
+    "    else:\n",
+    "        for i, key in enumerate(old_const[g].keys()):\n",
+    "            data1 = np.nanmean((new_const[g][key] - old_const[g][key]), axis=1)\n",
+    "            data2 = np.nanmean((new_const[g][key] - old_const[g][key])/old_const[g][key]*100, axis=1)\n",
+    "            data = [data1, data2]\n",
+    "            plot_definition(data, g, key)\n",
+    "        "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [],
+   "source": [
+    "for gain in old_gain_data.keys():\n",
+    "    plot_diff_consts(old_gain_data, gain_data, gain)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "plot_diff_consts(old_gain_data, gain_data, 'Ratio HG/MG', ratio=True)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "scrolled": false
+   },
+   "outputs": [],
+   "source": [
+    "g_label = ['High gain', 'Medium gain', 'Bad pixels PC']\n",
+    "for idx, g in enumerate(gain_data.keys()):\n",
+    "    gs = gridspec.GridSpec(1, 2)\n",
+    "    fig = plt.figure(figsize=(15, 7))\n",
+    "    plt.suptitle(f'{g_label[idx]}', fontsize=16)\n",
+    "    \n",
+    "    for i, key in enumerate(gain_data[g].keys()):\n",
+    "        if key is 'BadPixelsPC':\n",
+    "            data = np.nanmean(gain_data[g][key]>0, axis=1)\n",
+    "            vmin, vmax = (0,1)\n",
+    "            ax = fig.add_subplot(gs[0, :])\n",
+    "            ticks = [0, 0.5, 1]\n",
+    "            \n",
+    "        else:\n",
+    "            data = np.nanmean(gain_data[g][key], axis=1)\n",
+    "            vmin, vmax = get_range(data, 5)\n",
+    "            ax = fig.add_subplot(gs[0, i])\n",
+    "        geom.plot_data_fast(data,\n",
+    "                                vmin=vmin, vmax=vmax, ax=ax, cmap=\"jet\", figsize=(13,7),\n",
+    "                                colorbar={'shrink': 1,\n",
+    "                                          'pad': 0.04,\n",
+    "                                          'fraction': 0.1,\n",
+    "                                          \n",
+    "                                         })\n",
+    "        colorbar = ax.images[0].colorbar\n",
+    "        ax.set_title(key, fontsize=14)\n",
+    "        ax.set_xlabel('Columns', fontsize=13)\n",
+    "        ax.set_ylabel('Rows', fontsize=13)\n",
+    "        \n",
+    "    plt.show()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Summary across cells ##\n",
+    "\n",
+    "Good pixels only."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "ratio = gain_data['HG']['ml'] / gain_data['MG']['mh']\n",
+    "\n",
+    "fig = plt.figure(figsize=(7, 7))\n",
+    "ax = fig.add_subplot(111)\n",
+    "data = np.nanmean(ratio, axis=1)\n",
+    "vmin, vmax = get_range(data, 5)\n",
+    "ax = geom.plot_data_fast(data,\n",
+    "                                vmin=vmin, vmax=vmax, ax=ax, cmap=\"jet\", figsize=(6,7),\n",
+    "                                colorbar={'shrink': 1,\n",
+    "                                          'pad': 0.04,\n",
+    "                                          'fraction': 0.1\n",
+    "                                         })\n",
+    "colorbar = ax.images[0].colorbar\n",
+    "colorbar.set_label('HG slope / MG slope', fontsize=13)\n",
+    "ax.set_title('High/Medium Gain Slope Ratio', fontsize=14)\n",
+    "ax.set_xlabel('Columns', fontsize=13)\n",
+    "ax.set_ylabel('Rows', fontsize=13)\n",
+    "\n",
+    "plt.show()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [],
+   "source": [
+    "for idx, g in enumerate(gain_data.keys()):\n",
+    "    \n",
+    "    for key in gain_data[g].keys():\n",
+    "        data = np.copy(gain_data[g][key])\n",
+    "        if key=='BadPixelsPC':\n",
+    "            data = data>0\n",
+    "        else:\n",
+    "            data[gain_data['BP']['BadPixelsPC']>0] = np.nan\n",
+    "\n",
+    "        d = []\n",
+    "        for i in range(nmods):\n",
+    "            d.append({'x': np.arange(data[i].shape[0]),\n",
+    "                      'y': np.nanmean(data[i], axis=(1,2)),\n",
+    "                      'drawstyle': 'steps-pre',\n",
+    "                      'label': f'{i}',\n",
+    "                      'linewidth': 2,\n",
+    "                      'linestyle': '--' if i>7 else '-'\n",
+    "                      })\n",
+    "\n",
+    "        fig = plt.figure(figsize=(12, 6))\n",
+    "        plt.suptitle(f'{g_label[idx]} - {key}', fontsize=16)\n",
+    "        ax = fig.add_subplot(111)\n",
+    "\n",
+    "        _ = simplePlot(d, xrange=(-12, 510),\n",
+    "                            x_label='Memory Cell ID',\n",
+    "                            y_label=key,\n",
+    "                            use_axis=ax,\n",
+    "                            legend='top-left-frame-ncol8',)\n",
+    "        ylim = ax.get_ylim()\n",
+    "        ax.set_ylim(ylim[0], ylim[1] + np.abs(ylim[1]-ylim[0])*0.2)\n",
+    "        ax.grid()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "d = []\n",
+    "for i in range(nmods):\n",
+    "    d.append({'x': np.arange(ratio[i].shape[0]),\n",
+    "              'y': np.nanmean(ratio[i], axis=(1,2)),\n",
+    "              'drawstyle': 'steps-pre',\n",
+    "              'label': f'{i}',\n",
+    "              'linewidth': 2,\n",
+    "              'linestyle': '--' if i>7 else '-'\n",
+    "              })\n",
+    "\n",
+    "fig = plt.figure(figsize=(12, 6))\n",
+    "plt.suptitle('High/Medium Gain Slope Ratio', fontsize=16)\n",
+    "ax = fig.add_subplot(111)\n",
+    "\n",
+    "_ = simplePlot(d, xrange=(-12, 510),\n",
+    "                    x_label='Memory Cell ID',\n",
+    "                    y_label='Gain ratio ml/mh',\n",
+    "                    use_axis=ax,\n",
+    "                    legend='top-left-frame-ncol8',)\n",
+    "ylim = ax.get_ylim()\n",
+    "ax.set_ylim(ylim[0], ylim[1] + np.abs(ylim[1]-ylim[0])*0.2)\n",
+    "ax.grid()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "table = []\n",
+    "ratio_old = old_gain_data['HG']['ml'] / old_gain_data['MG']['mh']\n",
+    "for mod in modules:\n",
+    "        \n",
+    "    table.append((mod,\n",
+    "                  f\"{np.nanmean(ratio[mod]):0.1f} +- {np.nanstd(ratio[mod]):0.2f}\",\n",
+    "                  f\"{np.nanmean(ratio_old[mod]):0.1f} +- {np.nanstd(ratio_old[mod]):0.2f}\",\n",
+    "                  f\"{np.nanmean(gain_data['BP']['BadPixelsPC'][mod]>0)*100:0.1f} ({np.nansum(gain_data['BP']['BadPixelsPC'][mod]>0)})\"\n",
+    "                ))\n",
+    "\n",
+    "all_HM = []\n",
+    "all_HM_old = []\n",
+    "for mod in modules:\n",
+    "    all_HM.extend(ratio[mod])\n",
+    "    all_HM_old.extend(ratio_old[mod])\n",
+    "all_HM = np.array(all_HM)\n",
+    "all_HM_old = np.array(all_HM_old)\n",
+    "\n",
+    "all_MSK = np.array([list(msk) for msk in gain_data['BP']['BadPixelsPC']])\n",
+    "\n",
+    "table.append(('overall',\n",
+    "              f\"{np.nanmean(all_HM):0.1f} +- {np.nanstd(all_HM):0.2f}\",\n",
+    "              f\"{np.nanmean(all_HM_old):0.1f} +- {np.nanstd(all_HM_old):0.2f}\",\n",
+    "              f\"{np.nanmean(all_MSK>0)*100:0.1f} ({np.nansum(all_MSK>0)})\"\n",
+    "            ))\n",
+    "\n",
+    "md = display(Latex(tabulate.tabulate(table, tablefmt='latex',\n",
+    "                                     headers=[\"Module\", \n",
+    "                                              \"HG/MG Ratio\",\n",
+    "                                              \"Previous HG/MG Ratio\",\n",
+    "                                              \"Bad pixels [%(Count)]\"])))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Summary high-medium gain ratio (good pixels only) + histograms"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "colors = cm.rainbow(np.linspace(0, 1, nmods))\n",
+    "\n",
+    "gs = gridspec.GridSpec(1, 2)\n",
+    "fig = plt.figure(figsize=(17, 8))\n",
+    "\n",
+    "\n",
+    "ratio[gain_data['BP']['BadPixelsPC'] > 0] = np.nan\n",
+    "data = np.nanmean(ratio, axis=1)\n",
+    "vmin, vmax = get_range(data, 5)\n",
+    "ax = fig.add_subplot(gs[0, 0])\n",
+    "geom.plot_data_fast(data,\n",
+    "                        vmin=vmin, vmax=vmax, ax=ax, cmap=\"jet\", figsize=(12.5,7),\n",
+    "                        colorbar={'shrink': 1,\n",
+    "                                  'pad': 0.04,\n",
+    "                                  'fraction': 0.1\n",
+    "                                 })\n",
+    "colorbar = ax.images[0].colorbar\n",
+    "colorbar.set_label('HG/MG', fontsize=12)\n",
+    "ax.set_xlabel('Columns', fontsize=12)\n",
+    "ax.set_ylabel('Rows', fontsize=12)\n",
+    "\n",
+    "ax = fig.add_subplot(gs[0,1])\n",
+    "for mod in modules:\n",
+    "    h, e = np.histogram(ratio[mod].flatten(), bins=100, range=(vmin, vmax))\n",
+    "    ax.plot(e[:-1], h, color=colors[mod],linewidth=2, label=f'{mod}', alpha=0.8)\n",
+    "    ax.set_xlabel('High/Medium Gain Ratio', fontsize=13)\n",
+    "    ax.set_ylabel('Counts', fontsize=13)\n",
+    "    plt.ticklabel_format(axis='y', style='sci', scilimits=(0,0))\n",
+    "ax.grid()\n",
+    "ax.legend()\n",
+    "plt.show()"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "pycalibration",
+   "language": "python",
+   "name": "python3"
+  },
+  "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.8.11"
+  },
+  "latex_envs": {
+   "LaTeX_envs_menu_present": true,
+   "autocomplete": true,
+   "bibliofile": "biblio.bib",
+   "cite_by": "apalike",
+   "current_citInitial": 1,
+   "eqLabelWithNumbers": true,
+   "eqNumInitial": 1,
+   "hotkeys": {
+    "equation": "Ctrl-E",
+    "itemize": "Ctrl-I"
+   },
+   "labels_anchors": false,
+   "latex_user_defs": false,
+   "report_style_numbering": false,
+   "user_envs_cfg": false
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/src/xfel_calibrate/notebooks.py b/src/xfel_calibrate/notebooks.py
index 63231b4dff9c60cf7a62a808ef06b270da51e7a3..e1f308faab5228ef145cfa19b57f891d43630e4d 100644
--- a/src/xfel_calibrate/notebooks.py
+++ b/src/xfel_calibrate/notebooks.py
@@ -14,6 +14,8 @@ notebooks = {
         },
         "PC": {
             "notebook": "notebooks/AGIPD/Chracterize_AGIPD_Gain_PC_NBC.ipynb",
+            "dep_notebooks": [
+                "notebooks/AGIPD/Chracterize_AGIPD_Gain_PC_Summary.ipynb"],
             "concurrency": {"parameter": "modules",
                             "default concurrency": 16,
                             "cluster cores": 32},