Load the data

!pip install nucleus-cdk==0.5.0rc2 | tail -n2

# Surface a failed install here, rather than as a confusing ModuleNotFoundError
# in the import cell below.
import importlib.metadata as md
assert md.version("nucleus-cdk") == "0.5.0rc2", f"got {md.version('nucleus-cdk')}"
Requirement already satisfied: urllib3<3,>=1.21.1 in /opt/homebrew/Caskroom/miniforge/base/lib/python3.12/site-packages (from requests->panel>=1.0->hvplot<0.12.0,>=0.11.1->nucleus-cdk==0.5.0rc2) (2.5.0)
Requirement already satisfied: certifi>=2017.4.17 in /opt/homebrew/Caskroom/miniforge/base/lib/python3.12/site-packages (from requests->panel>=1.0->hvplot<0.12.0,>=0.11.1->nucleus-cdk==0.5.0rc2) (2025.11.12)
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

from cdk.analysis.cytosol import platereader as pr

# Initialize plotting
pr.plot_setup()

Load the data

Provide a CSV file containing the data, and a platemap. This function returns both the data with the plate map mapped to it, and the platemap by itself, which is useful for certain tasks.

data_file = "data/20251105-labcraft-energy-sweep-01-biotek-cdk.txt"
platemap_file = "data/labcraft-platemap.csv"

data = pr.load_platereader_data(data_file)
data = data[data["Read"] == "GFP-G35"]
data = data.dropna()
data.Well.unique()
array(['A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'D1', 'D2', 'D3', 'D4', 'D5', 'D6', 'E1', 'E2', 'E3', 'E4', 'E5', 'E6', 'F1', 'F2', 'F3', 'F4', 'F5', 'F6', 'G1', 'G2', 'G3', 'G4', 'G5', 'G6', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'I1', 'I2', 'I3', 'I4', 'I5', 'I6', 'J1', 'J2', 'J3', 'J4', 'J5', 'J6', 'K1', 'K2', 'K3', 'K4', 'K5', 'K6', 'L1', 'L2', 'L3', 'L4', 'L5', 'L6', 'M1', 'M2', 'M3', 'M4', 'M5', 'M6', 'N1', 'N2', 'N3', 'N4', 'N5', 'N6', 'O1', 'O2', 'O3', 'O4', 'O5', 'O6', 'P1', 'P2', 'P3', 'P4', 'P5', 'P6'], dtype=object)
data[data.Well == "L5"]
Loading...
platemap = pd.read_csv(platemap_file)

for values, g in platemap.groupby(['Mg Vol (droplets)', 'K Vol (droplets)', 'Water Vol (droplets)']):
    mg, k, water = values
    name = f"Mg {mg}; K {k}"
    platemap.loc[g.index, "Name"] = name

platemap['Type'] = "Sample"

controls = pd.DataFrame(['D5', 'E5', 'F5', 'G5', 'H5', 'I5','J5','K5','L5','M5','N5','O5'], columns=['Well'])
controls['Name'] = [*["1 uM fresh HPTS"]*4, *["10 uM frozen HPTS"]*4, *["10 uM fresh HPTS"]*4]
controls['Type'] = "Standard"


platemap = pd.concat([platemap, controls], ignore_index=True)
platemap.Well.unique()
array(['A1', 'A2', 'A3', 'B1', 'B2', 'B3', 'C1', 'C2', 'C3', 'D1', 'D2', 'D3', 'E1', 'E2', 'E3', 'E4', 'F1', 'F2', 'F3', 'F4', 'G1', 'G2', 'G3', 'G4', 'H1', 'H2', 'H3', 'H4', 'I1', 'I2', 'I3', 'I4', 'J1', 'J2', 'J3', 'J4', 'K1', 'K2', 'K3', 'K4', 'L1', 'L2', 'L3', 'L4', 'M1', 'M2', 'M3', 'M4', 'N1', 'N2', 'N3', 'N4', 'O1', 'O2', 'O3', 'O4', 'P1', 'P2', 'P3', 'P4', 'D5', 'E5', 'F5', 'G5', 'H5', 'I5', 'J5', 'K5', 'L5', 'M5', 'N5', 'O5'], dtype=object)
conc = pd.read_csv("data/concentration_key.csv")
conc.columns = ["Well", "[Mg] (mM)", "[K] (mM)", "Water"]
platemap_full = platemap.merge(conc, how="outer")
platemap_full = platemap_full.drop(columns=['K Vol (droplets)', 'Water Vol (droplets)', "Completed", "Water"])
new_columns = {
    "HEPES": 50,
    "ATP": 2,
    "GTP": 2,
    "CTP": 1,
    "UTP": 1,
    "Creatine phosphate": 20,
    "TCEP": 1,
    "Folinic acid": 0.02,
    "Spermidine": 2,
    "Amino Acid solution": 0.3,
    "tRNA": 3.5,
    "DNA":5,
    "Product":"plamGFP",
    "PPK":0,
    
}
platemap_full = platemap_full.assign(**new_columns)

platemap_full.to_csv("full_platemap_cleaned.csv")
platemap.Well.unique()
array(['A1', 'A2', 'A3', 'B1', 'B2', 'B3', 'C1', 'C2', 'C3', 'D1', 'D2', 'D3', 'E1', 'E2', 'E3', 'E4', 'F1', 'F2', 'F3', 'F4', 'G1', 'G2', 'G3', 'G4', 'H1', 'H2', 'H3', 'H4', 'I1', 'I2', 'I3', 'I4', 'J1', 'J2', 'J3', 'J4', 'K1', 'K2', 'K3', 'K4', 'L1', 'L2', 'L3', 'L4', 'M1', 'M2', 'M3', 'M4', 'N1', 'N2', 'N3', 'N4', 'O1', 'O2', 'O3', 'O4', 'P1', 'P2', 'P3', 'P4', 'D5', 'E5', 'F5', 'G5', 'H5', 'I5', 'J5', 'K5', 'L5', 'M5', 'N5', 'O5'], dtype=object)
data.Well.unique()
array(['A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'D1', 'D2', 'D3', 'D4', 'D5', 'D6', 'E1', 'E2', 'E3', 'E4', 'E5', 'E6', 'F1', 'F2', 'F3', 'F4', 'F5', 'F6', 'G1', 'G2', 'G3', 'G4', 'G5', 'G6', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'I1', 'I2', 'I3', 'I4', 'I5', 'I6', 'J1', 'J2', 'J3', 'J4', 'J5', 'J6', 'K1', 'K2', 'K3', 'K4', 'K5', 'K6', 'L1', 'L2', 'L3', 'L4', 'L5', 'L6', 'M1', 'M2', 'M3', 'M4', 'M5', 'M6', 'N1', 'N2', 'N3', 'N4', 'N5', 'N6', 'O1', 'O2', 'O3', 'O4', 'O5', 'O6', 'P1', 'P2', 'P3', 'P4', 'P5', 'P6'], dtype=object)
data = data.merge(platemap)
data = data.merge(conc, how="outer")
data.Well.unique()
array(['A1', 'A2', 'A3', 'B1', 'B2', 'B3', 'C1', 'C2', 'C3', 'D1', 'D2', 'D3', 'D5', 'E1', 'E2', 'E3', 'E4', 'E5', 'F1', 'F2', 'F3', 'F4', 'F5', 'G1', 'G2', 'G3', 'G4', 'G5', 'H1', 'H2', 'H3', 'H4', 'H5', 'I1', 'I2', 'I3', 'I4', 'I5', 'J1', 'J2', 'J3', 'J4', 'J5', 'K1', 'K2', 'K3', 'K4', 'K5', 'L1', 'L2', 'L3', 'L4', 'L5', 'M1', 'M2', 'M3', 'M4', 'M5', 'N1', 'N2', 'N3', 'N4', 'N5', 'O1', 'O2', 'O3', 'O4', 'O5', 'P1', 'P2', 'P3', 'P4'], dtype=object)

Basic Analysis

Curves

Curves of RFU over time, by named sample.

data[data.Name == "10 uM fresh HPTS"]
Loading...
pr.plot_curves(data) #, hue="Well")
<seaborn.axisgrid.FacetGrid at 0x10d5549b0>
<Figure size 682.688x500 with 1 Axes>
data.Name.unique()
array(['Mg 4; K 17', 'Mg 4; K 34', 'Mg 4; K 51', 'Mg 8; K 17', 'Mg 20; K 51', 'Mg 8; K 34', 'Mg 20; K 34', 'Mg 8; K 51', '1 uM fresh HPTS', 'Mg 20; K 17', 'Mg 12; K 17', 'Mg 16; K 51', 'Mg 12; K 34', 'Mg 16; K 34', 'Mg 12; K 51', 'Mg 16; K 17', '10 uM frozen HPTS', '10 uM fresh HPTS'], dtype=object)
pr.plot_curves(data, hue="[Mg] (mM)", col="[K] (mM)", palette="viridis")
<seaborn.axisgrid.FacetGrid at 0x10f5155b0>
<Figure size 2082.11x500 with 3 Axes>

Steady state

Bar graph of steady-state endpoint of each sample. Steady state is calculated as the maximum fluorescence value over a 3-sample rolling average on the data.

pr.plot_steadystate(data)
<seaborn.axisgrid.FacetGrid at 0x102fe2fc0>
<Figure size 611.111x400 with 1 Axes>
kinetics = pr.kinetic_analysis(data, group_by=["Well", "Read", "[Mg] (mM)", "[K] (mM)", "Experiment"])
kinetics.head()
Loading...
kinetics.to_csv("Mg_K_screen_20251105_fits.csv")
ss = kinetics["Steady State"]["Data"].reset_index().merge(platemap).merge(conc)

sns.catplot(
    data=ss,
    x="[Mg] (mM)",
    y="Data",
    col="[K] (mM)",
    kind="bar"
)
<seaborn.axisgrid.FacetGrid at 0x10f1fc560>
<Figure size 1511.11x500 with 3 Axes>
ss.head()
Loading...
sns.heatmap(
    data=ss.groupby(["[Mg] (mM)", "[K] (mM)"])["Data"].mean().reset_index().pivot(index="[Mg] (mM)", columns="[K] (mM)", values="Data"),
    cmap="viridis",
    square=True
)
<Axes: xlabel='[K] (mM)', ylabel='[Mg] (mM)'>
<Figure size 640x480 with 2 Axes>