Reproducing Pakhomov et al. (2023) from dandiset 000875¶
Paper. Pakhomov AG, Gudvangen E, Mangalanathan U, Kondratiev O, Redondo L, Semenov I (2023). Next generation CANCAN focusing for remote stimulation by nanosecond electric pulses. Bioelectrochemistry 152, 108437. doi:10.1016/j.bioelechem.2023.108437. The claims file was written from the accepted author manuscript in PubMed Central (PMC10247516), with Methods, Results, Discussion and legends; there is no supplement and no linked code.
Dandiset. DANDI:000875, version 0.240515.1925. The paper cites no dandiset or version. This is the only published version, and the draft lists the same nine assets (same asset ids and sizes), so the most recent published version is pinned.
What the dandiset holds. Nine stitched YO-PRO-1 (YP) images of CHO monolayers, one per dish, three dishes each after Packet 2 was rotated 1, 5 or 10 times over the four electrodes (1Px4, 5Px4, 10Px4; 4, 20 or 40 packets), first pulse 3.2 kV. This is the experiment of Fig. 6. The single-cell time-lapse of Fig. 4 and the monolayer experiments of Figs. 5, 7, 8 and 9 are not in it, and the Sim4Life model of Fig. 3 is not public.
Method. Each image is streamed from the archive. The four electrode footprints are found in
an 8 x 8 block-mean overview, and mean intensities are measured in square ROIs along the
diagonals of the full-resolution image, over +/- 1.65 mm from the array center (Methods 2.4, small
array), under every reading the claims file names. The background reading b2 subtracts a dark offset
estimated from the darkest parts of each image, since the electrode footprints turned out to hold
cells. The pixel size is not in the files; 0.65 um
per pixel (camera pixel through the 10x objective) is assumed, and checked against the electrode
geometry. Helper: cancan.py.
| Claim | Status |
|---|---|
| fig6a-more-packets-more-uptake | tested |
| fig6b-peak-relative-to-periphery | tested |
| fig6-trough-half-of-center | tested |
| fig6-peak-narrower | tested |
| fig4-bipolar-cancellation, fig4-twenty-fold-cancellation | blocked: data missing (single-cell time-lapse not in the dandiset) |
| fig5a-packet-without-rotation, fig5bc-rotation-focuses-center | blocked: data missing (Fig. 5 dishes not in the dandiset) |
| fig7ab-amplitude-scales-uptake, fig7-targeting-independent-of-amplitude, fig7-targeting-independent-of-array-size | blocked: data missing (only 3.2 kV, small array, 1Px4 to 10Px4) |
| fig8-packet2-best-targeting, fig8b-normalized-center, fig8-cancellation-predicts-targeting | blocked: data missing (Packets 1 and 3, 4 kV, not in the dandiset; the last also needs Fig. 4) |
| fig9-gap-fades-periphery, fig9b-six-fold-targeting | blocked: data missing (no lifted-array dishes) |
| fig3-field-simulation | blocked: data missing (Sim4Life model not public) |
import os
os.environ.setdefault("OMP_NUM_THREADS", "1")
import time
import warnings
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from scipy import ndimage, stats
import cancan
pd.set_option("display.width", 220)
pd.set_option("display.max_columns", 40)
pd.set_option("display.max_rows", 400)
warnings.filterwarnings("ignore", category=RuntimeWarning)
TREATMENTS = ["1Px4", "5Px4", "10Px4"]
HIST_BINS = np.geomspace(20, 5000, 120) # log-spaced bins for the intensity histograms, a plotting choice
started = time.time()
assets = cancan.list_assets()
dishes = {t: [] for t in TREATMENTS}
for a in assets:
meta = cancan.read_metadata(a["asset_id"])
overview = cancan.load_overview(a["asset_id"])
electrodes = cancan.find_electrodes(overview)
geo = cancan.geometry(electrodes)
region, origin = cancan.load_region(a["asset_id"], geo["center"], 2700)
profiles = cancan.dish_profiles(region, origin, electrodes)
half_geo = cancan.geometric_half_span(electrodes)
profiles_geo = cancan.dish_profiles(region, origin, electrodes, half_geo)
k = 32 # an 80 x 80 thumbnail (blocks of 256 x 256 pixels), kept for the duplicate check and the figure
h = overview.shape[0] // k * k
thumb = overview[:h, :h].reshape(h // k, k, h // k, k).mean(axis=(1, 3))
zones = cancan.zone_values(overview, electrodes)
dark = cancan.dark_level(overview)
# Blocks whose 3 x 3 neighbourhood is all nonzero cannot straddle the zero padding; the dark level from them alone is a check.
interior = ndimage.binary_erosion(overview > 0, np.ones((3, 3)), border_value=0)
dark_interior = float(np.percentile(overview[interior], 1.0))
dark_touch = float((~interior[(overview > 0) & (overview <= dark)]).mean())
R = np.mean([np.hypot(e["row"] - geo["center"][0], e["col"] - geo["center"][1]) for e in electrodes])
dy, dx = np.nonzero((overview > 0) & (overview <= dark))
dark_far = float((np.hypot(dy * cancan.BLOCK - geo["center"][0], dx * cancan.BLOCK - geo["center"][1]) > 2 * R).mean())
# The array area of the overview (8 x 8 blocks) and a full-resolution crop of footprint 0 and its rim, for the figures.
cb = (geo["center"] / cancan.BLOCK).astype(int)
hw = int(1.45 * np.max([np.hypot(e["row"] - geo["center"][0], e["col"] - geo["center"][1]) for e in electrodes]) / cancan.BLOCK)
array_crop = overview[max(0, cb[0] - hw):cb[0] + hw, max(0, cb[1] - hw):cb[1] + hw].copy()
e0 = electrodes[0]
fp_crop, fp_origin = cancan.load_region(a["asset_id"], (e0["row"], e0["col"]), int(1.6 * e0["radius"]))
# Full-resolution 600 x 600 patches: the footprint center, and the monolayer 1.25 radii out, away from the array.
u = np.array([e0["row"], e0["col"]]) - geo["center"]
u /= np.linalg.norm(u)
patches = {}
for name, p in {"footprint": (e0["row"], e0["col"]), "outside": np.array([e0["row"], e0["col"]]) + 1.25 * e0["radius"] * u}.items():
py, px = int(p[0]) - fp_origin[0], int(p[1]) - fp_origin[1]
patches[name] = fp_crop[py - 300:py + 300, px - 300:px + 300].copy()
s4 = fp_crop.shape[0] // 4 * 4, fp_crop.shape[1] // 4 * 4
fp_small = fp_crop[:s4[0], :s4[1]].reshape(s4[0] // 4, 4, s4[1] // 4, 4).mean(axis=(1, 3))
dishes[a["treatment"]].append({
**a, "meta": meta, "electrodes": electrodes, "geometry": geo, "profiles": profiles,
"profiles_geo": profiles_geo, "half_span_geo_mm": half_geo * cancan.PIXEL_UM / 1000,
"footprint": cancan.footprint_level(overview, electrodes),
"dark": dark, "dark_far_fraction": dark_far, "dark_interior": dark_interior, "dark_touch_zero": dark_touch, "region_min": float(region.min()),
"dark_q": {q: cancan.dark_level(overview, q) for q in (0.1, 1.0, 5.0)},
"zone_hist": {z: np.histogram(v, HIST_BINS)[0] for z, v in zones.items()},
"zone_n": {z: len(v) for z, v in zones.items()},
"zone_pct": {z: np.percentile(v, [1, 5, 50, 95, 99]) for z, v in zones.items()},
"overview_stats": {"min": float(overview.min()), "max": float(overview.max()),
"median_nonzero": float(np.median(overview[overview > 0])),
"zero_fraction": float((overview == 0).mean())},
"region_stats": {"min": int(region.min()), "max": int(region.max()), "median": float(np.median(region)),
"near_ceiling_fraction": float((region >= 65000).mean())},
"thumb": thumb, "array_crop": array_crop, "array_crop_origin": (max(0, cb[0] - hw), max(0, cb[1] - hw)),
"fp_small": fp_small, "fp_crop_origin": fp_origin, "patches": patches,
})
del overview, region, fp_crop
print(f"loaded {len(assets)} files from dandiset {cancan.DANDISET_ID} version {cancan.DANDISET_VERSION} "
f"in {time.time() - started:.0f} s")
loaded 9 files from dandiset 000875 version 0.240515.1925 in 260 s
Data check¶
Each check of the metadata against the values is stated under its output.
rows = []
for t in TREATMENTS:
for d in dishes[t]:
m = d["meta"]
desc = m["session_description"]
cycles = int(desc.split("A total of ")[1].split(" cycles")[0])
kv = float(desc.split("single ")[1].split(" kV")[0])
rows.append({"treatment": t, "dish": d["dish"], "subject_id": m["subject_id"],
"cycles_in_description": cycles, "kV_in_description": kv, "kV_in_name": d["kv_from_name"],
"session_start": m["session_start_time"], "species": m["species"].split("/")[-1],
"strain": m["strain"], "age": m["age"], "shape": m["shape"], "unit": m["unit"],
"rate_Hz": m["rate"], "series": m["series_fields"], "size_MB": round(d["size"] / 1e6)})
info = pd.DataFrame(rows)
print("Files per treatment:", info.treatment.value_counts().reindex(TREATMENTS).to_dict())
print(info.drop(columns=["series"]).to_string(index=False))
print("\nPacket cycles in the description equal the packets per electrode in the name:",
bool((info.cycles_in_description == info.treatment.str[:-3].astype(int)).all()))
print("First-pulse voltage in every description:", sorted(info.kV_in_description.unique()), "kV; in the names:",
sorted(info.kV_in_name.unique()))
print("Fields of the ImageSeries:", info.series.iloc[0], "; groups in the file:", dishes["1Px4"][0]["meta"]["groups"])
shared = info.groupby("session_start").dish.apply(list)
print("\nSession start times shared by more than one dish:", shared[shared.map(len) > 1].to_dict())
print("Device description:", dishes["1Px4"][0]["meta"]["device_description"])
print("Experimenter:", dishes["1Px4"][0]["meta"]["experimenter"])
vm = cancan.version_metadata()
summ = vm["assetsSummary"]
print("\nArchive summary of the version: numberOfFiles", summ["numberOfFiles"], "; numberOfSubjects", summ["numberOfSubjects"],
"; species", [x["name"] for x in summ.get("species", [])], "; distinct subject ids in the files", info.subject_id.nunique())
print("Dandiset description:", vm["description"])
Files per treatment: {'1Px4': 3, '5Px4': 3, '10Px4': 3}
treatment dish subject_id cycles_in_description kV_in_description kV_in_name session_start species strain age shape unit rate_Hz size_MB
1Px4 23 1p_x4_600ns_200ms_3,2kV_YP_(dish23) 1 3.2 3.2 2021-02-16T17:03:39-05:00 NCBITaxon_9913 cellline: CHO P1D (1, 20480, 20480) n.a. 2.0 378
1Px4 24 1p_x4_600ns_200ms_3,2kV_YP_(dish24) 1 3.2 3.2 2021-02-16T17:09:42-05:00 NCBITaxon_9913 cellline: CHO P1D (1, 20480, 20480) n.a. 2.0 385
1Px4 25 1p_x4_600ns_200ms_3,2kV_YP_(dish25) 1 3.2 3.2 2021-02-16T17:15:04-05:00 NCBITaxon_9913 cellline: CHO P1D (1, 20480, 20480) n.a. 2.0 371
5Px4 9 5p_x4_600ns_200ms_3,2kV_YP_(dish09) 5 3.2 3.2 2021-02-16T17:15:04-05:00 NCBITaxon_9913 cellline: CHO P1D (1, 20480, 20480) n.a. 2.0 407
5Px4 20 5p_x4_600ns_200ms_3,2kV_YP_(dish20) 5 3.2 3.2 2021-02-16T16:50:24-05:00 NCBITaxon_9913 cellline: CHO P1D (1, 20480, 20480) n.a. 2.0 413
5Px4 22 5p_x4_600ns_200ms_3,2kV_YP_(dish22) 5 3.2 3.2 2021-02-16T16:50:24-05:00 NCBITaxon_9913 cellline: CHO P1D (1, 20480, 20480) n.a. 2.0 394
10Px4 4 10p_x4_600ns_200ms_3,2kV_YP_(dish04) 10 3.2 3.2 2021-02-16T13:39:45-05:00 NCBITaxon_9913 cellline: CHO P1D (1, 20480, 20480) n.a. 2.0 419
10Px4 11 10p_x4_600ns_200ms_3,2kV_YP_(dish11) 10 3.2 3.2 2021-02-16T14:38:33-05:00 NCBITaxon_9913 cellline: CHO P1D (1, 20480, 20480) n.a. 2.0 421
10Px4 18 10p_x4_600ns_200ms_3,2kV_YP_(dish18) 10 3.2 3.2 2021-02-16T16:21:42-05:00 NCBITaxon_9913 cellline: CHO P1D (1, 20480, 20480) n.a. 2.0 421
Packet cycles in the description equal the packets per electrode in the name: True
First-pulse voltage in every description: [np.float64(3.2)] kV; in the names: [np.float64(3.2)]
Fields of the ImageSeries: ['data', 'starting_time'] ; groups in the file: ['acquisition', 'analysis', 'file_create_date', 'general', 'identifier', 'processing', 'session_description', 'session_start_time', 'specifications', 'stimulus', 'timestamps_reference_time']
Session start times shared by more than one dish: {'2021-02-16T16:50:24-05:00': [20, 22], '2021-02-16T17:15:04-05:00': [25, 9]}
Device description: IX83 microscope used; MS-2000 scanning stage; X-Cite 110LED illuminator; ORCA-Flash4 sCMOS camera;CellSens software for automation; ex/em 480/535nm for detecting electroporation using 1uM YOPRO-1; dark circles indicate electrode footprints; 144 images captured in a 12x12 grid from a six-well plate; all images automatically stitched for a final composite; 10×, 0.38NA objective used for high-resolution imaging.
Experimenter: ['Iurii Semenov']
Archive summary of the version: numberOfFiles 9 ; numberOfSubjects 18 ; species ['Bos taurus - Cattle'] ; distinct subject ids in the files 9 Dandiset description: This data provides images of Yo-Pro uptake when different numbers of nanosecond electric pulse packets were applied in a four-electrode array. Increasing the total number of applied packets from 4 to 20 and 40 significantly enhanced the electroporative effect across the electrode array. The peak of electroporation at the center was clearly distinguishable for all tested treatments. The study was supported in part by NIH R21EY034258
The nine files are three dishes each of 1Px4, 5Px4 and 10Px4 (Packet 2 applied 1, 5 or 10 times from each electrode, 4, 20 or 40 packets in all), first pulse 3.2 kV, as the session descriptions say and the file names agree. This is the experiment of Fig. 6 (Results 3.3, paragraph 1); the legend gives n = 3 to 4, and the dandiset has 3 per treatment. Each file holds one stitched image and nothing else: no ROI table, no pixel size, no electrode positions. The species is NCBITaxon 9913 (Bos taurus, cattle), while the strain field and the paper say CHO cells (Chinese hamster); the age "P1D" has no meaning for a cell line. The ImageSeries has unit "n.a." and a rate of 2 Hz for a single frame. Two pairs of dishes share a session start time to the second, one pair across treatments (dish 09 of 5Px4 and dish 25 of 1Px4); the images themselves differ (checked below), so the start times are not acquisition times of each dish. The "200ms" in every file name is not explained; packets were given at 1 Hz.
rows = []
for t in TREATMENTS:
for d in dishes[t]:
rows.append({"treatment": t, "dish": d["dish"], **{f"overview_{k}": round(v, 3) for k, v in d["overview_stats"].items()},
**{f"region_{k}": round(v, 5) if isinstance(v, float) else v for k, v in d["region_stats"].items()},
"footprint_median": round(d["footprint"], 1),
**{f"dark_p{q:g}": round(v, 1) for q, v in d["dark_q"].items()},
"roi_saturated_max": max(float(p["saturated"].max()) for p in d["profiles"].values())})
vals = pd.DataFrame(rows)
print("Intensities are uint16 camera counts (unit 'n.a.', conversion 1, offset 0).")
print("overview_*: 8 x 8 block means of the whole 20480 x 20480 image; region_*: the full-resolution square around the array center;")
print("dark_p*: percentiles of the nonzero block means of the whole image.")
print(vals.to_string(index=False))
Intensities are uint16 camera counts (unit 'n.a.', conversion 1, offset 0).
overview_*: 8 x 8 block means of the whole 20480 x 20480 image; region_*: the full-resolution square around the array center;
dark_p*: percentiles of the nonzero block means of the whole image.
treatment dish overview_min overview_max overview_median_nonzero overview_zero_fraction region_min region_max region_median region_near_ceiling_fraction footprint_median dark_p0.1 dark_p1 dark_p5 roi_saturated_max
1Px4 23 0.0 65434.859 278.562 0.259 110 65440 509.0 0.00001 295.2 58.6 73.5 102.1 0.000000
1Px4 24 0.0 64654.812 278.344 0.259 118 65442 482.0 0.00001 265.9 59.0 86.7 153.1 0.000000
1Px4 25 0.0 57509.406 228.469 0.259 110 65437 411.0 0.00000 238.5 58.2 76.2 99.2 0.000000
5Px4 9 0.0 65435.312 338.547 0.259 171 65442 1180.0 0.00007 349.7 59.9 76.7 121.9 0.005131
5Px4 20 0.0 65434.969 297.812 0.258 129 65445 1727.0 0.00018 312.0 58.5 78.5 115.1 0.007225
5Px4 22 0.0 59244.906 258.719 0.258 160 64855 973.0 0.00000 292.8 58.5 73.8 107.9 0.000000
10Px4 4 0.0 65435.109 309.859 0.258 186 65445 2330.0 0.00085 332.8 60.7 87.1 122.9 0.024951
10Px4 11 0.0 65435.281 364.469 0.258 200 65446 1964.0 0.00072 402.8 59.5 81.0 107.9 0.049589
10Px4 18 0.0 65391.750 294.859 0.258 173 65447 2798.0 0.00034 365.5 58.5 81.3 104.0 0.009849
Pixels are 16-bit counts; the zero pixels (26% of each image) are the padding outside the
stitched tiles. The brightest pixels reach about 65440, the ceiling of these images; the fraction
of pixels at or above 65000 in the central region is printed as region_near_ceiling_fraction,
and the largest such fraction in any ROI as roi_saturated_max: none in 1Px4, up to 5.0% of
an ROI in 10Px4, so the brightest 10Px4 ROIs, near the electrodes, are slightly capped. This
lowers the 10Px4 periphery, which works against the order tested in fig6a. The median inside the
electrode footprints is 239 to 403 counts; the darkest pixel of the central region is 110 to 200
counts; the 1st percentile of each image's nonzero block means is 73.5 to 87.1 counts (0.1st
percentile 58.2 to 60.7, 5th 99.2 to 153.1). These are the candidate background levels examined
below.
rows = []
for t in TREATMENTS:
for d in dishes[t]:
g = d["geometry"]
rows.append({"treatment": t, "dish": d["dish"], "center_row": round(g["center"][0]), "center_col": round(g["center"][1]),
"footprint_diam_mm": np.round(g["footprint_diameter_mm"], 2).tolist(),
"diag_center_to_center_mm": np.round(g["diag_cc_mm"], 2).tolist(),
"diag_between_footprints_mm": np.round(g["diag_inner_mm"], 2).tolist(),
"sides_mm": np.round(g["side_cc_mm"], 2).tolist()})
geo = pd.DataFrame(rows)
print(f"Distances at the assumed {cancan.PIXEL_UM} um per pixel:")
print(geo.to_string(index=False))
inner = np.concatenate([d["geometry"]["diag_inner_mm"] for t in TREATMENTS for d in dishes[t]])
diam = np.concatenate([d["geometry"]["footprint_diameter_mm"] for t in TREATMENTS for d in dishes[t]])
cc = np.concatenate([d["geometry"]["diag_cc_mm"] for t in TREATMENTS for d in dishes[t]])
print(f"\nFootprint diameter {diam.min():.2f} to {diam.max():.2f} mm (median {np.median(diam):.2f}); needle diameter 1.5 mm (Methods 2.3).")
print(f"Diagonal between footprint edges {inner.min():.2f} to {inner.max():.2f} mm.")
print(f"Small array: ROIs cover +/- 1.65 mm = 3.30 mm; the margin left at each end is {(inner.min() - 3.3) / 2:.2f} to {(inner.max() - 3.3) / 2:.2f} mm,"
f" {100 * (inner.min() - 3.3) / 2 / inner.min():.1f}% to {100 * (inner.max() - 3.3) / 2 / inner.max():.1f}% of the diagonal (Methods 2.4: '<5% of the diagonal length' excluded).")
print(f"Large array: ROIs cover +/- 3.65 mm = 7.30 mm, more than the {inner.max():.2f} mm between footprints at this scale.")
hg = [d["half_span_geo_mm"] for t in TREATMENTS for d in dishes[t]]
print(f"Variant extent, 5% of the footprint-to-footprint diagonal short of each footprint: +/- {min(hg):.2f} to {max(hg):.2f} mm at this scale (main: +/- 1.65 mm).")
# Scale check against the array sizes of the paper (Methods 2.3, 2.4; Section 3.5).
print("\nScale check. The paper: large array 8.4 mm diagonal (Section 3.5); 'approximately a 2-fold size difference' (Methods 2.3);")
print("needles 1.5 mm (Methods 2.3); ROIs over +/- 1.65 mm (small) and +/- 3.65 mm (large), '<5% of the diagonal length' excluded (Methods 2.4).")
print(f" If 8.4 mm were center to center, the large array would leave {8.4 - 1.5:.2f} mm between needle edges, less than its own 7.30 mm of ROIs;"
" so the paper's ROI extent fits only if the diagonal is read between needle edges.")
print(f" Read between needle edges, the large array's ROIs leave {100 * (8.4 - 7.3) / 2 / 8.4:.1f}% of the diagonal at each end; the same"
f" proportion gives a small-array diagonal of {3.3 / (7.3 / 8.4):.2f} mm, and half of 8.4 mm is 4.20 mm.")
for scale in [cancan.PIXEL_UM, 0.53]:
f = scale / cancan.PIXEL_UM
edge = cc * f - 1.5
print(f" At {scale} um per pixel: center-to-center diagonal {cc.min() * f:.2f} to {cc.max() * f:.2f} mm; between 1.5-mm needle edges"
f" {edge.min():.2f} to {edge.max():.2f} mm; between dark footprint edges {inner.min() * f:.2f} to {inner.max() * f:.2f} mm;"
f" the 3.30 mm of small-array ROIs fit between the footprints: {bool(inner.min() * f > 3.3)}.")
scale_needle = 1.5 / np.median(diam) * cancan.PIXEL_UM
print(f" Scale that makes the median footprint exactly 1.5 mm: {scale_needle:.3f} um per pixel; scale that makes the center-to-center diagonal"
f" 4.2 mm (half of 8.4 mm read center to center): {4.2 / np.median(cc) * cancan.PIXEL_UM:.3f} um per pixel.")
Distances at the assumed 0.65 um per pixel:
treatment dish center_row center_col footprint_diam_mm diag_center_to_center_mm diag_between_footprints_mm sides_mm
1Px4 23 9701 9559 [1.72, 1.84, 1.83, 1.83] [5.24, 5.32] [3.47, 3.48] [3.58, 3.7, 3.92, 3.74]
1Px4 24 10368 8506 [1.81, 1.82, 1.68, 1.79] [5.35, 5.31] [3.6, 3.5] [3.72, 3.69, 3.89, 3.78]
1Px4 25 9911 8456 [1.95, 1.87, 1.66, 1.75] [5.4, 5.35] [3.6, 3.55] [3.78, 3.73, 3.88, 3.82]
5Px4 9 8392 7519 [1.88, 1.8, 1.7, 1.77] [5.28, 5.23] [3.49, 3.45] [3.66, 3.72, 3.84, 3.65]
5Px4 20 10929 9161 [2.06, 1.93, 1.91, 1.9] [5.4, 5.35] [3.42, 3.43] [3.6, 3.87, 3.98, 3.77]
5Px4 22 10426 10119 [1.92, 1.88, 1.8, 1.88] [5.37, 5.42] [3.52, 3.54] [3.7, 3.86, 3.86, 3.85]
10Px4 4 10303 8172 [2.09, 1.87, 1.79, 1.8] [5.34, 5.44] [3.4, 3.61] [3.68, 3.8, 3.99, 3.79]
10Px4 11 10906 9009 [1.96, 1.85, 1.77, 1.81] [5.29, 5.38] [3.43, 3.55] [3.56, 3.8, 3.98, 3.77]
10Px4 18 11462 9565 [1.96, 1.76, 1.7, 1.91] [5.43, 5.55] [3.59, 3.71] [3.71, 3.92, 3.92, 3.98]
Footprint diameter 1.66 to 2.09 mm (median 1.83); needle diameter 1.5 mm (Methods 2.3).
Diagonal between footprint edges 3.40 to 3.71 mm.
Small array: ROIs cover +/- 1.65 mm = 3.30 mm; the margin left at each end is 0.05 to 0.21 mm, 1.5% to 5.6% of the diagonal (Methods 2.4: '<5% of the diagonal length' excluded).
Large array: ROIs cover +/- 3.65 mm = 7.30 mm, more than the 3.71 mm between footprints at this scale.
Variant extent, 5% of the footprint-to-footprint diagonal short of each footprint: +/- 1.54 to 1.64 mm at this scale (main: +/- 1.65 mm).
Scale check. The paper: large array 8.4 mm diagonal (Section 3.5); 'approximately a 2-fold size difference' (Methods 2.3);
needles 1.5 mm (Methods 2.3); ROIs over +/- 1.65 mm (small) and +/- 3.65 mm (large), '<5% of the diagonal length' excluded (Methods 2.4).
If 8.4 mm were center to center, the large array would leave 6.90 mm between needle edges, less than its own 7.30 mm of ROIs; so the paper's ROI extent fits only if the diagonal is read between needle edges.
Read between needle edges, the large array's ROIs leave 6.5% of the diagonal at each end; the same proportion gives a small-array diagonal of 3.80 mm, and half of 8.4 mm is 4.20 mm.
At 0.65 um per pixel: center-to-center diagonal 5.23 to 5.55 mm; between 1.5-mm needle edges 3.73 to 4.05 mm; between dark footprint edges 3.40 to 3.71 mm; the 3.30 mm of small-array ROIs fit between the footprints: True.
At 0.53 um per pixel: center-to-center diagonal 4.27 to 4.53 mm; between 1.5-mm needle edges 2.77 to 3.03 mm; between dark footprint edges 2.78 to 3.03 mm; the 3.30 mm of small-array ROIs fit between the footprints: False.
Scale that makes the median footprint exactly 1.5 mm: 0.532 um per pixel; scale that makes the center-to-center diagonal 4.2 mm (half of 8.4 mm read center to center): 0.510 um per pixel.
The files give no pixel size. At 0.65 um per pixel (the 6.5 um pixel of the ORCA-Flash4 camera through the 10x objective, both named in the file's device description and Methods 2.4), the four footprints sit on a near square with 5.23 to 5.55 mm center-to-center diagonals and 3.40 to 3.71 mm between the dark footprint edges. The small array's +/- 1.65 mm of ROIs then fits between the footprints with 1.5 to 5.6% of the diagonal left at each end, so in the narrowest dishes the outer ROIs reach into the 5% the Methods exclude (the variant that sets the ROI extent from the footprints avoids this), and the large array's +/- 3.65 mm does not fit at all, so the images are of the small array.
Two cues point to a smaller scale. The dark footprints are 1.66 to 2.09 mm across, against 1.5-mm needles (0.532 um per pixel would make the median footprint 1.5 mm), and half of the large array's 8.4 mm diagonal, read center to center, is 4.2 mm (0.510 um per pixel). The scale check above weighs them against the paper's own ROI extent. Read center to center, 8.4 mm would leave 6.90 mm between the large array's needles, less than the 7.30 mm its ROIs cover, so the paper's diagonal is between needle edges; on that reading the large array's ROIs leave 6.5% of it at each end, and the same proportion gives a small-array diagonal of 3.80 mm (half of 8.4 mm is 4.20 mm). At 0.65 um per pixel the small array measures 3.73 to 4.05 mm between 1.5-mm needle edges, which agrees; at 0.53 um it measures 2.77 to 3.03 mm, too short for the paper's 3.30 mm of ROIs. So the camera scale is kept, as an assumption, and the dark footprints are taken to be wider than the needles. The variant that sets the ROI extent from the footprints uses no pixel size, and each claim gives its outcome under it.
names = [(t, d["dish"]) for t in TREATMENTS for d in dishes[t]]
thumbs = [np.log(np.clip(d["thumb"], 1, None)) for t in TREATMENTS for d in dishes[t]]
corr = np.array([[np.corrcoef(a.ravel(), b.ravel())[0, 1] for b in thumbs] for a in thumbs])
identical = [(names[i], names[j]) for i in range(len(thumbs)) for j in range(i + 1, len(thumbs))
if np.array_equal(thumbs[i], thumbs[j])]
print("Pairs of identical images:", identical if identical else "none")
off = corr[~np.eye(len(corr), dtype=bool)]
print(f"Correlation of log thumbnails between different dishes: {off.min():.3f} to {off.max():.3f}")
centers = np.array([d["geometry"]["center"] for t in TREATMENTS for d in dishes[t]])
print("Array centers (row, col) differ between dishes:", len({tuple(np.round(c, -1)) for c in centers}) == len(centers))
pair_corr = {f"{names[i][0]} dish{names[i][1]} / {names[j][0]} dish{names[j][1]}": round(corr[i, j], 3)
for i in range(len(names)) for j in range(i + 1, len(names))
if {names[i][1], names[j][1]} in ({20, 22}, {9, 25})}
print("Dishes that share a session start time, correlation of thumbnails:", pair_corr)
fig, axes = plt.subplots(3, 3, figsize=(12, 12))
for ax, (t, d) in zip(axes.flat, [(t, d) for t in TREATMENTS for d in dishes[t]]):
th = d["thumb"]
ax.imshow(np.clip(th, 0, np.percentile(th[th > 0], 99)), cmap="gray")
c = np.array([[e["row"], e["col"]] for e in d["electrodes"]]) / 256
for e in d["electrodes"]:
ax.add_patch(plt.Circle((e["col"] / 256, e["row"] / 256), e["radius"] / 256, fill=False, color="y"))
cen = c.mean(0)
half = cancan.HALF_SPAN_MM * 1000 / cancan.PIXEL_UM / 256
for a_, b_ in [(0, 2), (1, 3)]:
u = (c[b_] - c[a_]) / np.linalg.norm(c[b_] - c[a_])
ax.plot([cen[1] - half * u[1], cen[1] + half * u[1]], [cen[0] - half * u[0], cen[0] + half * u[0]], "c-", lw=1)
ax.set_title(f"{t} dish {d['dish']}", fontsize=9)
ax.set_xticks([]); ax.set_yticks([])
plt.suptitle("Thumbnails (blocks of 256 x 256 pixels), detected footprints (yellow) and the ROI lines (cyan)")
plt.tight_layout(); plt.show()
print("Display: each thumbnail clipped at its 99th percentile of nonzero blocks.")
Pairs of identical images: none
Correlation of log thumbnails between different dishes: 0.943 to 0.997
Array centers (row, col) differ between dishes: True
Dishes that share a session start time, correlation of thumbnails: {'1Px4 dish25 / 5Px4 dish9': np.float64(0.983), '5Px4 dish20 / 5Px4 dish22': np.float64(0.981)}
Display: each thumbnail clipped at its 99th percentile of nonzero blocks.
No two images are identical, and the array sits at a different place in each, so no recording was deposited twice; the shared start times are a metadata problem only. The footprints and ROI lines drawn on the thumbnails show the detection. Which electrode is e1 cannot be told from the images, but every treatment here rotates the packet over all four electrodes, so the diagonals are equivalent; diagonal A joins footprints 0 and 2 in the order of their angle around the center.
There is no time axis or trial table to align: each file is one image taken after the treatment. The check that the treatment labels belong to the images is the expected contrast between treatments, which is the subject of the first claim below.
What the electrode footprints hold, and the dark offset¶
Reading b2 of the claims file subtracts "a cell-free or dark offset, where the data hold one". The first round used the median inside the dark electrode footprints. The cells below show what the footprints hold at full resolution, the intensity distributions of the footprints, of the monolayer outside the array and of the exposed area between the electrodes, and where the darkest blocks of each image lie.
from scipy.ndimage import gaussian_filter
alld = [(t, d) for t in TREATMENTS for d in dishes[t]]
fig, axes = plt.subplots(3, 3, figsize=(13, 13))
for ax, (t, d) in zip(axes.flat, alld):
im = d["array_crop"]
o = d["array_crop_origin"]
ax.imshow(np.log(np.clip(im, 1, None)), cmap="gray", vmin=np.log(np.percentile(im[im > 0], 1)), vmax=np.log(np.percentile(im[im > 0], 99.5)))
c = np.array([[e["row"], e["col"]] for e in d["electrodes"]]) / cancan.BLOCK - np.array(o)
for e in d["electrodes"]:
ax.add_patch(plt.Circle((e["col"] / cancan.BLOCK - o[1], e["row"] / cancan.BLOCK - o[0]), e["radius"] / cancan.BLOCK, fill=False, color="y", lw=0.8))
cen = c.mean(0)
half = cancan.HALF_SPAN_MM * 1000 / cancan.PIXEL_UM / cancan.BLOCK
for a_, b_ in [(0, 2), (1, 3)]:
u = (c[b_] - c[a_]) / np.linalg.norm(c[b_] - c[a_])
ax.plot([cen[1] - half * u[1], cen[1] + half * u[1]], [cen[0] - half * u[0], cen[0] + half * u[0]], "c-", lw=0.8)
ax.set_title(f"{t} dish {d['dish']}", fontsize=9); ax.set_xticks([]); ax.set_yticks([])
plt.suptitle("Array area at 8 x 8 block resolution (5.2 um per block at the assumed scale), log scale, clipped at the 1st and 99.5th percentiles:\n"
"fitted footprint circles (yellow) and the ROI lines over +/- 1.65 mm (cyan)")
plt.tight_layout(); plt.show()
fig, axes = plt.subplots(3, 3, figsize=(13, 13))
for ax, (t, d) in zip(axes.flat, alld):
im = d["fp_small"]
o = d["fp_crop_origin"]
e = d["electrodes"][0]
ax.imshow(im, cmap="gray", vmin=np.percentile(im, 1), vmax=np.percentile(im, 99.5))
ax.add_patch(plt.Circle(((e["col"] - o[1]) / 4, (e["row"] - o[0]) / 4), e["radius"] / 4, fill=False, color="y", lw=0.8))
ax.set_title(f"{t} dish {d['dish']}: footprint 0", fontsize=9); ax.set_xticks([]); ax.set_yticks([])
plt.suptitle("Footprint 0 of each dish and its rim (full resolution shown in 4 x 4 pixel means), linear scale clipped at the 1st and 99.5th percentiles")
plt.tight_layout(); plt.show()
fig, axes = plt.subplots(3, 6, figsize=(18, 9.5))
rows = []
for k, (t, d) in enumerate(alld):
for j, name in enumerate(["footprint", "outside"]):
z = d["patches"][name]
ax = axes.flat[2 * k + j]
ax.imshow(z, cmap="gray", vmin=np.percentile(z, 1), vmax=np.percentile(z, 95))
ax.set_title(f"{t} d{d['dish']}: {name}", fontsize=8); ax.set_xticks([]); ax.set_yticks([])
# Band-pass (difference of Gaussians, sigma 3 and 15 pixels, about 2 and 10 um): keeps structure of the size of nuclei, removes shot noise and gradients.
tex = {name: gaussian_filter(d["patches"][name].astype(float), 3) - gaussian_filter(d["patches"][name].astype(float), 15) for name in ["footprint", "outside"]}
rows.append({"treatment": t, "dish": d["dish"],
**{f"{name}_median": round(float(np.median(d["patches"][name])), 1) for name in tex},
**{f"{name}_texture_counts": round(float(np.subtract(*np.percentile(tex[name], [75, 25]))), 1) for name in tex}})
plt.suptitle("Full-resolution 600 x 600 pixel patches (0.39 mm at the assumed scale): the center of footprint 0, and the monolayer 1.25 radii\n"
"from its center on the side away from the array; each clipped at its own 1st and 95th percentiles (the brightest debris saturates)")
plt.tight_layout(); plt.show()
print("Texture: interquartile range (counts) of the band-passed patch (difference of Gaussians, sigma 3 and 15 pixels), structure the size of nuclei.")
print(pd.DataFrame(rows).to_string(index=False))
Texture: interquartile range (counts) of the band-passed patch (difference of Gaussians, sigma 3 and 15 pixels), structure the size of nuclei.
treatment dish footprint_median outside_median footprint_texture_counts outside_texture_counts
1Px4 23 292.0 305.0 11.2 36.0
1Px4 24 217.0 277.0 9.7 32.6
1Px4 25 246.0 240.0 8.6 28.8
5Px4 9 369.0 419.0 16.5 79.6
5Px4 20 373.0 408.0 21.4 201.9
5Px4 22 279.0 359.0 7.6 80.7
10Px4 4 284.0 387.0 9.6 131.5
10Px4 11 410.0 613.0 16.6 195.6
10Px4 18 294.0 496.0 14.6 138.2
fig, axes = plt.subplots(3, 3, figsize=(14, 10), sharex=True)
centers = np.sqrt(HIST_BINS[:-1] * HIST_BINS[1:])
rows = []
for ax, (t, d) in zip(axes.flat, alld):
for z, col in [("footprint", "k"), ("outside", "tab:green"), ("between", "tab:red")]:
h = d["zone_hist"][z]
ax.plot(centers, h / h.sum(), color=col, label=z)
for v, ls, lab in [(d["dark"], "--", "b2-dark"), (d["region_min"], ":", "b2-min")]:
ax.axvline(v, color="gray", ls=ls, label=lab)
ax.set_xscale("log"); ax.set_title(f"{t} dish {d['dish']}", fontsize=9)
rows.append({"treatment": t, "dish": d["dish"],
**{f"{z}_p1/p50/p99": " / ".join(f"{x:.0f}" for x in d["zone_pct"][z][[0, 2, 4]]) for z in ["footprint", "outside", "between"]},
"dark_p1": round(d["dark"], 1), "region_min": d["region_min"],
"darkest_1pct_beyond_2R": round(d["dark_far_fraction"], 3)})
axes.flat[0].legend(fontsize=8)
for ax in axes[-1]:
ax.set_xlabel("block mean (counts)")
plt.suptitle("Distributions of 8 x 8 block means: inside the footprints (within 0.7 radius), the monolayer outside the array\n"
"(1.2 to 1.6 times the center-to-footprint distance), and the exposed area between the electrodes (within half that distance)")
plt.tight_layout(); plt.show()
print(pd.DataFrame(rows).to_string(index=False))
for z in ["footprint", "outside", "between"]:
frac = [d["zone_hist"][z].sum() / d["zone_n"][z] for _, d in alld]
print(f"{z}: fraction of blocks within the plotted range {HIST_BINS[0]:.0f} to {HIST_BINS[-1]:.0f} counts, {min(frac):.3f} to {max(frac):.3f}")
fo = np.array([d["footprint"] / d["zone_pct"]["outside"][2] for _, d in alld])
print(f"\nFootprint median over the median of the monolayer outside the array: {fo.min():.2f} to {fo.max():.2f}")
print("Darkest 1% of nonzero blocks farther than 2 center-to-footprint distances from the array center:",
f"{min(d['dark_far_fraction'] for _, d in alld):.3f} to {max(d['dark_far_fraction'] for _, d in alld):.3f}")
print("Darkest 1% of nonzero blocks that touch a zero block (and so may straddle the zero padding):",
f"{min(d['dark_touch_zero'] for _, d in alld):.3f} to {max(d['dark_touch_zero'] for _, d in alld):.3f}")
print("1st percentile of the nonzero blocks away from the padding (3 x 3 neighbourhood all nonzero), per dish:",
", ".join(f"{d['dish']} {d['dark_interior']:.1f}" for _, d in alld),
f"(b2-dark: {min(d['dark'] for _, d in alld):.1f} to {max(d['dark'] for _, d in alld):.1f})")
print(f"b2-dark offsets {min(d['dark'] for _, d in alld):.1f} to {max(d['dark'] for _, d in alld):.1f} counts; "
f"b2-min offsets {min(d['region_min'] for _, d in alld):.0f} to {max(d['region_min'] for _, d in alld):.0f}; "
f"footprint medians {min(d['footprint'] for _, d in alld):.0f} to {max(d['footprint'] for _, d in alld):.0f}.")
fd = np.array([d["footprint"] / d["dark"] for _, d in alld])
print(f"Footprint median over the b2-dark offset: {fd.min():.1f} to {fd.max():.1f}")
treatment dish footprint_p1/p50/p99 outside_p1/p50/p99 between_p1/p50/p99 dark_p1 region_min darkest_1pct_beyond_2R
1Px4 23 236 / 295 / 443 241 / 318 / 583 303 / 540 / 1300 73.5 110.0 1.000
1Px4 24 200 / 266 / 384 220 / 294 / 578 292 / 496 / 1170 86.7 118.0 1.000
1Px4 25 195 / 239 / 372 195 / 254 / 517 252 / 423 / 992 76.2 110.0 0.999
5Px4 9 241 / 350 / 715 254 / 428 / 1404 466 / 1099 / 4265 76.7 171.0 0.998
5Px4 20 180 / 312 / 1410 168 / 376 / 1635 333 / 1563 / 10906 78.5 129.0 0.997
5Px4 22 231 / 293 / 546 214 / 312 / 843 438 / 964 / 3477 73.8 160.0 1.000
10Px4 4 255 / 333 / 1028 242 / 449 / 2344 672 / 1990 / 16980 87.1 186.0 0.996
10Px4 11 313 / 403 / 1863 301 / 544 / 2540 527 / 1624 / 10875 81.0 200.0 1.000
10Px4 18 263 / 365 / 1229 233 / 445 / 2513 720 / 2229 / 18702 81.3 173.0 0.996
footprint: fraction of blocks within the plotted range 20 to 5000 counts, 0.998 to 1.000
outside: fraction of blocks within the plotted range 20 to 5000 counts, 0.997 to 1.000
between: fraction of blocks within the plotted range 20 to 5000 counts, 0.865 to 1.000
Footprint median over the median of the monolayer outside the array: 0.74 to 0.94
Darkest 1% of nonzero blocks farther than 2 center-to-footprint distances from the array center: 0.996 to 1.000
Darkest 1% of nonzero blocks that touch a zero block (and so may straddle the zero padding): 0.062 to 0.089
1st percentile of the nonzero blocks away from the padding (3 x 3 neighbourhood all nonzero), per dish: 23 74.2, 24 88.0, 25 76.9, 9 77.5, 20 79.7, 22 74.5, 4 88.5, 11 82.1, 18 82.5 (b2-dark: 73.5 to 87.1)
b2-dark offsets 73.5 to 87.1 counts; b2-min offsets 110 to 200; footprint medians 239 to 403.
Footprint median over the b2-dark offset: 3.1 to 5.0
The footprints are not cell-free. At full resolution several show a faint monolayer, with
structure the size of nuclei (band-passed interquartile range 7.6 to 21.4 counts, against 28.8 to
201.9 in the monolayer just outside), and their median is 0.74 to 0.94 of the median of the
monolayer outside the array and 3.1 to 5.0 times the darkest blocks. They read as cells that took
up little dye, so the footprint median is not the "cell-free or dark offset" of reading b2. It is
kept only as the variant b2-fp, which counts towards no outcome.
The darkest 1% of each image's nonzero blocks lie, for 99.6 to 100% of them, more than twice the
center-to-footprint distance from the array center. The thumbnails suggest this is outside the
circular edge of the dish's glass bottom, but nothing printed here shows it. 6.2 to 8.9% of these
blocks touch a zero block and could straddle the zero padding, which would pull them down; the
1st percentile of the blocks away from the padding (3 x 3 neighbourhood all nonzero) is 74.2 to
88.5 counts, within 1.4 counts of the value with all blocks, so the padding does not set the
offset. Their upper bound, the 1st percentile (73.5 to 87.1
counts), is taken as the dark offset b2-dark; the darkest pixel of the region around the array
(110 to 200 counts) is a second reading, b2-min. The files hold no dark frame, so both are
estimates, and fig6b shows how its result depends on the size of the offset.
def table(layout, background, extent="camera"):
"""Per-dish ROI values for a layout and background reading, by treatment.
extent "camera": ROIs over +/- 1.65 mm at the assumed pixel size (main); "geometric": the
variant that ends the ROIs 5% of the diagonal short of the footprints.
"""
key = "profiles" if extent == "camera" else "profiles_geo"
return {t: cancan.dish_matrix([{"profiles": d[key], "footprint": d["footprint"], "dark": d["dark"], "region_min": d["region_min"]}
for d in dishes[t]], layout, background)
for t in TREATMENTS}
pos, _ = table("r2", "b1")["1Px4"]
for lay in cancan.LAYOUTS:
p, _ = table(lay, "b1")["1Px4"]
print(f"{lay}: {len(p)} ROIs, {p[0]:.3f} to {p[-1]:.3f} mm, spacing {1000 * (p[1] - p[0]):.1f} um")
rows = []
for t in TREATMENTS:
for lay in cancan.LAYOUTS:
_, P = table(lay, "b1")[t]
rows.append({"treatment": t, "layout": lay, "roi_min": P.min().round(1), "roi_max": P.max().round(1),
"dish_means": np.round(P.mean(axis=1), 1).tolist()})
print(pd.DataFrame(rows).to_string(index=False))
r2: 46 ROIs, -1.614 to 1.614 mm, spacing 71.7 um
r1-dA: 92 ROIs, -1.632 to 1.632 mm, spacing 35.9 um
r1-dB: 92 ROIs, -1.632 to 1.632 mm, spacing 35.9 um
treatment layout roi_min roi_max dish_means
1Px4 r2 363.8 946.5 [627.3, 567.0, 495.5]
1Px4 r1-dA 281.3 2070.9 [619.5, 556.6, 514.6]
1Px4 r1-dB 332.8 1778.1 [657.1, 587.6, 484.6]
5Px4 r2 867.3 6689.6 [1653.5, 2673.3, 1309.8]
5Px4 r1-dA 591.2 9880.5 [1466.2, 2504.9, 1216.2]
5Px4 r1-dB 616.7 11820.3 [1765.2, 2816.0, 1390.5]
10Px4 r2 1280.7 15942.7 [3954.4, 3000.5, 4615.1]
10Px4 r1-dA 832.9 18520.7 [3073.4, 2889.1, 3756.7]
10Px4 r1-dB 864.5 23280.2 [4736.9, 3229.9, 5164.5]
The readings of the claims file¶
The claims file leaves the ROI layout, background, center, periphery and normalization order
open and names readings for each (header of the claims file); a claim holds when it holds under
any combination, and every combination is shown. The readings, as implemented in cancan.py:
- layout:
r246 ROIs on each diagonal, averaged;r1-dAandr1-dB92 ROIs on one diagonal; - background:
b1raw counts;b2"minus a cell-free or dark offset, where the data hold one", run two ways because the files hold no dark frame:b2-darkminus the 1st percentile of the image's nonzero 8 x 8 block means (blocks far outside the array), andb2-minminus the darkest pixel of the full-resolution region around the array; - center:
c1the two ROIs nearest the center (equally near, averaged);c2the highest ROI between the minima on either side; - periphery:
e1the mean of the two end ROIs;e2-negande2-posone end; - normalization:
n1each dish normalized, then averaged;n2the mean profile normalized; - least affected area:
t1the mean of the two side minima;t2-neg,t2-posone side.
The first round used the median inside the electrode footprints as b2. The footprints hold a
faint monolayer (shown above), so that level is not cell-free; it is shown as the variant
b2-fp, and it does not count towards any outcome.
The side minima and the c2 peak are found on the treatment's mean profile. The reading shown
first is r2, b1, c1, e1, n1, t1: both diagonals (Fig. 5B legend averages both, and
these treatments rotate the packet), no background (none is named in Methods 2.4) and the most
literal center and periphery.
fig, axes = plt.subplots(1, 2, figsize=(13, 4.5))
colors = {"1Px4": "k", "5Px4": "tab:blue", "10Px4": "tab:red"}
data = table("r2", "b1")
ranges = []
for t in TREATMENTS:
pos, P = data[t]
m, se = P.mean(0), P.std(0, ddof=1) / np.sqrt(len(P))
axes[0].errorbar(pos, m, se, color=colors[t], label=f"{t} (n={len(P)})", lw=1, capsize=0)
N = P / cancan.periphery(P, "e1")[:, None] * 100
mn, sn = N.mean(0), N.std(0, ddof=1) / np.sqrt(len(N))
axes[1].errorbar(pos, mn, sn, color=colors[t], label=t, lw=1, capsize=0)
ranges.append({"treatment": t, "au_mean_min": m.min().round(1), "au_mean_max": m.max().round(1),
"norm_mean_min": mn.min().round(1), "norm_mean_max": mn.max().round(1)})
axes[0].set_ylabel("YP intensity (counts)"); axes[1].set_ylabel("% of most peripheral ROIs (e1, n1)")
for ax in axes:
ax.set_xlabel("distance from array center along the diagonal (mm)"); ax.legend()
axes[0].set_title("Reading r2, b1: mean +/- s.e. over dishes")
axes[1].set_title("Normalized as in Fig. 6B")
plt.tight_layout(); plt.show()
print(pd.DataFrame(ranges).to_string(index=False))
print("All points are within the axes.")
treatment au_mean_min au_mean_max norm_mean_min norm_mean_max
1Px4 455.9 748.2 83.7 139.5
5Px4 1072.6 3783.1 37.3 110.3
10Px4 1820.2 10193.6 19.9 110.1
All points are within the axes.
# Per-dish profiles, reading r2, b1: raw counts (top) and in percent of the mean of the two ends (bottom).
fig, axes = plt.subplots(2, 3, figsize=(15, 8), sharex=True)
data = table("r2", "b1")
rows = []
for j, t in enumerate(TREATMENTS):
pos, P = data[t]
for d, p in zip(dishes[t], P):
n = p / cancan.periphery(p, "e1")[0] * 100
axes[0, j].plot(pos, p, lw=1, label=f"dish {d['dish']}")
axes[1, j].plot(pos, n, lw=1, label=f"dish {d['dish']}")
ci = cancan.center_index(p, "c1")
rows.append({"treatment": t, "dish": d["dish"], "counts_min": round(p.min()), "counts_max": round(p.max()),
"neg_end": round(p[0]), "center_c1": round(cancan.center_value(p, ci)[0]), "pos_end": round(p[-1]),
"pct_min": round(n.min(), 1), "pct_max": round(n.max(), 1)})
axes[0, j].plot(pos, P.mean(0), "k--", lw=1.5, label="mean")
axes[1, j].plot(pos, (P / cancan.periphery(P, "e1")[:, None] * 100).mean(0), "k--", lw=1.5, label="mean (n1)")
axes[0, j].set_title(t); axes[0, j].legend(fontsize=8)
axes[0, 0].set_ylabel("YP intensity (counts)"); axes[1, 0].set_ylabel("% of the mean of the two ends")
for ax in axes[1]:
ax.set_xlabel("distance from array center (mm)")
plt.tight_layout(); plt.show()
print(pd.DataFrame(rows).to_string(index=False))
print("All points are within the axes.")
treatment dish counts_min counts_max neg_end center_c1 pos_end pct_min pct_max
1Px4 23 480 946 557 799 497 91.2 179.7
1Px4 24 395 783 615 711 642 62.8 124.7
1Px4 25 364 715 433 513 524 76.1 149.4
5Px4 9 932 3477 3181 2518 3048 29.9 111.6
5Px4 20 1393 6690 3257 3639 6690 28.0 134.5
5Px4 22 867 2022 1655 1735 1612 53.1 123.7
10Px4 4 1939 9637 6131 6100 9637 24.6 122.2
10Px4 11 1281 8419 5618 4502 8419 18.2 120.0
10Px4 18 1668 15943 15943 4915 12525 11.7 112.0
All points are within the axes.
fig6a-more-packets-more-uptake¶
Increasing the total number of rotated Packet 2 packets from 4 (1Px4) to 20 (5Px4) and 40 (10Px4) profoundly enhanced YP uptake throughout the electrode array.
Criterion (claims file): in a.u., at the periphery, the center and the minimum between them, the mean is ordered 4 < 20 < 40 packets and 40 exceeds 4 by a two-sided Student's t-test on per-dish values at p < 0.05; partially reproduced when the order holds at all three places and the test at one or two. Run under every combination of layout, background, center, periphery and trough readings (the normalization readings do not apply to a.u. values).
rows = []
for lay in cancan.LAYOUTS:
for bg in cancan.BACKGROUNDS + cancan.VARIANT_BACKGROUNDS:
data = table(lay, bg)
for cen in cancan.CENTERS:
for per in cancan.PERIPHERIES:
for tro in cancan.TROUGHS:
v = {}
for t in TREATMENTS:
pos, P = data[t]
m = P.mean(0)
v[t] = {"periphery": cancan.periphery(P, per),
"center": cancan.center_value(P, cancan.center_index(m, cen)),
"trough": cancan.trough_value(P, cancan.side_minima(m), tro)}
row = {"layout": lay, "bg": bg, "center": cen, "periphery": per, "trough": tro}
for place in ["periphery", "center", "trough"]:
a, b, c = (v[t][place] for t in TREATMENTS)
row[f"{place}_means"] = f"{a.mean():.0f} / {b.mean():.0f} / {c.mean():.0f}"
row[f"{place}_order"] = a.mean() < b.mean() < c.mean()
row[f"{place}_p"] = stats.ttest_ind(c, a).pvalue
row[f"{place}_ratio40to4"] = c.mean() / a.mean()
rows.append(row)
allf6a = pd.DataFrame(rows)
places = ["periphery", "center", "trough"]
allf6a["order_all"] = allf6a[[f"{p}_order" for p in places]].all(axis=1)
allf6a["n_sig"] = (allf6a[[f"{p}_p" for p in places]] < 0.05).sum(axis=1)
allf6a["outcome"] = np.where(allf6a.order_all & (allf6a.n_sig == 3), "reproduced",
np.where(allf6a.order_all & (allf6a.n_sig >= 1), "partially", "not"))
f6a = allf6a[allf6a.bg.isin(cancan.BACKGROUNDS)]
print("Primary reading (r2, b1, c1, e1, t1):")
print(f6a[(f6a.layout == "r2") & (f6a.bg == "b1") & (f6a.center == "c1") & (f6a.periphery == "e1") & (f6a.trough == "t1")].T.to_string())
print("\nReadings of the claims file (backgrounds", cancan.BACKGROUNDS, "):")
print("Combinations by outcome:", f6a.outcome.value_counts().to_dict(), "of", len(f6a))
print("Order 4 < 20 < 40 at all three places in", int(f6a.order_all.sum()), "of", len(f6a))
print("Range over combinations of the 40-over-4 ratio:",
{p: (round(f6a[f"{p}_ratio40to4"].min(), 2), round(f6a[f"{p}_ratio40to4"].max(), 2)) for p in places})
print("Range over combinations of the t-test p (40 against 4):",
{p: (float(f6a[f"{p}_p"].min().round(5)), float(f6a[f"{p}_p"].max().round(5))) for p in places})
failed = {p: int(((f6a[f"{p}_p"] >= 0.05) & f6a.order_all).sum()) for p in places}
print("Combinations in which the test fails, by place:", failed)
print("Periphery test failures by layout and periphery reading:")
print(f6a[f6a.periphery_p >= 0.05].groupby(["layout", "periphery"]).size().to_string())
print("\nBy layout and background, combinations reproduced / partially / not:")
print(f6a.groupby(["layout", "bg"]).outcome.value_counts().unstack(fill_value=0).to_string())
v6a = allf6a[allf6a.bg.isin(cancan.VARIANT_BACKGROUNDS)]
print("\nVariant b2-fp (footprint median, not a reading of the claims file): combinations by outcome", v6a.outcome.value_counts().to_dict(), "of", len(v6a))
Primary reading (r2, b1, c1, e1, t1):
0
layout r2
bg b1
center c1
periphery e1
trough t1
periphery_means 544 / 3240 / 9712
periphery_order True
periphery_p 0.015737
periphery_ratio40to4 17.838235
center_means 674 / 2631 / 5172
center_order True
center_p 0.000759
center_ratio40to4 7.672547
trough_means 479 / 1148 / 1880
trough_order True
trough_p 0.00079
trough_ratio40to4 3.923182
order_all True
n_sig 3
outcome reproduced
Readings of the claims file (backgrounds ('b1', 'b2-dark', 'b2-min') ):
Combinations by outcome: {'partially': 90, 'reproduced': 72} of 162
Order 4 < 20 < 40 at all three places in 162 of 162
Range over combinations of the 40-over-4 ratio: {'periphery': (np.float64(8.38), np.float64(34.84)), 'center': (np.float64(7.67), np.float64(11.56)), 'trough': (np.float64(3.0), np.float64(4.76))}
Range over combinations of the t-test p (40 against 4): {'periphery': (0.00138, 0.12664), 'center': (0.00043, 0.01188), 'trough': (0.00065, 0.04064)}
Combinations in which the test fails, by place: {'periphery': 90, 'center': 0, 'trough': 0}
Periphery test failures by layout and periphery reading:
layout periphery
r1-dA e1 18
e2-neg 18
e2-pos 18
r1-dB e2-neg 18
r2 e2-neg 18
By layout and background, combinations reproduced / partially / not:
outcome partially reproduced
layout bg
r1-dA b1 18 0
b2-dark 18 0
b2-min 18 0
r1-dB b1 6 12
b2-dark 6 12
b2-min 6 12
r2 b1 6 12
b2-dark 6 12
b2-min 6 12
Variant b2-fp (footprint median, not a reading of the claims file): combinations by outcome {'partially': 30, 'reproduced': 24} of 54
# Per dish, primary reading: the values the test uses.
data = table("r2", "b1")
rows = []
for t in TREATMENTS:
pos, P = data[t]
m = P.mean(0)
ci, mins = cancan.center_index(m, "c1"), cancan.side_minima(m)
for d, p in zip(dishes[t], P):
rows.append({"treatment": t, "dish": d["dish"], "periphery_e1": round(cancan.periphery(p, "e1")[0], 1),
"center_c1": round(cancan.center_value(p, ci)[0], 1), "trough_t1": round(cancan.trough_value(p, mins, "t1")[0], 1),
"trough_positions_mm": [round(pos[i], 2) for i in mins]})
print(pd.DataFrame(rows).to_string(index=False))
treatment dish periphery_e1 center_c1 trough_t1 trough_positions_mm
1Px4 23 526.8 798.8 558.7 [-0.54, 0.82]
1Px4 24 628.2 710.6 480.6 [-0.54, 0.82]
1Px4 25 478.4 513.0 398.4 [-0.54, 0.82]
5Px4 9 3114.4 2518.1 1056.4 [-0.75, 0.97]
5Px4 20 4973.3 3639.4 1457.6 [-0.75, 0.97]
5Px4 22 1633.8 1735.2 931.2 [-0.75, 0.97]
10Px4 4 7884.1 6099.8 2090.7 [-0.54, 0.54]
10Px4 11 7018.4 4502.4 1600.0 [-0.54, 0.54]
10Px4 18 14233.7 4914.6 1949.8 [-0.54, 0.54]
# Variant: ROI extent from the footprints (no pixel size), primary reading (r2, b1, c1, e1, t1).
data = table("r2", "b1", "geometric")
v = {}
for t in TREATMENTS:
pos, P = data[t]
m = P.mean(0)
v[t] = {"periphery": cancan.periphery(P, "e1"), "center": cancan.center_value(P, cancan.center_index(m, "c1")),
"trough": cancan.trough_value(P, cancan.side_minima(m), "t1")}
for place in ["periphery", "center", "trough"]:
a, b, c = (v[t][place] for t in TREATMENTS)
print(f"{place}: means {a.mean():.0f} / {b.mean():.0f} / {c.mean():.0f}, order {a.mean() < b.mean() < c.mean()}, "
f"40 against 4 p = {stats.ttest_ind(c, a).pvalue:.4f}")
periphery: means 579 / 2667 / 8851, order True, 40 against 4 p = 0.0351 center: means 673 / 2639 / 5165, order True, 40 against 4 p = 0.0008 trough: means 475 / 1150 / 1899, order True, 40 against 4 p = 0.0008
Result: reproduced. Under the primary reading (both diagonals, raw counts, the two central ROIs, the mean of the two ends, the mean of the two side minima), the mean intensity rises from 4 to 20 to 40 packets at the periphery (544, 3240, 9712 counts), the center (674, 2631, 5172) and the least affected area (479, 1148, 1880), and 40 exceeds 4 at each place by a two-sided Student's t-test on 3 dishes each (p = 0.016, 0.00076 and 0.00079). The order holds in all 162 combinations of the claims file's readings; all three tests pass in 72 and at least one in the other 90. Only the periphery test fails (p up to 0.127): in all 54 combinations on diagonal A alone and in the 36 others that take the periphery from the negative end alone. So the full result needs diagonal B or both diagonals, with the periphery from both ends or the positive end, not from the negative end alone; the other readings give a partial result, and the claims file accepts a claim that holds under any combination. Saturation of up to 5% of an ROI near the 10Px4 electrodes lowers the 10Px4 periphery, so it works against the order. With the ROI extent taken from the footprints the primary reading gives the same order and p = 0.035, 0.0008 and 0.0008. The footprint variant b2-fp, outside the readings, gives 24 reproduced and 30 partial of 54.
fig6b-peak-relative-to-periphery¶
The central peak was almost twofold brighter than the periphery for 1Px4, and about the same as the periphery for 5Px4 and 10Px4.
Criterion (claims file): normalized center 200 +/- 20% for 1Px4 and 100 +/- 10% for 5Px4 and 10Px4; reproduced when all three are within tolerance under one combination of readings; partially reproduced when 1Px4 is within tolerance and above both other treatments.
def fig6b_table(extent):
rows = []
for lay in cancan.LAYOUTS:
for bg in cancan.BACKGROUNDS + cancan.VARIANT_BACKGROUNDS:
data = table(lay, bg, extent)
for cen in cancan.CENTERS:
for per in cancan.PERIPHERIES:
for norm in cancan.NORMALIZATIONS:
row = {"layout": lay, "bg": bg, "center": cen, "periphery": per, "norm": norm}
for t in TREATMENTS:
pos, P = data[t]
Q = cancan.mean_profile(P, per, norm)
ci = cancan.center_index(Q, cen)
row[t] = cancan.center_value(Q, ci)[0]
if norm == "n1":
per_dish = cancan.center_value(P, ci) / cancan.periphery(P, per) * 100
row[f"{t}_se"] = per_dish.std(ddof=1) / np.sqrt(len(per_dish))
rows.append(row)
return pd.DataFrame(rows)
def judge_6b(f6b):
f6b["in_1Px4"] = f6b["1Px4"].between(180, 220)
f6b["in_5Px4"] = f6b["5Px4"].between(90, 110)
f6b["in_10Px4"] = f6b["10Px4"].between(90, 110)
f6b["1Px4_highest"] = (f6b["1Px4"] > f6b["5Px4"]) & (f6b["1Px4"] > f6b["10Px4"])
f6b["outcome"] = np.where(f6b.in_1Px4 & f6b.in_5Px4 & f6b.in_10Px4, "reproduced",
np.where(f6b.in_1Px4 & f6b["1Px4_highest"], "partially", "not"))
return f6b
allf6b = judge_6b(fig6b_table("camera"))
f6b = allf6b[allf6b.bg.isin(cancan.BACKGROUNDS)]
print(f6b.round(1).to_string(index=False))
print("\nReadings of the claims file (backgrounds", cancan.BACKGROUNDS, "): combinations by outcome", f6b.outcome.value_counts().to_dict(), "of", len(f6b))
for t in TREATMENTS:
print(f"{t}: normalized center {f6b[t].min():.1f} to {f6b[t].max():.1f}% over combinations, median {f6b[t].median():.1f}%")
print("1Px4 above both others in", int(f6b["1Px4_highest"].sum()), "of", len(f6b))
print("Within tolerance: 1Px4 in", int(f6b.in_1Px4.sum()), "; 5Px4 in", int(f6b.in_5Px4.sum()), "; 10Px4 in", int(f6b.in_10Px4.sum()))
print("\nCombinations that are reproduced or partially reproduced:")
print(f6b[f6b.outcome != "not"].round(1).to_string(index=False))
print("\nBy background, combinations by outcome:", allf6b.groupby("bg").outcome.value_counts().unstack(fill_value=0).to_dict("index"))
print("By layout and center, partial combinations:", f6b[f6b.outcome == "partially"].groupby(["layout", "center"]).size().to_dict())
g6b = judge_6b(fig6b_table("geometric"))
gv = g6b[g6b.bg.isin(cancan.BACKGROUNDS)]
print("\nVariant, ROI extent from the footprints (no pixel size): combinations by outcome", gv.outcome.value_counts().to_dict(), "of", len(gv),
"; by background", g6b.groupby("bg").outcome.value_counts().unstack(fill_value=0).to_dict("index"))
for t in TREATMENTS:
print(f" {t}: {gv[t].min():.1f} to {gv[t].max():.1f}%, median {gv[t].median():.1f}%; within tolerance in", int(gv[f"in_{t}"].sum()))
print(" primary reading (r2, b1, c1, e1, n1):", gv[(gv.layout == "r2") & (gv.bg == "b1") & (gv.center == "c1") & (gv.periphery == "e1") & (gv.norm == "n1")][TREATMENTS].round(1).to_dict("records"))
layout bg center periphery norm 1Px4 1Px4_se 5Px4 5Px4_se 10Px4 10Px4_se in_1Px4 in_5Px4 in_10Px4 1Px4_highest outcome
r2 b1 c1 e1 n1 124.0 13.9 86.7 10.0 58.7 12.7 False False False True not
r2 b1 c1 e1 n2 123.8 NaN 81.2 NaN 53.3 NaN False False False True not
r2 b1 c1 e2-neg n1 125.8 8.8 98.6 9.9 70.2 20.4 False True False True not
r2 b1 c1 e2-neg n2 126.0 NaN 97.5 NaN 56.0 NaN False True False True not
r2 b1 c1 e2-pos n1 123.2 19.2 81.6 15.4 52.0 7.0 False False False True not
r2 b1 c1 e2-pos n2 121.7 NaN 69.5 NaN 50.7 NaN False False False True not
r2 b1 c2 e1 n1 139.5 21.9 91.7 13.0 70.8 17.2 False True False True not
r2 b1 c2 e1 n2 137.4 NaN 86.1 NaN 63.3 NaN False False False True not
r2 b1 c2 e2-neg n1 141.7 18.6 105.2 16.3 85.2 26.6 False True False True not
r2 b1 c2 e2-neg n2 139.9 NaN 103.5 NaN 66.6 NaN False True False True not
r2 b1 c2 e2-pos n1 138.5 26.7 85.6 17.1 62.3 10.3 False False False True not
r2 b1 c2 e2-pos n2 135.0 NaN 73.8 NaN 60.3 NaN False False False True not
r2 b2-dark c1 e1 n1 127.9 16.2 86.5 10.2 58.3 12.7 False False False True not
r2 b2-dark c1 e1 n2 127.8 NaN 80.7 NaN 52.9 NaN False False False True not
r2 b2-dark c1 e2-neg n1 130.2 10.0 98.6 10.2 69.9 20.5 False True False True not
r2 b2-dark c1 e2-neg n2 130.5 NaN 97.4 NaN 55.6 NaN False True False True not
r2 b2-dark c1 e2-pos n1 127.1 22.5 81.3 15.6 51.6 7.0 False False False True not
r2 b2-dark c1 e2-pos n2 125.3 NaN 68.9 NaN 50.3 NaN False False False True not
r2 b2-dark c2 e1 n1 146.2 25.5 91.6 13.4 70.6 17.3 False True False True not
r2 b2-dark c2 e1 n2 143.8 NaN 85.8 NaN 63.0 NaN False False False True not
r2 b2-dark c2 e2-neg n1 149.1 21.7 105.5 16.8 85.2 26.8 False True False True not
r2 b2-dark c2 e2-neg n2 146.8 NaN 103.6 NaN 66.3 NaN False True False True not
r2 b2-dark c2 e2-pos n1 145.1 31.4 85.6 17.5 62.0 10.4 False False False True not
r2 b2-dark c2 e2-pos n2 140.8 NaN 73.2 NaN 60.0 NaN False False False True not
r2 b2-min c1 e1 n1 130.3 17.6 86.4 10.5 57.9 12.7 False False False True not
r2 b2-min c1 e1 n2 130.0 NaN 80.3 NaN 52.3 NaN False False False True not
r2 b2-min c1 e2-neg n1 132.7 10.8 98.5 10.5 69.7 20.6 False True False True not
r2 b2-min c1 e2-neg n2 133.0 NaN 97.4 NaN 55.1 NaN False True False True not
r2 b2-min c1 e2-pos n1 129.6 24.7 81.2 15.9 51.1 7.0 False False False True not
r2 b2-min c1 e2-pos n2 127.2 NaN 68.3 NaN 49.8 NaN False False False True not
r2 b2-min c2 e1 n1 150.2 27.7 91.6 13.9 70.3 17.3 False True False True not
r2 b2-min c2 e1 n2 147.2 NaN 85.5 NaN 62.6 NaN False False False True not
r2 b2-min c2 e2-neg n1 153.5 23.6 105.6 17.3 85.1 27.0 False True False True not
r2 b2-min c2 e2-neg n2 150.5 NaN 103.7 NaN 65.9 NaN False True False True not
r2 b2-min c2 e2-pos n1 149.2 34.4 85.6 18.0 61.7 10.4 False False False True not
r2 b2-min c2 e2-pos n2 144.0 NaN 72.7 NaN 59.6 NaN False False False True not
r1-dA b1 c1 e1 n1 137.7 24.2 112.2 26.1 101.0 57.6 False False True True not
r1-dA b1 c1 e1 n2 135.7 NaN 102.2 NaN 61.7 NaN False True False True not
r1-dA b1 c1 e2-neg n1 136.8 22.7 97.9 20.4 179.7 61.9 False True False False not
r1-dA b1 c1 e2-neg n2 136.2 NaN 80.0 NaN 126.5 NaN False False False True not
r1-dA b1 c1 e2-pos n1 141.1 27.4 154.5 53.5 78.4 50.9 False False False False not
r1-dA b1 c1 e2-pos n2 135.1 NaN 141.1 NaN 40.8 NaN False False False False not
r1-dA b1 c2 e1 n1 223.1 124.8 123.6 13.2 164.0 108.5 False False False True not
r1-dA b1 c2 e1 n2 173.9 NaN 115.5 NaN 90.2 NaN False False True True not
r1-dA b1 c2 e2-neg n1 177.7 56.9 113.1 40.0 273.5 115.0 False False False False not
r1-dA b1 c2 e2-neg n2 174.6 NaN 90.5 NaN 185.1 NaN False True False False not
r1-dA b1 c2 e2-pos n1 242.9 146.7 162.8 30.9 129.2 94.2 False False False True not
r1-dA b1 c2 e2-pos n2 173.2 NaN 159.6 NaN 59.6 NaN False False False True not
r1-dA b2-dark c1 e1 n1 144.8 28.8 112.8 27.0 102.0 59.0 False False True True not
r1-dA b2-dark c1 e1 n2 142.3 NaN 102.2 NaN 61.3 NaN False True False True not
r1-dA b2-dark c1 e2-neg n1 143.5 26.8 98.3 20.9 183.1 63.9 False True False False not
r1-dA b2-dark c1 e2-neg n2 143.0 NaN 79.6 NaN 127.0 NaN False False False True not
r1-dA b2-dark c1 e2-pos n1 149.7 32.7 157.6 56.8 78.9 51.7 False False False False not
r1-dA b2-dark c1 e2-pos n2 141.6 NaN 142.7 NaN 40.4 NaN False False False False not
r1-dA b2-dark c2 e1 n1 249.3 151.0 124.7 13.8 166.7 111.6 False False False True not
r1-dA b2-dark c2 e1 n2 187.6 NaN 115.9 NaN 90.1 NaN True False True True partially
r1-dA b2-dark c2 e2-neg n1 191.8 67.1 114.8 42.3 280.4 119.3 True False False False not
r1-dA b2-dark c2 e2-neg n2 188.5 NaN 90.3 NaN 186.8 NaN True True False True partially
r1-dA b2-dark c2 e2-pos n1 278.7 182.3 165.9 33.0 130.9 96.2 False False False True not
r1-dA b2-dark c2 e2-pos n2 186.7 NaN 161.9 NaN 59.4 NaN True False False True partially
r1-dA b2-min c1 e1 n1 149.3 31.9 113.7 28.2 103.1 60.6 False False True True not
r1-dA b2-min c1 e1 n2 145.9 NaN 102.3 NaN 60.8 NaN False True False True not
r1-dA b2-min c1 e2-neg n1 147.5 29.5 98.9 21.3 187.7 66.6 False True False False not
r1-dA b2-min c1 e2-neg n2 146.7 NaN 79.2 NaN 127.7 NaN False False False True not
r1-dA b2-min c1 e2-pos n1 155.2 36.2 162.0 61.5 79.4 52.7 False False False False not
r1-dA b2-min c1 e2-pos n2 145.2 NaN 144.5 NaN 39.9 NaN False False False True not
r1-dA b2-min c2 e1 n1 265.0 166.3 126.1 14.5 170.0 115.3 False False False True not
r1-dA b2-min c2 e1 n2 195.1 NaN 116.4 NaN 90.0 NaN True False False True partially
r1-dA b2-min c2 e2-neg n1 200.7 73.8 117.2 45.3 289.6 124.7 True False False False not
r1-dA b2-min c2 e2-neg n2 196.1 NaN 90.1 NaN 189.0 NaN True True False True partially
r1-dA b2-min c2 e2-pos n1 301.3 204.2 170.0 36.0 132.9 98.6 False False False True not
r1-dA b2-min c2 e2-pos n2 194.1 NaN 164.4 NaN 59.1 NaN True False False True partially
r1-dB b1 c1 e1 n1 131.4 18.8 54.7 2.2 56.3 17.0 False False False True not
r1-dB b1 c1 e1 n2 130.7 NaN 54.6 NaN 48.5 NaN False False False True not
r1-dB b1 c1 e2-neg n1 135.3 12.7 82.2 21.2 52.2 20.2 False False False True not
r1-dB b1 c1 e2-neg n2 134.5 NaN 84.0 NaN 40.4 NaN False False False True not
r1-dB b1 c1 e2-pos n1 129.9 26.2 46.9 9.3 63.9 12.5 False False False True not
r1-dB b1 c1 e2-pos n2 127.1 NaN 40.4 NaN 60.6 NaN False False False True not
r1-dB b1 c2 e1 n1 167.7 31.9 73.9 24.7 93.4 31.8 False False True True not
r1-dB b1 c2 e1 n2 166.5 NaN 79.8 NaN 77.1 NaN False False False True not
r1-dB b1 c2 e2-neg n1 172.6 27.5 120.8 65.6 86.9 35.6 False False False True not
r1-dB b1 c2 e2-neg n2 171.3 NaN 122.9 NaN 64.3 NaN False False False True not
r1-dB b1 c2 e2-pos n1 166.6 41.4 63.6 18.6 105.2 27.2 False False True True not
r1-dB b1 c2 e2-pos n2 161.9 NaN 59.1 NaN 96.4 NaN False False True True not
r1-dB b2-dark c1 e1 n1 137.0 22.0 53.7 2.1 56.0 17.1 False False False True not
r1-dB b2-dark c1 e1 n2 136.3 NaN 53.7 NaN 48.1 NaN False False False True not
r1-dB b2-dark c1 e2-neg n1 142.2 14.7 81.6 21.9 51.9 20.2 False False False True not
r1-dB b2-dark c1 e2-neg n2 141.0 NaN 83.6 NaN 40.1 NaN False False False True not
r1-dB b2-dark c1 e2-pos n1 135.5 31.2 46.0 9.0 63.5 12.5 False False False True not
r1-dB b2-dark c1 e2-pos n2 132.0 NaN 39.6 NaN 60.3 NaN False False False True not
r1-dB b2-dark c2 e1 n1 180.0 37.3 73.3 25.1 93.5 32.0 False False True True not
r1-dB b2-dark c2 e1 n2 178.6 NaN 79.4 NaN 77.0 NaN False False False True not
r1-dB b2-dark c2 e2-neg n1 188.8 36.1 121.4 67.4 87.0 35.8 True False False True partially
r1-dB b2-dark c2 e2-neg n2 184.8 NaN 123.5 NaN 64.1 NaN True False False True partially
r1-dB b2-dark c2 e2-pos n1 179.0 49.5 63.5 40.6 105.3 27.4 False False True True not
r1-dB b2-dark c2 e2-pos n2 172.9 NaN 58.5 NaN 96.4 NaN False False True True not
r1-dB b2-min c1 e1 n1 140.5 24.2 52.6 2.2 55.5 17.2 False False False True not
r1-dB b2-min c1 e1 n2 139.4 NaN 52.9 NaN 47.7 NaN False False False True not
r1-dB b2-min c1 e2-neg n1 146.4 16.1 80.8 22.5 51.5 20.3 False False False True not
r1-dB b2-min c1 e2-neg n2 144.6 NaN 83.1 NaN 39.6 NaN False False False True not
r1-dB b2-min c1 e2-pos n1 139.1 34.5 44.9 8.6 63.1 12.6 False False False True not
r1-dB b2-min c1 e2-pos n2 134.6 NaN 38.8 NaN 59.8 NaN False False False True not
r1-dB b2-min c2 e1 n1 187.3 41.0 72.4 25.6 93.6 32.3 True False True True partially
r1-dB b2-min c2 e1 n2 185.3 NaN 79.0 NaN 76.8 NaN True False False True partially
r1-dB b2-min c2 e2-neg n1 198.7 41.7 121.3 68.9 87.0 36.1 True False False True partially
r1-dB b2-min c2 e2-neg n2 192.3 NaN 124.2 NaN 63.8 NaN True False False True partially
r1-dB b2-min c2 e2-pos n1 186.6 54.9 63.7 41.7 105.5 27.7 True False True True partially
r1-dB b2-min c2 e2-pos n2 178.9 NaN 58.0 NaN 96.3 NaN False False True True not
Readings of the claims file (backgrounds ('b1', 'b2-dark', 'b2-min') ): combinations by outcome {'not': 95, 'partially': 13} of 108
1Px4: normalized center 121.7 to 301.3% over combinations, median 144.7%
5Px4: normalized center 38.8 to 170.0% over combinations, median 88.4%
10Px4: normalized center 39.6 to 289.6% over combinations, median 65.1%
1Px4 above both others in 96 of 108
Within tolerance: 1Px4 in 15 ; 5Px4 in 24 ; 10Px4 in 14
Combinations that are reproduced or partially reproduced:
layout bg center periphery norm 1Px4 1Px4_se 5Px4 5Px4_se 10Px4 10Px4_se in_1Px4 in_5Px4 in_10Px4 1Px4_highest outcome
r1-dA b2-dark c2 e1 n2 187.6 NaN 115.9 NaN 90.1 NaN True False True True partially
r1-dA b2-dark c2 e2-neg n2 188.5 NaN 90.3 NaN 186.8 NaN True True False True partially
r1-dA b2-dark c2 e2-pos n2 186.7 NaN 161.9 NaN 59.4 NaN True False False True partially
r1-dA b2-min c2 e1 n2 195.1 NaN 116.4 NaN 90.0 NaN True False False True partially
r1-dA b2-min c2 e2-neg n2 196.1 NaN 90.1 NaN 189.0 NaN True True False True partially
r1-dA b2-min c2 e2-pos n2 194.1 NaN 164.4 NaN 59.1 NaN True False False True partially
r1-dB b2-dark c2 e2-neg n1 188.8 36.1 121.4 67.4 87.0 35.8 True False False True partially
r1-dB b2-dark c2 e2-neg n2 184.8 NaN 123.5 NaN 64.1 NaN True False False True partially
r1-dB b2-min c2 e1 n1 187.3 41.0 72.4 25.6 93.6 32.3 True False True True partially
r1-dB b2-min c2 e1 n2 185.3 NaN 79.0 NaN 76.8 NaN True False False True partially
r1-dB b2-min c2 e2-neg n1 198.7 41.7 121.3 68.9 87.0 36.1 True False False True partially
r1-dB b2-min c2 e2-neg n2 192.3 NaN 124.2 NaN 63.8 NaN True False False True partially
r1-dB b2-min c2 e2-pos n1 186.6 54.9 63.7 41.7 105.5 27.7 True False True True partially
By background, combinations by outcome: {'b1': {'not': 36, 'partially': 0}, 'b2-dark': {'not': 31, 'partially': 5}, 'b2-fp': {'not': 29, 'partially': 7}, 'b2-min': {'not': 28, 'partially': 8}}
By layout and center, partial combinations: {('r1-dA', 'c2'): 6, ('r1-dB', 'c2'): 7}
Variant, ROI extent from the footprints (no pixel size): combinations by outcome {'not': 107, 'partially': 1} of 108 ; by background {'b1': {'not': 35, 'partially': 1}, 'b2-dark': {'not': 36, 'partially': 0}, 'b2-fp': {'not': 34, 'partially': 2}, 'b2-min': {'not': 36, 'partially': 0}}
1Px4: 104.9 to 284.8%, median 131.8%; within tolerance in 1
5Px4: 66.7 to 257.3%, median 112.6%; within tolerance in 36
10Px4: 47.5 to 166.9%, median 80.4%; within tolerance in 12
primary reading (r2, b1, c1, e1, n1): [{'1Px4': 116.1, '5Px4': 105.1, '10Px4': 68.0}]
# Per dish, primary reading (r2, c1, e1) under each background.
rows = []
for bg in cancan.BACKGROUNDS + cancan.VARIANT_BACKGROUNDS:
data = table("r2", bg)
for t in TREATMENTS:
pos, P = data[t]
ci = cancan.center_index(P.mean(0), "c1")
for d, p in zip(dishes[t], P):
rows.append({"bg": bg, "treatment": t, "dish": d["dish"],
"center_pct_of_periphery": round(float(cancan.center_value(p, ci)[0] / cancan.periphery(p, "e1")[0] * 100), 1),
"center_pct_neg_end": round(float(cancan.center_value(p, ci)[0] / p[0] * 100), 1),
"center_pct_pos_end": round(float(cancan.center_value(p, ci)[0] / p[-1] * 100), 1)})
print(pd.DataFrame(rows).to_string(index=False))
# Per dish, every partial combination: the center ROI is the one the combination reads from the mean profile.
print("\nPartial combinations, per dish (counts after the background is subtracted; the percent is per dish, before averaging):")
rows = []
for _, r in f6b[f6b.outcome == "partially"].iterrows():
data = table(r.layout, r.bg)
for t in TREATMENTS:
pos, P = data[t]
ci = cancan.center_index(cancan.mean_profile(P, r.periphery, r.norm), r.center)
for d, p in zip(dishes[t], P):
c, e = cancan.center_value(p, ci)[0], cancan.periphery(p, r.periphery)[0]
rows.append({"combination": f"{r.layout} {r.bg} {r.center} {r.periphery} {r.norm}", "treatment": t, "dish": d["dish"],
"center_pos_mm": round(float(np.mean(pos[ci])), 2), "center": round(c), "periphery": round(e), "pct": round(100 * c / e, 1),
"combination_value": round(r[t], 1)})
pdish = pd.DataFrame(rows)
print(pdish.to_string(index=False))
one = pdish[pdish.treatment == "1Px4"]
print("\n1Px4 per-dish percent over the partial combinations:", one.groupby("dish").pct.agg(["min", "median", "max"]).round(1).to_dict("index"))
# How the 1Px4 value depends on the size of the offset: one offset for every dish, from 0 to 300 counts.
print("\n1Px4 normalized center against a common offset subtracted from every dish (r2 c1 e1 n1, and the partial layouts with c2):")
offs = np.arange(0, 301, 25)
sweep = {}
for lay, cen, per, norm in [("r2", "c1", "e1", "n1"), ("r2", "c2", "e1", "n1"), ("r1-dA", "c2", "e1", "n2"), ("r1-dB", "c2", "e1", "n1")]:
_, P = table(lay, "b1")["1Px4"]
vals = []
for o in offs:
Q = cancan.mean_profile(P - o, per, norm)
vals.append(round(cancan.center_value(Q, cancan.center_index(Q, cen))[0], 1))
sweep[f"{lay} {cen} {per} {norm}"] = vals
print(pd.DataFrame(sweep, index=pd.Index(offs, name="offset")).T.to_string())
bg treatment dish center_pct_of_periphery center_pct_neg_end center_pct_pos_end
b1 1Px4 23 151.6 143.4 160.8
b1 1Px4 24 113.1 115.6 110.7
b1 1Px4 25 107.2 118.5 97.9
b1 5Px4 9 80.9 79.2 82.6
b1 5Px4 20 73.2 111.7 54.4
b1 5Px4 22 106.2 104.8 107.6
b1 10Px4 4 77.4 99.5 63.3
b1 10Px4 11 64.2 80.1 53.5
b1 10Px4 18 34.5 30.8 39.2
b2-dark 1Px4 23 160.0 150.0 171.4
b2-dark 1Px4 24 115.2 118.2 112.4
b2-dark 1Px4 25 108.6 122.4 97.6
b2-dark 5Px4 9 80.4 78.6 82.2
b2-dark 5Px4 20 72.7 112.0 53.9
b2-dark 5Px4 22 106.5 105.0 108.0
b2-dark 10Px4 4 77.1 99.5 63.0
b2-dark 10Px4 11 63.7 79.9 53.0
b2-dark 10Px4 18 34.2 30.5 38.8
b2-min 1Px4 23 165.3 154.1 178.1
b2-min 1Px4 24 116.2 119.4 113.1
b2-min 1Px4 25 109.4 124.7 97.4
b2-min 5Px4 9 79.7 78.0 81.6
b2-min 5Px4 20 72.5 112.2 53.5
b2-min 5Px4 22 106.9 105.3 108.5
b2-min 10Px4 4 76.8 99.5 62.6
b2-min 10Px4 11 63.1 79.4 52.3
b2-min 10Px4 18 33.7 30.1 38.4
b2-fp 1Px4 23 217.5 192.4 250.0
b2-fp 1Px4 24 122.8 127.6 118.3
b2-fp 1Px4 25 114.4 141.1 96.2
b2-fp 5Px4 9 78.4 76.6 80.4
b2-fp 5Px4 20 71.4 113.0 52.2
b2-fp 5Px4 22 107.6 105.9 109.3
b2-fp 10Px4 4 76.4 99.5 62.0
b2-fp 10Px4 11 62.0 78.6 51.1
b2-fp 10Px4 18 32.8 29.2 37.4
Partial combinations, per dish (counts after the background is subtracted; the percent is per dish, before averaging):
combination treatment dish center_pos_mm center periphery pct combination_value
r1-dA b2-dark c2 e1 n2 1Px4 23 0.13 1315 390 337.2 187.6
r1-dA b2-dark c2 e1 n2 1Px4 24 0.13 460 527 87.4 187.6
r1-dA b2-dark c2 e1 n2 1Px4 25 0.13 622 362 172.0 187.6
r1-dA b2-dark c2 e1 n2 5Px4 9 0.13 1270 1992 63.8 115.9
r1-dA b2-dark c2 e1 n2 5Px4 20 0.13 6305 4840 130.3 115.9
r1-dA b2-dark c2 e1 n2 5Px4 22 0.13 1957 1390 140.8 115.9
r1-dA b2-dark c2 e1 n2 10Px4 4 0.05 10796 2771 389.6 90.1
r1-dA b2-dark c2 e1 n2 10Px4 11 0.05 6280 9750 64.4 90.1
r1-dA b2-dark c2 e1 n2 10Px4 18 0.05 6077 13170 46.1 90.1
r1-dA b2-dark c2 e2-neg n2 1Px4 23 0.13 1315 407 323.0 188.5
r1-dA b2-dark c2 e2-neg n2 1Px4 24 0.13 460 452 101.9 188.5
r1-dA b2-dark c2 e2-neg n2 1Px4 25 0.13 622 413 150.5 188.5
r1-dA b2-dark c2 e2-neg n2 5Px4 9 0.13 1270 2748 46.2 90.3
r1-dA b2-dark c2 e2-neg n2 5Px4 20 0.13 6305 6700 94.1 90.3
r1-dA b2-dark c2 e2-neg n2 5Px4 22 0.13 1957 1108 176.6 90.3
r1-dA b2-dark c2 e2-neg n2 10Px4 4 0.05 10796 2203 490.1 186.8
r1-dA b2-dark c2 e2-neg n2 10Px4 11 0.05 6280 2291 274.1 186.8
r1-dA b2-dark c2 e2-neg n2 10Px4 18 0.05 6077 7901 76.9 186.8
r1-dA b2-dark c2 e2-pos n2 1Px4 23 0.13 1315 373 352.7 186.7
r1-dA b2-dark c2 e2-pos n2 1Px4 24 0.13 460 602 76.5 186.7
r1-dA b2-dark c2 e2-pos n2 1Px4 25 0.13 622 310 200.7 186.7
r1-dA b2-dark c2 e2-pos n2 5Px4 9 0.13 1270 1236 102.8 161.9
r1-dA b2-dark c2 e2-pos n2 5Px4 20 0.13 6305 2980 211.6 161.9
r1-dA b2-dark c2 e2-pos n2 5Px4 22 0.13 1957 1671 117.1 161.9
r1-dA b2-dark c2 e2-pos n2 10Px4 4 0.05 10796 3340 323.3 59.4
r1-dA b2-dark c2 e2-pos n2 10Px4 11 0.05 6280 17210 36.5 59.4
r1-dA b2-dark c2 e2-pos n2 10Px4 18 0.05 6077 18439 33.0 59.4
r1-dA b2-min c2 e1 n2 1Px4 23 0.13 1279 354 361.7 195.1
r1-dA b2-min c2 e1 n2 1Px4 24 0.13 429 495 86.6 195.1
r1-dA b2-min c2 e1 n2 1Px4 25 0.13 588 328 179.4 195.1
r1-dA b2-min c2 e1 n2 5Px4 9 0.13 1176 1898 62.0 116.4
r1-dA b2-min c2 e1 n2 5Px4 20 0.13 6255 4789 130.6 116.4
r1-dA b2-min c2 e1 n2 5Px4 22 0.13 1871 1304 143.5 116.4
r1-dA b2-min c2 e1 n2 10Px4 4 0.05 10697 2672 400.3 90.0
r1-dA b2-min c2 e1 n2 10Px4 11 0.05 6161 9631 64.0 90.0
r1-dA b2-min c2 e1 n2 10Px4 18 0.05 5985 13079 45.8 90.0
r1-dA b2-min c2 e2-neg n2 1Px4 23 0.13 1279 371 345.0 196.1
r1-dA b2-min c2 e2-neg n2 1Px4 24 0.13 429 420 102.0 196.1
r1-dA b2-min c2 e2-neg n2 1Px4 25 0.13 588 380 155.0 196.1
r1-dA b2-min c2 e2-neg n2 5Px4 9 0.13 1176 2654 44.3 90.1
r1-dA b2-min c2 e2-neg n2 5Px4 20 0.13 6255 6649 94.1 90.1
r1-dA b2-min c2 e2-neg n2 5Px4 22 0.13 1871 1022 183.1 90.1
r1-dA b2-min c2 e2-neg n2 10Px4 4 0.05 10697 2104 508.5 189.0
r1-dA b2-min c2 e2-neg n2 10Px4 11 0.05 6161 2172 283.7 189.0
r1-dA b2-min c2 e2-neg n2 10Px4 18 0.05 5985 7809 76.6 189.0
r1-dA b2-min c2 e2-pos n2 1Px4 23 0.13 1279 336 380.1 194.1
r1-dA b2-min c2 e2-pos n2 1Px4 24 0.13 429 570 75.2 194.1
r1-dA b2-min c2 e2-pos n2 1Px4 25 0.13 588 276 213.0 194.1
r1-dA b2-min c2 e2-pos n2 5Px4 9 0.13 1176 1142 103.0 164.4
r1-dA b2-min c2 e2-pos n2 5Px4 20 0.13 6255 2930 213.5 164.4
r1-dA b2-min c2 e2-pos n2 5Px4 22 0.13 1871 1585 118.0 164.4
r1-dA b2-min c2 e2-pos n2 10Px4 4 0.05 10697 3241 330.1 59.1
r1-dA b2-min c2 e2-pos n2 10Px4 11 0.05 6161 17091 36.0 59.1
r1-dA b2-min c2 e2-pos n2 10Px4 18 0.05 5985 18348 32.6 59.1
r1-dB b2-dark c2 e2-neg n1 1Px4 23 0.23 777 457 170.2 188.8
r1-dB b2-dark c2 e2-neg n1 1Px4 24 0.23 696 505 137.7 188.8
r1-dB b2-dark c2 e2-neg n1 1Px4 25 0.23 744 288 258.4 188.8
r1-dB b2-dark c2 e2-neg n1 5Px4 9 -0.13 1342 3039 44.2 121.4
r1-dB b2-dark c2 e2-neg n1 5Px4 20 -0.13 7321 2862 255.8 121.4
r1-dB b2-dark c2 e2-neg n1 5Px4 22 -0.13 1491 2320 64.3 121.4
r1-dB b2-dark c2 e2-neg n1 10Px4 4 0.16 11917 7894 151.0 87.0
r1-dB b2-dark c2 e2-neg n1 10Px4 11 0.16 7663 9226 83.1 87.0
r1-dB b2-dark c2 e2-neg n1 10Px4 18 0.16 6256 23199 27.0 87.0
r1-dB b2-dark c2 e2-neg n2 1Px4 23 0.16 1073 457 234.9 184.8
r1-dB b2-dark c2 e2-neg n2 1Px4 24 0.16 719 505 142.2 184.8
r1-dB b2-dark c2 e2-neg n2 1Px4 25 0.16 518 288 179.9 184.8
r1-dB b2-dark c2 e2-neg n2 5Px4 9 -0.13 1342 3039 44.2 123.5
r1-dB b2-dark c2 e2-neg n2 5Px4 20 -0.13 7321 2862 255.8 123.5
r1-dB b2-dark c2 e2-neg n2 5Px4 22 -0.13 1491 2320 64.3 123.5
r1-dB b2-dark c2 e2-neg n2 10Px4 4 0.16 11917 7894 151.0 64.1
r1-dB b2-dark c2 e2-neg n2 10Px4 11 0.16 7663 9226 83.1 64.1
r1-dB b2-dark c2 e2-neg n2 10Px4 18 0.16 6256 23199 27.0 64.1
r1-dB b2-min c2 e1 n1 1Px4 23 0.16 1036 385 269.1 187.3
r1-dB b2-min c2 e1 n1 1Px4 24 0.16 688 487 141.1 187.3
r1-dB b2-min c2 e1 n1 1Px4 25 0.16 484 319 151.8 187.3
r1-dB b2-min c2 e1 n1 5Px4 9 -0.13 1248 4386 28.5 72.4
r1-dB b2-min c2 e1 n1 5Px4 20 -0.13 7270 6210 117.1 72.4
r1-dB b2-min c2 e1 n1 5Px4 22 -0.13 1405 1960 71.7 72.4
r1-dB b2-min c2 e1 n1 10Px4 4 0.16 11818 8074 146.4 93.6
r1-dB b2-min c2 e1 n1 10Px4 11 0.16 7544 7598 99.3 93.6
r1-dB b2-min c2 e1 n1 10Px4 18 0.16 6165 17586 35.1 93.6
r1-dB b2-min c2 e1 n2 1Px4 23 0.16 1036 385 269.1 185.3
r1-dB b2-min c2 e1 n2 1Px4 24 0.16 688 487 141.1 185.3
r1-dB b2-min c2 e1 n2 1Px4 25 0.16 484 319 151.8 185.3
r1-dB b2-min c2 e1 n2 5Px4 9 -0.13 1248 4386 28.5 79.0
r1-dB b2-min c2 e1 n2 5Px4 20 -0.13 7270 6210 117.1 79.0
r1-dB b2-min c2 e1 n2 5Px4 22 -0.13 1405 1960 71.7 79.0
r1-dB b2-min c2 e1 n2 10Px4 4 0.16 11818 8074 146.4 76.8
r1-dB b2-min c2 e1 n2 10Px4 11 0.16 7544 7598 99.3 76.8
r1-dB b2-min c2 e1 n2 10Px4 18 0.16 6165 17586 35.1 76.8
r1-dB b2-min c2 e2-neg n1 1Px4 23 0.23 741 420 176.2 198.7
r1-dB b2-min c2 e2-neg n1 1Px4 24 0.23 665 474 140.2 198.7
r1-dB b2-min c2 e2-neg n1 1Px4 25 0.23 710 254 279.5 198.7
r1-dB b2-min c2 e2-neg n1 5Px4 9 -0.13 1248 2945 42.4 121.3
r1-dB b2-min c2 e2-neg n1 5Px4 20 -0.13 7270 2812 258.6 121.3
r1-dB b2-min c2 e2-neg n1 5Px4 22 -0.13 1405 2234 62.9 121.3
r1-dB b2-min c2 e2-neg n1 10Px4 4 0.16 11818 7795 151.6 87.0
r1-dB b2-min c2 e2-neg n1 10Px4 11 0.16 7544 9107 82.8 87.0
r1-dB b2-min c2 e2-neg n1 10Px4 18 0.16 6165 23107 26.7 87.0
r1-dB b2-min c2 e2-neg n2 1Px4 23 0.16 1036 420 246.6 192.3
r1-dB b2-min c2 e2-neg n2 1Px4 24 0.16 688 474 145.0 192.3
r1-dB b2-min c2 e2-neg n2 1Px4 25 0.16 484 254 190.6 192.3
r1-dB b2-min c2 e2-neg n2 5Px4 9 -0.13 1248 2945 42.4 124.2
r1-dB b2-min c2 e2-neg n2 5Px4 20 -0.13 7270 2812 258.6 124.2
r1-dB b2-min c2 e2-neg n2 5Px4 22 -0.13 1405 2234 62.9 124.2
r1-dB b2-min c2 e2-neg n2 10Px4 4 0.16 11818 7795 151.6 63.8
r1-dB b2-min c2 e2-neg n2 10Px4 11 0.16 7544 9107 82.8 63.8
r1-dB b2-min c2 e2-neg n2 10Px4 18 0.16 6165 23107 26.7 63.8
r1-dB b2-min c2 e2-pos n1 1Px4 23 0.16 1036 350 296.2 186.6
r1-dB b2-min c2 e2-pos n1 1Px4 24 0.16 688 500 137.4 186.6
r1-dB b2-min c2 e2-pos n1 1Px4 25 0.16 484 384 126.1 186.6
r1-dB b2-min c2 e2-pos n1 5Px4 9 0.16 1397 5827 24.0 63.7
r1-dB b2-min c2 e2-pos n1 5Px4 20 0.16 1928 9608 20.1 63.7
r1-dB b2-min c2 e2-pos n1 5Px4 22 0.16 2477 1685 147.0 63.7
r1-dB b2-min c2 e2-pos n1 10Px4 4 0.16 11818 8352 141.5 105.5
r1-dB b2-min c2 e2-pos n1 10Px4 11 0.16 7544 6089 123.9 105.5
r1-dB b2-min c2 e2-pos n1 10Px4 18 0.16 6165 12064 51.1 105.5
1Px4 per-dish percent over the partial combinations: {23: {'min': 170.2, 'median': 296.2, 'max': 380.1}, 24: {'min': 75.2, 'median': 137.4, 'max': 145.0}, 25: {'min': 126.1, 'median': 179.4, 'max': 279.5}}
1Px4 normalized center against a common offset subtracted from every dish (r2 c1 e1 n1, and the partial layouts with c2):
offset 0 25 50 75 100 125 150 175 200 225 250 275 300
r2 c1 e1 n1 124.0 125.2 126.5 127.9 129.5 131.3 133.3 135.6 138.3 141.4 145.1 149.5 154.8
r2 c2 e1 n1 139.5 141.5 143.7 146.2 149.0 152.1 155.7 159.8 164.6 170.3 177.0 185.1 195.2
r1-dA c2 e1 n2 173.9 177.7 182.0 186.8 192.1 198.2 205.1 213.1 222.3 233.3 246.3 262.3 282.0
r1-dB c2 e1 n1 167.7 171.3 175.3 179.8 184.9 190.7 197.3 205.0 214.1 224.9 238.1 256.4 281.2
Result: partially reproduced. Under the primary reading (both diagonals, raw counts, the two central ROIs, the mean of the two ends, each dish normalized) the center is 124.0% of the periphery for 1Px4, 86.7% for 5Px4 and 58.7% for 10Px4; per dish 107.2 to 151.6%, 73.2 to 106.2% and 34.5 to 77.4%. No combination of readings puts all three values within tolerance. 1Px4 is within 180 to 220% and above both others in 13 of the 108 combinations of the claims file's readings, which meets its rule for a partial reproduction: 5 with the dark offset b2-dark and 8 with b2-min, none with raw counts, and all on a single diagonal with the peak taken as the highest ROI between the minima (c2). These rows are fragile. Their center is one ROI 36 um wide, and across them 1Px4 per dish is 170.2 to 380.1% for dish 23, 75.2 to 145.0% for dish 24 and 126.1 to 279.5% for dish 25. The 1Px4 value on diagonal A with c2, e1 and n2 passes 180% once a common offset of 50 counts is subtracted, less than every dark offset estimated here, and stays within 220% up to 175 counts (222.3% at 200); this sweep covers 1Px4 only and does not check the order against 5Px4 and 10Px4. On both diagonals with c1 it stays below 155% for offsets up to 300 counts. 1Px4 is above both others in 96 of 108. 10Px4 is within 90 to 110% in 14 of 108, and is below its periphery under the primary reading. With the ROI extent from the footprints, 1 of 108 combinations is partial (raw counts) and none reproduced (primary 116.1, 105.1 and 68.0%). The variant b2-fp, outside the readings, gives 7 partial of 36. So the ranking holds, "almost twofold" for 1Px4 is reached only on a single diagonal with a dark offset subtracted, and the 40-packet center is mostly well below its periphery, not "about the same".
fig6-trough-half-of-center¶
For all packet numbers the central peak was clearly discernible, and the least affected area of the monolayer, between the center and the electrodes, showed about 2-fold lower intensity than the center.
Criterion (claims file): the least affected area is the minimum of the mean profile between the center and the most peripheral ROI on each side, (t1) the mean of the two sides or (t2) each side; reproduced when center over least affected area is within 1.8 to 2.2 for all three treatments; partially reproduced when within tolerance for one or two and above 1 for all.
def trough_table(extent):
rows = []
for lay in cancan.LAYOUTS:
for bg in cancan.BACKGROUNDS + cancan.VARIANT_BACKGROUNDS:
data = table(lay, bg, extent)
for cen in cancan.CENTERS:
for norm in cancan.NORMALIZATIONS:
for per in (cancan.PERIPHERIES if norm == "n1" else ("e1",)):
for tro in cancan.TROUGHS:
row = {"layout": lay, "bg": bg, "center": cen, "norm": norm, "periphery": per, "trough": tro}
for t in TREATMENTS:
pos, P = data[t]
Q = cancan.mean_profile(P, per, norm)
ci, mins = cancan.center_index(Q, cen), cancan.side_minima(Q)
row[t] = cancan.center_value(Q, ci)[0] / cancan.trough_value(Q, mins, tro)[0]
rows.append(row)
ftr = pd.DataFrame(rows)
inside = ftr[TREATMENTS].apply(lambda s: s.between(1.8, 2.2))
ftr["n_within"] = inside.sum(axis=1)
ftr["all_above_1"] = (ftr[TREATMENTS] > 1).all(axis=1)
ftr["outcome"] = np.where(ftr.n_within == 3, "reproduced",
np.where((ftr.n_within >= 1) & ftr.all_above_1, "partially", "not"))
keep = ftr.bg.isin(cancan.BACKGROUNDS)
return ftr, inside, keep
allftr, allinside, keep = trough_table("camera")
ftr, inside = allftr[keep], allinside[keep]
print("Rows with n2 do not depend on the periphery reading and are shown once (e1).")
print(ftr.round(2).to_string(index=False))
print("\nReadings of the claims file (backgrounds", cancan.BACKGROUNDS, "): combinations by outcome", ftr.outcome.value_counts().to_dict(), "of", len(ftr))
for t in TREATMENTS:
print(f"{t}: center / least affected {ftr[t].min():.2f} to {ftr[t].max():.2f}, median {ftr[t].median():.2f}; within 1.8-2.2 in {int(inside[t].sum())} of {len(ftr)}")
print("Above 1 for all three treatments in", int(ftr.all_above_1.sum()), "of", len(ftr))
print("By background, combinations by outcome:", allftr.groupby("bg").outcome.value_counts().unstack(fill_value=0).to_dict("index"))
print("10Px4 by background, range:", allftr.groupby("bg")["10Px4"].agg(["min", "max"]).round(2).to_dict("index"))
gtr, ginside, gkeep = trough_table("geometric")
print("\nVariant, ROI extent from the footprints (no pixel size): combinations by outcome", gtr[gkeep].outcome.value_counts().to_dict(), "of", int(gkeep.sum()))
for t in TREATMENTS:
print(f" {t}: {gtr[gkeep][t].min():.2f} to {gtr[gkeep][t].max():.2f}, median {gtr[gkeep][t].median():.2f}; within 1.8-2.2 in {int(ginside[gkeep][t].sum())}")
Rows with n2 do not depend on the periphery reading and are shown once (e1).
layout bg center norm periphery trough 1Px4 5Px4 10Px4 n_within all_above_1 outcome
r2 b1 c1 n1 e1 t1 1.40 2.16 2.80 1 True partially
r2 b1 c1 n1 e1 t2-neg 1.48 2.02 2.95 1 True partially
r2 b1 c1 n1 e1 t2-pos 1.33 2.33 2.67 0 True not
r2 b1 c1 n1 e2-neg t1 1.40 2.20 2.84 0 True not
r2 b1 c1 n1 e2-neg t2-neg 1.47 2.07 2.99 1 True partially
r2 b1 c1 n1 e2-neg t2-pos 1.33 2.36 2.70 0 True not
r2 b1 c1 n1 e2-pos t1 1.41 2.14 2.77 1 True partially
r2 b1 c1 n1 e2-pos t2-neg 1.49 2.00 2.90 1 True partially
r2 b1 c1 n1 e2-pos t2-pos 1.33 2.31 2.66 0 True not
r2 b1 c1 n2 e1 t1 1.41 2.29 2.75 0 True not
r2 b1 c1 n2 e1 t2-neg 1.48 2.15 2.84 1 True partially
r2 b1 c1 n2 e1 t2-pos 1.34 2.45 2.67 0 True not
r2 b1 c2 n1 e1 t1 1.57 2.29 3.38 0 True not
r2 b1 c2 n1 e1 t2-neg 1.67 2.14 3.56 1 True partially
r2 b1 c2 n1 e1 t2-pos 1.49 2.46 3.23 0 True not
r2 b1 c2 n1 e2-neg t1 1.57 2.35 3.45 0 True not
r2 b1 c2 n1 e2-neg t2-neg 1.66 2.20 3.63 0 True not
r2 b1 c2 n1 e2-neg t2-pos 1.49 2.52 3.28 0 True not
r2 b1 c2 n1 e2-pos t1 1.58 2.25 3.32 0 True not
r2 b1 c2 n1 e2-pos t2-neg 1.67 2.10 3.47 1 True partially
r2 b1 c2 n1 e2-pos t2-pos 1.50 2.42 3.19 0 True not
r2 b1 c2 n2 e1 t1 1.56 2.43 3.27 0 True not
r2 b1 c2 n2 e1 t2-neg 1.64 2.28 3.38 0 True not
r2 b1 c2 n2 e1 t2-pos 1.49 2.60 3.17 0 True not
r2 b2-dark c1 n1 e1 t1 1.48 2.25 2.89 0 True not
r2 b2-dark c1 n1 e1 t2-neg 1.58 2.09 3.04 1 True partially
r2 b2-dark c1 n1 e1 t2-pos 1.39 2.43 2.75 0 True not
r2 b2-dark c1 n1 e2-neg t1 1.47 2.29 2.93 0 True not
r2 b2-dark c1 n1 e2-neg t2-neg 1.57 2.14 3.09 1 True partially
r2 b2-dark c1 n1 e2-neg t2-pos 1.39 2.47 2.78 0 True not
r2 b2-dark c1 n1 e2-pos t1 1.48 2.23 2.86 0 True not
r2 b2-dark c1 n1 e2-pos t2-neg 1.59 2.07 2.99 1 True partially
r2 b2-dark c1 n1 e2-pos t2-pos 1.39 2.41 2.73 0 True not
r2 b2-dark c1 n2 e1 t1 1.49 2.38 2.83 0 True not
r2 b2-dark c1 n2 e1 t2-neg 1.58 2.23 2.93 0 True not
r2 b2-dark c1 n2 e1 t2-pos 1.40 2.56 2.74 0 True not
r2 b2-dark c2 n1 e1 t1 1.69 2.38 3.50 0 True not
r2 b2-dark c2 n1 e1 t2-neg 1.81 2.22 3.68 1 True partially
r2 b2-dark c2 n1 e1 t2-pos 1.58 2.58 3.33 0 True not
r2 b2-dark c2 n1 e2-neg t1 1.69 2.45 3.57 0 True not
r2 b2-dark c2 n1 e2-neg t2-neg 1.80 2.29 3.76 0 True not
r2 b2-dark c2 n1 e2-neg t2-pos 1.59 2.64 3.39 0 True not
r2 b2-dark c2 n1 e2-pos t1 1.69 2.34 3.43 0 True not
r2 b2-dark c2 n1 e2-pos t2-neg 1.82 2.17 3.60 2 True partially
r2 b2-dark c2 n1 e2-pos t2-pos 1.59 2.54 3.28 0 True not
r2 b2-dark c2 n2 e1 t1 1.67 2.53 3.38 0 True not
r2 b2-dark c2 n2 e1 t2-neg 1.78 2.37 3.49 0 True not
r2 b2-dark c2 n2 e1 t2-pos 1.58 2.73 3.27 0 True not
r2 b2-min c1 n1 e1 t1 1.52 2.36 3.01 0 True not
r2 b2-min c1 n1 e1 t2-neg 1.64 2.18 3.18 1 True partially
r2 b2-min c1 n1 e1 t2-pos 1.42 2.57 2.86 0 True not
r2 b2-min c1 n1 e2-neg t1 1.52 2.39 3.06 0 True not
r2 b2-min c1 n1 e2-neg t2-neg 1.63 2.22 3.24 0 True not
r2 b2-min c1 n1 e2-neg t2-pos 1.42 2.60 2.89 0 True not
r2 b2-min c1 n1 e2-pos t1 1.53 2.34 2.97 0 True not
r2 b2-min c1 n1 e2-pos t2-neg 1.65 2.16 3.12 1 True partially
r2 b2-min c1 n1 e2-pos t2-pos 1.43 2.56 2.84 0 True not
r2 b2-min c1 n2 e1 t1 1.53 2.49 2.94 0 True not
r2 b2-min c1 n2 e1 t2-neg 1.64 2.31 3.05 0 True not
r2 b2-min c1 n2 e1 t2-pos 1.44 2.70 2.84 0 True not
r2 b2-min c2 n1 e1 t1 1.75 2.50 3.66 0 True not
r2 b2-min c2 n1 e1 t2-neg 1.89 2.31 3.87 1 True partially
r2 b2-min c2 n1 e1 t2-pos 1.63 2.73 3.47 0 True not
r2 b2-min c2 n1 e2-neg t1 1.75 2.57 3.73 0 True not
r2 b2-min c2 n1 e2-neg t2-neg 1.88 2.38 3.96 1 True partially
r2 b2-min c2 n1 e2-neg t2-pos 1.64 2.78 3.54 0 True not
r2 b2-min c2 n1 e2-pos t1 1.76 2.47 3.59 0 True not
r2 b2-min c2 n1 e2-pos t2-neg 1.90 2.27 3.77 1 True partially
r2 b2-min c2 n1 e2-pos t2-pos 1.64 2.69 3.42 0 True not
r2 b2-min c2 n2 e1 t1 1.73 2.65 3.52 0 True not
r2 b2-min c2 n2 e1 t2-neg 1.85 2.46 3.65 1 True partially
r2 b2-min c2 n2 e1 t2-pos 1.63 2.87 3.40 0 True not
r1-dA b1 c1 n1 e1 t1 1.66 2.86 4.46 0 True not
r1-dA b1 c1 n1 e1 t2-neg 1.74 2.75 5.07 0 True not
r1-dA b1 c1 n1 e1 t2-pos 1.58 2.97 3.99 0 True not
r1-dA b1 c1 n1 e2-neg t1 1.64 2.60 4.14 0 True not
r1-dA b1 c1 n1 e2-neg t2-neg 1.72 2.52 4.68 0 True not
r1-dA b1 c1 n1 e2-neg t2-pos 1.57 2.69 3.72 0 True not
r1-dA b1 c1 n1 e2-pos t1 1.67 3.16 4.59 0 True not
r1-dA b1 c1 n1 e2-pos t2-neg 1.75 3.00 5.19 0 True not
r1-dA b1 c1 n1 e2-pos t2-pos 1.60 3.34 4.11 0 True not
r1-dA b1 c1 n2 e1 t1 1.64 3.07 4.11 0 True not
r1-dA b1 c1 n2 e1 t2-neg 1.71 2.89 4.43 0 True not
r1-dA b1 c1 n2 e1 t2-pos 1.58 3.28 3.83 0 True not
r1-dA b1 c2 n1 e1 t1 2.68 3.15 7.24 0 True not
r1-dA b1 c2 n1 e1 t2-neg 2.82 3.03 8.23 0 True not
r1-dA b1 c2 n1 e1 t2-pos 2.56 3.28 6.47 0 True not
r1-dA b1 c2 n1 e2-neg t1 2.13 3.01 6.30 1 True partially
r1-dA b1 c2 n1 e2-neg t2-neg 2.24 2.91 7.12 0 True not
r1-dA b1 c2 n1 e2-neg t2-pos 2.04 3.11 5.66 1 True partially
r1-dA b1 c2 n1 e2-pos t1 2.88 3.34 7.56 0 True not
r1-dA b1 c2 n1 e2-pos t2-neg 3.02 3.17 8.55 0 True not
r1-dA b1 c2 n1 e2-pos t2-pos 2.75 3.52 6.77 0 True not
r1-dA b1 c2 n2 e1 t1 2.10 3.47 6.02 1 True partially
r1-dA b1 c2 n2 e1 t2-neg 2.19 3.27 6.49 1 True partially
r1-dA b1 c2 n2 e1 t2-pos 2.02 3.71 5.61 1 True partially
r1-dA b2-dark c1 n1 e1 t1 1.81 3.03 4.72 1 True partially
r1-dA b2-dark c1 n1 e1 t2-neg 1.93 2.90 5.41 1 True partially
r1-dA b2-dark c1 n1 e1 t2-pos 1.71 3.16 4.18 0 True not
r1-dA b2-dark c1 n1 e2-neg t1 1.79 2.74 4.35 0 True not
r1-dA b2-dark c1 n1 e2-neg t2-neg 1.90 2.64 4.96 1 True partially
r1-dA b2-dark c1 n1 e2-neg t2-pos 1.69 2.85 3.88 0 True not
r1-dA b2-dark c1 n1 e2-pos t1 1.84 3.38 4.86 1 True partially
r1-dA b2-dark c1 n1 e2-pos t2-neg 1.95 3.19 5.54 1 True partially
r1-dA b2-dark c1 n1 e2-pos t2-pos 1.74 3.59 4.33 0 True not
r1-dA b2-dark c1 n2 e1 t1 1.79 3.26 4.33 0 True not
r1-dA b2-dark c1 n2 e1 t2-neg 1.89 3.05 4.69 1 True partially
r1-dA b2-dark c1 n2 e1 t2-pos 1.70 3.50 4.01 0 True not
r1-dA b2-dark c2 n1 e1 t1 3.12 3.35 7.71 0 True not
r1-dA b2-dark c2 n1 e1 t2-neg 3.32 3.21 8.85 0 True not
r1-dA b2-dark c2 n1 e1 t2-pos 2.95 3.49 6.83 0 True not
r1-dA b2-dark c2 n1 e2-neg t1 2.39 3.20 6.67 0 True not
r1-dA b2-dark c2 n1 e2-neg t2-neg 2.54 3.09 7.60 0 True not
r1-dA b2-dark c2 n1 e2-neg t2-pos 2.26 3.33 5.94 0 True not
r1-dA b2-dark c2 n1 e2-pos t1 3.42 3.56 8.07 0 True not
r1-dA b2-dark c2 n1 e2-pos t2-neg 3.63 3.36 9.20 0 True not
r1-dA b2-dark c2 n1 e2-pos t2-pos 3.24 3.78 7.18 0 True not
r1-dA b2-dark c2 n2 e1 t1 2.36 3.69 6.36 0 True not
r1-dA b2-dark c2 n2 e1 t2-neg 2.49 3.45 6.90 0 True not
r1-dA b2-dark c2 n2 e1 t2-pos 2.24 3.97 5.90 0 True not
r1-dA b2-min c1 n1 e1 t1 1.91 3.26 5.07 1 True partially
r1-dA b2-min c1 n1 e1 t2-neg 2.05 3.11 5.90 1 True partially
r1-dA b2-min c1 n1 e1 t2-pos 1.80 3.42 4.44 0 True not
r1-dA b2-min c1 n1 e2-neg t1 1.88 2.93 4.67 1 True partially
r1-dA b2-min c1 n1 e2-neg t2-neg 2.01 2.81 5.40 1 True partially
r1-dA b2-min c1 n1 e2-neg t2-pos 1.76 3.06 4.11 0 True not
r1-dA b2-min c1 n1 e2-pos t1 1.95 3.67 5.24 1 True partially
r1-dA b2-min c1 n1 e2-pos t2-neg 2.08 3.45 6.04 1 True partially
r1-dA b2-min c1 n1 e2-pos t2-pos 1.83 3.92 4.63 1 True partially
r1-dA b2-min c1 n2 e1 t1 1.88 3.48 4.64 1 True partially
r1-dA b2-min c1 n2 e1 t2-neg 1.99 3.23 5.06 1 True partially
r1-dA b2-min c1 n2 e1 t2-pos 1.78 3.76 4.27 0 True not
r1-dA b2-min c2 n1 e1 t1 3.40 3.62 8.35 0 True not
r1-dA b2-min c2 n1 e1 t2-neg 3.63 3.45 9.73 0 True not
r1-dA b2-min c2 n1 e1 t2-pos 3.19 3.79 7.32 0 True not
r1-dA b2-min c2 n1 e2-neg t1 2.56 3.48 7.20 0 True not
r1-dA b2-min c2 n1 e2-neg t2-neg 2.73 3.33 8.32 0 True not
r1-dA b2-min c2 n1 e2-neg t2-pos 2.40 3.63 6.34 0 True not
r1-dA b2-min c2 n1 e2-pos t1 3.78 3.85 8.77 0 True not
r1-dA b2-min c2 n1 e2-pos t2-neg 4.04 3.62 10.11 0 True not
r1-dA b2-min c2 n1 e2-pos t2-pos 3.55 4.12 7.74 0 True not
r1-dA b2-min c2 n2 e1 t1 2.51 3.96 6.86 0 True not
r1-dA b2-min c2 n2 e1 t2-neg 2.66 3.68 7.50 0 True not
r1-dA b2-min c2 n2 e1 t2-pos 2.37 4.28 6.32 0 True not
r1-dB b1 c1 n1 e1 t1 1.45 2.05 3.71 1 True partially
r1-dB b1 c1 n1 e1 t2-neg 1.60 2.03 3.73 1 True partially
r1-dB b1 c1 n1 e1 t2-pos 1.33 2.07 3.70 1 True partially
r1-dB b1 c1 n1 e2-neg t1 1.43 2.34 3.79 0 True not
r1-dB b1 c1 n1 e2-neg t2-neg 1.57 2.50 3.72 0 True not
r1-dB b1 c1 n1 e2-neg t2-pos 1.32 2.21 3.86 0 True not
r1-dB b1 c1 n1 e2-pos t1 1.48 1.91 3.60 1 True partially
r1-dB b1 c1 n1 e2-pos t2-neg 1.62 1.86 3.71 1 True partially
r1-dB b1 c1 n1 e2-pos t2-pos 1.36 1.95 3.50 1 True partially
r1-dB b1 c1 n2 e1 t1 1.47 2.41 3.49 0 True not
r1-dB b1 c1 n2 e1 t2-neg 1.61 2.60 3.55 0 True not
r1-dB b1 c1 n2 e1 t2-pos 1.35 2.25 3.43 0 True not
r1-dB b1 c2 n1 e1 t1 1.85 2.77 6.16 1 True partially
r1-dB b1 c2 n1 e1 t2-neg 2.04 2.75 6.19 1 True partially
r1-dB b1 c2 n1 e1 t2-pos 1.70 2.79 6.14 0 True not
r1-dB b1 c2 n1 e2-neg t1 1.83 3.45 6.32 1 True partially
r1-dB b1 c2 n1 e2-neg t2-neg 2.00 3.67 6.21 1 True partially
r1-dB b1 c2 n1 e2-neg t2-pos 1.68 3.25 6.43 0 True not
r1-dB b1 c2 n1 e2-pos t1 1.90 2.59 5.94 1 True partially
r1-dB b1 c2 n1 e2-pos t2-neg 2.08 2.52 6.11 1 True partially
r1-dB b1 c2 n1 e2-pos t2-pos 1.74 2.65 5.77 0 True not
r1-dB b1 c2 n2 e1 t1 1.87 3.53 5.54 1 True partially
r1-dB b1 c2 n2 e1 t2-neg 2.05 3.80 5.64 1 True partially
r1-dB b1 c2 n2 e1 t2-pos 1.72 3.29 5.45 0 True not
r1-dB b2-dark c1 n1 e1 t1 1.54 2.13 3.87 1 True partially
r1-dB b2-dark c1 n1 e1 t2-neg 1.73 2.11 3.89 1 True partially
r1-dB b2-dark c1 n1 e1 t2-pos 1.39 2.15 3.86 1 True partially
r1-dB b2-dark c1 n1 e2-neg t1 1.51 2.46 3.96 0 True not
r1-dB b2-dark c1 n1 e2-neg t2-neg 1.69 2.63 3.88 0 True not
r1-dB b2-dark c1 n1 e2-neg t2-pos 1.37 2.30 4.03 0 True not
r1-dB b2-dark c1 n1 e2-pos t1 1.58 1.98 3.76 1 True partially
r1-dB b2-dark c1 n1 e2-pos t2-neg 1.77 1.93 3.88 1 True partially
r1-dB b2-dark c1 n1 e2-pos t2-pos 1.43 2.03 3.65 1 True partially
r1-dB b2-dark c1 n2 e1 t1 1.57 2.53 3.63 0 True not
r1-dB b2-dark c1 n2 e1 t2-neg 1.75 2.74 3.69 0 True not
r1-dB b2-dark c1 n2 e1 t2-pos 1.42 2.35 3.56 0 True not
r1-dB b2-dark c2 n1 e1 t1 2.03 2.91 6.47 1 True partially
r1-dB b2-dark c2 n1 e1 t2-neg 2.27 2.88 6.50 0 True not
r1-dB b2-dark c2 n1 e1 t2-pos 1.83 2.94 6.45 1 True partially
r1-dB b2-dark c2 n1 e2-neg t1 2.01 3.65 6.63 1 True partially
r1-dB b2-dark c2 n1 e2-neg t2-neg 2.24 3.91 6.51 0 True not
r1-dB b2-dark c2 n1 e2-neg t2-pos 1.82 3.42 6.76 1 True partially
r1-dB b2-dark c2 n1 e2-pos t1 2.09 2.73 6.23 1 True partially
r1-dB b2-dark c2 n1 e2-pos t2-neg 2.34 2.66 6.43 0 True not
r1-dB b2-dark c2 n1 e2-pos t2-pos 1.88 2.81 6.05 1 True partially
r1-dB b2-dark c2 n2 e1 t1 2.05 3.74 5.80 1 True partially
r1-dB b2-dark c2 n2 e1 t2-neg 2.29 4.06 5.90 0 True not
r1-dB b2-dark c2 n2 e1 t2-pos 1.86 3.47 5.70 1 True partially
r1-dB b2-min c1 n1 e1 t1 1.60 2.24 4.11 0 True not
r1-dB b2-min c1 n1 e1 t2-neg 1.81 2.21 4.13 1 True partially
r1-dB b2-min c1 n1 e1 t2-pos 1.43 2.27 4.09 0 True not
r1-dB b2-min c1 n1 e2-neg t1 1.56 2.59 4.20 0 True not
r1-dB b2-min c1 n1 e2-neg t2-neg 1.76 2.78 4.11 0 True not
r1-dB b2-min c1 n1 e2-neg t2-pos 1.40 2.41 4.28 0 True not
r1-dB b2-min c1 n1 e2-pos t1 1.64 2.08 3.99 1 True partially
r1-dB b2-min c1 n1 e2-pos t2-neg 1.86 2.02 4.13 2 True partially
r1-dB b2-min c1 n1 e2-pos t2-pos 1.47 2.14 3.86 1 True partially
r1-dB b2-min c1 n2 e1 t1 1.62 2.67 3.82 0 True not
r1-dB b2-min c1 n2 e1 t2-neg 1.83 2.92 3.90 1 True partially
r1-dB b2-min c1 n2 e1 t2-pos 1.46 2.47 3.75 0 True not
r1-dB b2-min c2 n1 e1 t1 2.13 3.08 6.93 1 True partially
r1-dB b2-min c2 n1 e1 t2-neg 2.42 3.04 6.96 0 True not
r1-dB b2-min c2 n1 e1 t2-pos 1.90 3.13 6.89 1 True partially
r1-dB b2-min c2 n1 e2-neg t1 2.12 3.88 7.10 1 True partially
r1-dB b2-min c2 n1 e2-neg t2-neg 2.39 4.17 6.95 0 True not
r1-dB b2-min c2 n1 e2-neg t2-pos 1.90 3.62 7.24 1 True partially
r1-dB b2-min c2 n1 e2-pos t1 2.20 2.95 6.67 0 True not
r1-dB b2-min c2 n1 e2-pos t2-neg 2.50 2.87 6.90 0 True not
r1-dB b2-min c2 n1 e2-pos t2-pos 1.97 3.04 6.45 1 True partially
r1-dB b2-min c2 n2 e1 t1 2.16 4.00 6.16 1 True partially
r1-dB b2-min c2 n2 e1 t2-neg 2.44 4.37 6.27 0 True not
r1-dB b2-min c2 n2 e1 t2-pos 1.94 3.68 6.04 1 True partially
Readings of the claims file (backgrounds ('b1', 'b2-dark', 'b2-min') ): combinations by outcome {'not': 137, 'partially': 79} of 216
1Px4: center / least affected 1.32 to 4.04, median 1.74; within 1.8-2.2 in 52 of 216
5Px4: center / least affected 1.86 to 4.37, median 2.69; within 1.8-2.2 in 29 of 216
10Px4: center / least affected 2.66 to 10.11, median 4.11; within 1.8-2.2 in 0 of 216
Above 1 for all three treatments in 216 of 216
By background, combinations by outcome: {'b1': {'not': 45, 'partially': 27}, 'b2-dark': {'not': 47, 'partially': 25}, 'b2-fp': {'not': 58, 'partially': 14}, 'b2-min': {'not': 45, 'partially': 27}}
10Px4 by background, range: {'b1': {'min': 2.66, 'max': 8.55}, 'b2-dark': {'min': 2.73, 'max': 9.2}, 'b2-fp': {'min': 3.05, 'max': 12.06}, 'b2-min': {'min': 2.84, 'max': 10.11}}
Variant, ROI extent from the footprints (no pixel size): combinations by outcome {'not': 147, 'partially': 69} of 216
1Px4: 1.37 to 4.28, median 1.77; within 1.8-2.2 in 51
5Px4: 2.08 to 4.31, median 2.69; within 1.8-2.2 in 18
10Px4: 2.68 to 9.27, median 4.16; within 1.8-2.2 in 0
# Per dish, primary reading (r2, c1, t1) under each background, minima taken from the treatment's mean profile.
rows = []
for bg in cancan.BACKGROUNDS + cancan.VARIANT_BACKGROUNDS:
data = table("r2", bg)
for t in TREATMENTS:
pos, P = data[t]
m = P.mean(0)
ci, mins = cancan.center_index(m, "c1"), cancan.side_minima(m)
for d, p in zip(dishes[t], P):
rows.append({"bg": bg, "treatment": t, "dish": d["dish"],
"center_over_trough_t1": round(float(cancan.center_value(p, ci)[0] / cancan.trough_value(p, mins, "t1")[0]), 2)})
print(pd.DataFrame(rows).pivot_table(index=["treatment", "dish"], columns="bg", values="center_over_trough_t1", sort=False).to_string())
bg b1 b2-dark b2-min b2-fp
treatment dish
1Px4 23 1.43 1.49 1.54 1.91
24 1.48 1.58 1.63 2.07
25 1.29 1.36 1.40 1.72
5Px4 9 2.38 2.49 2.65 3.07
20 2.50 2.58 2.64 2.90
22 1.86 1.94 2.04 2.26
10Px4 4 2.92 3.00 3.10 3.28
11 2.81 2.91 3.07 3.42
18 2.52 2.59 2.67 2.87
Result: partially reproduced. Under the primary reading the center over the least affected area is 1.40 for 1Px4, 2.16 for 5Px4 and 2.80 for 10Px4. Over the 216 combinations of the claims file's readings it is 1.32 to 4.04 for 1Px4 (within 1.8 to 2.2 in 52), 1.86 to 4.37 for 5Px4 (in 29) and 2.66 to 10.11 for 10Px4 (in none). No combination puts all three within tolerance; 79 put one or two within it, with all three above 1 (27 with raw counts, 25 with b2-dark and 27 with b2-min). The central peak is discernible for every treatment (the ratio is above 1 in all 216 combinations), but the ratio grows with the number of packets, so "about 2-fold for all the treatments" does not hold at 40 packets; per dish, 10Px4 is 2.52 to 2.92 with raw counts. The ROI extent from the footprints gives 69 partial and none reproduced (10Px4 2.68 to 9.27); the variant b2-fp, outside the readings, gives 14 partial of 72 (10Px4 3.05 to 12.06).
fig6-peak-narrower¶
The central peak appeared narrower (sharper) with increasing number of packets.
Criterion (claims file): (w1) full width of the central peak at half its height above the least affected area (the mean of the two side minima); (w2) the distance between the two minima on either side of the center. Each on the mean normalized profile, also with LOESS fits of span 0.25 and 0.5. Reproduced when, under a reading, width decreases from 4 to 20 to 40 packets; partially reproduced when 40 is narrower than 4 but 20 is out of order. The center reading sets where the half-height walk starts and the peak height (c1: the two central ROIs; c2: the highest ROI between the minima).
rows = []
for lay in cancan.LAYOUTS:
for bg in cancan.BACKGROUNDS + cancan.VARIANT_BACKGROUNDS:
data = table(lay, bg)
for norm in cancan.NORMALIZATIONS:
for per in (cancan.PERIPHERIES if norm == "n1" else ("e1",)):
for sm in cancan.SMOOTHING:
for cen in cancan.CENTERS:
row = {"layout": lay, "bg": bg, "norm": norm, "periphery": per, "smoothing": sm, "center": cen}
for t in TREATMENTS:
pos, P = data[t]
Q = cancan.mean_profile(P, per, norm)
if sm != "none":
Q = cancan.loess(pos, Q, float(sm.split("-")[1]))
ci, mins = cancan.center_index(Q, cen), cancan.side_minima(Q)
start = ci[0] if len(ci) == 1 else (ci[0] if Q[ci[0]] >= Q[ci[1]] else ci[1])
peak = cancan.center_value(Q, ci)[0]
base = cancan.trough_value(Q, mins, "t1")[0]
row[f"w1_{t}"] = cancan.half_max_width(pos, Q, start, peak, base)
row[f"w2_{t}"] = pos[mins[1]] - pos[mins[0]]
rows.append(row)
allfw = pd.DataFrame(rows)
for w in ["w1", "w2"]:
a, b, c = (allfw[f"{w}_{t}"] for t in TREATMENTS)
allfw[f"{w}_outcome"] = np.where((a > b) & (b > c), "reproduced", np.where(c < a, "partially", "not"))
fw = allfw[allfw.bg.isin(cancan.BACKGROUNDS)]
# w2 does not depend on the center reading: count it once per combination of the other readings.
fw2 = fw[fw.center == "c1"]
print("Widths in mm. Rows with n2 do not depend on the periphery reading and are shown once (e1);"
" w2 does not depend on the center reading and is counted once.")
print(fw.round(3).to_string(index=False))
for w, f in [("w1", fw), ("w2", fw2)]:
print(f"\n{w}: combinations by outcome", f[f"{w}_outcome"].value_counts().to_dict(), "of", len(f),
"; with n1 only:", f[f.norm == "n1"][f"{w}_outcome"].value_counts().to_dict(),
"; with n2 only:", f[f.norm == "n2"][f"{w}_outcome"].value_counts().to_dict())
for t in TREATMENTS:
s = f[f"{w}_{t}"]
print(f" {t}: {s.min():.3f} to {s.max():.3f} mm, median {s.median():.3f}; not measurable (NaN) in {int(s.isna().sum())}")
print(" by smoothing:", f.groupby("smoothing")[f"{w}_outcome"].value_counts().unstack(fill_value=0).to_dict("index"))
print(" by background:", f.groupby("bg")[f"{w}_outcome"].value_counts().unstack(fill_value=0).to_dict("index"))
print("\nw1 by center reading:", fw.groupby("center")["w1_outcome"].value_counts().unstack(fill_value=0).to_dict("index"))
v = allfw[allfw.bg.isin(cancan.VARIANT_BACKGROUNDS)]
print("Variant b2-fp (not a reading of the claims file): w1", v.w1_outcome.value_counts().to_dict(), "of", len(v),
"; w2", v[v.center == "c1"].w2_outcome.value_counts().to_dict(), "of", int((v.center == "c1").sum()))
Widths in mm. Rows with n2 do not depend on the periphery reading and are shown once (e1); w2 does not depend on the center reading and is counted once.
layout bg norm periphery smoothing center w1_1Px4 w2_1Px4 w1_5Px4 w2_5Px4 w1_10Px4 w2_10Px4 w1_outcome w2_outcome
r2 b1 n1 e1 none c1 1.051 1.363 0.545 1.722 0.488 1.148 reproduced partially
r2 b1 n1 e1 none c2 0.591 1.363 0.511 1.722 0.437 1.148 reproduced partially
r2 b1 n1 e1 loess-0.25 c1 0.800 1.722 0.654 1.793 0.560 1.363 reproduced partially
r2 b1 n1 e1 loess-0.25 c2 0.791 1.722 0.649 1.793 0.546 1.363 reproduced partially
r2 b1 n1 e1 loess-0.5 c1 0.992 2.367 0.863 1.650 0.817 1.435 reproduced reproduced
r2 b1 n1 e1 loess-0.5 c2 0.980 2.367 0.860 1.650 0.813 1.435 reproduced reproduced
r2 b1 n1 e2-neg none c1 1.053 1.363 0.563 1.722 0.486 1.148 reproduced partially
r2 b1 n1 e2-neg none c2 0.601 1.363 0.518 1.722 0.432 1.148 reproduced partially
r2 b1 n1 e2-neg loess-0.25 c1 0.802 1.722 0.648 1.793 0.557 1.363 reproduced partially
r2 b1 n1 e2-neg loess-0.25 c2 0.793 1.722 0.640 1.793 0.543 1.363 reproduced partially
r2 b1 n1 e2-neg loess-0.5 c1 0.980 2.367 0.861 1.578 0.822 1.435 reproduced reproduced
r2 b1 n1 e2-neg loess-0.5 c2 0.969 2.367 0.856 1.578 0.818 1.435 reproduced reproduced
r2 b1 n1 e2-pos none c1 1.051 1.507 0.535 1.722 0.492 1.076 reproduced partially
r2 b1 n1 e2-pos none c2 0.584 1.507 0.506 1.722 0.442 1.076 reproduced partially
r2 b1 n1 e2-pos loess-0.25 c1 0.802 2.439 0.657 1.793 0.563 1.363 reproduced reproduced
r2 b1 n1 e2-pos loess-0.25 c2 0.793 2.439 0.654 1.793 0.549 1.363 reproduced reproduced
r2 b1 n1 e2-pos loess-0.5 c1 1.005 2.367 0.865 1.578 0.811 1.435 reproduced reproduced
r2 b1 n1 e2-pos loess-0.5 c2 0.991 2.367 0.863 1.578 0.808 1.435 reproduced reproduced
r2 b1 n2 e1 none c1 0.970 1.363 0.552 1.722 0.499 1.076 reproduced partially
r2 b1 n2 e1 none c2 0.598 1.363 0.510 1.722 0.452 1.076 reproduced partially
r2 b1 n2 e1 loess-0.25 c1 0.805 1.793 0.619 1.722 0.570 1.363 reproduced reproduced
r2 b1 n2 e1 loess-0.25 c2 0.796 1.793 0.608 1.722 0.556 1.363 reproduced reproduced
r2 b1 n2 e1 loess-0.5 c1 0.978 2.367 0.858 1.578 0.806 1.435 reproduced reproduced
r2 b1 n2 e1 loess-0.5 c2 0.967 2.367 0.853 1.578 0.803 1.435 reproduced reproduced
r2 b2-dark n1 e1 none c1 1.052 1.363 0.545 1.722 0.488 1.148 reproduced partially
r2 b2-dark n1 e1 none c2 0.592 1.363 0.511 1.722 0.437 1.148 reproduced partially
r2 b2-dark n1 e1 loess-0.25 c1 0.800 1.722 0.656 1.793 0.560 1.363 reproduced partially
r2 b2-dark n1 e1 loess-0.25 c2 0.791 1.722 0.650 1.793 0.546 1.363 reproduced partially
r2 b2-dark n1 e1 loess-0.5 c1 0.991 2.367 0.863 1.650 0.817 1.435 reproduced reproduced
r2 b2-dark n1 e1 loess-0.5 c2 0.980 2.367 0.860 1.650 0.813 1.435 reproduced reproduced
r2 b2-dark n1 e2-neg none c1 1.054 1.363 0.563 1.722 0.486 1.148 reproduced partially
r2 b2-dark n1 e2-neg none c2 0.603 1.363 0.519 1.722 0.432 1.148 reproduced partially
r2 b2-dark n1 e2-neg loess-0.25 c1 0.802 1.722 0.650 1.793 0.557 1.363 reproduced partially
r2 b2-dark n1 e2-neg loess-0.25 c2 0.794 1.722 0.641 1.793 0.543 1.363 reproduced partially
r2 b2-dark n1 e2-neg loess-0.5 c1 0.978 2.367 0.861 1.578 0.822 1.435 reproduced reproduced
r2 b2-dark n1 e2-neg loess-0.5 c2 0.966 2.367 0.856 1.578 0.818 1.435 reproduced reproduced
r2 b2-dark n1 e2-pos none c1 1.052 1.507 0.536 1.722 0.492 1.076 reproduced partially
r2 b2-dark n1 e2-pos none c2 0.583 1.507 0.507 1.722 0.442 1.076 reproduced partially
r2 b2-dark n1 e2-pos loess-0.25 c1 0.802 2.439 0.659 1.793 0.563 1.363 reproduced reproduced
r2 b2-dark n1 e2-pos loess-0.25 c2 0.793 2.439 0.655 1.793 0.549 1.363 reproduced reproduced
r2 b2-dark n1 e2-pos loess-0.5 c1 1.006 2.367 0.865 1.578 0.811 1.435 reproduced reproduced
r2 b2-dark n1 e2-pos loess-0.5 c2 0.993 2.367 0.863 1.578 0.808 1.435 reproduced reproduced
r2 b2-dark n2 e1 none c1 0.970 1.363 0.552 1.722 0.499 1.076 reproduced partially
r2 b2-dark n2 e1 none c2 0.598 1.363 0.510 1.722 0.452 1.076 reproduced partially
r2 b2-dark n2 e1 loess-0.25 c1 0.805 1.793 0.619 1.722 0.570 1.363 reproduced reproduced
r2 b2-dark n2 e1 loess-0.25 c2 0.796 1.793 0.608 1.722 0.556 1.363 reproduced reproduced
r2 b2-dark n2 e1 loess-0.5 c1 0.978 2.367 0.858 1.578 0.806 1.435 reproduced reproduced
r2 b2-dark n2 e1 loess-0.5 c2 0.967 2.367 0.853 1.578 0.803 1.435 reproduced reproduced
r2 b2-min n1 e1 none c1 1.052 1.363 0.545 1.722 0.488 1.148 reproduced partially
r2 b2-min n1 e1 none c2 0.591 1.363 0.511 1.722 0.437 1.148 reproduced partially
r2 b2-min n1 e1 loess-0.25 c1 0.800 2.439 0.658 1.793 0.560 1.363 reproduced reproduced
r2 b2-min n1 e1 loess-0.25 c2 0.791 2.439 0.652 1.793 0.545 1.363 reproduced reproduced
r2 b2-min n1 e1 loess-0.5 c1 0.994 2.367 0.864 1.650 0.817 1.435 reproduced reproduced
r2 b2-min n1 e1 loess-0.5 c2 0.982 2.367 0.861 1.650 0.813 1.435 reproduced reproduced
r2 b2-min n1 e2-neg none c1 1.055 1.363 0.563 1.722 0.485 1.148 reproduced partially
r2 b2-min n1 e2-neg none c2 0.603 1.363 0.519 1.722 0.432 1.148 reproduced partially
r2 b2-min n1 e2-neg loess-0.25 c1 0.802 1.722 0.651 1.793 0.557 1.363 reproduced partially
r2 b2-min n1 e2-neg loess-0.25 c2 0.793 1.722 0.643 1.793 0.543 1.363 reproduced partially
r2 b2-min n1 e2-neg loess-0.5 c1 0.978 2.367 0.861 1.578 0.822 1.435 reproduced reproduced
r2 b2-min n1 e2-neg loess-0.5 c2 0.967 2.367 0.857 1.578 0.818 1.435 reproduced reproduced
r2 b2-min n1 e2-pos none c1 1.052 1.507 0.536 1.722 0.491 1.076 reproduced partially
r2 b2-min n1 e2-pos none c2 0.582 1.507 0.507 1.722 0.442 1.076 reproduced partially
r2 b2-min n1 e2-pos loess-0.25 c1 0.803 2.439 0.661 1.793 0.563 1.363 reproduced reproduced
r2 b2-min n1 e2-pos loess-0.25 c2 0.794 2.439 0.658 1.793 0.549 1.363 reproduced reproduced
r2 b2-min n1 e2-pos loess-0.5 c1 1.010 2.367 0.866 1.578 0.812 1.435 reproduced reproduced
r2 b2-min n1 e2-pos loess-0.5 c2 0.996 2.367 0.864 1.578 0.808 1.435 reproduced reproduced
r2 b2-min n2 e1 none c1 0.970 1.363 0.552 1.722 0.499 1.076 reproduced partially
r2 b2-min n2 e1 none c2 0.598 1.363 0.510 1.722 0.452 1.076 reproduced partially
r2 b2-min n2 e1 loess-0.25 c1 0.805 1.793 0.619 1.722 0.570 1.363 reproduced reproduced
r2 b2-min n2 e1 loess-0.25 c2 0.796 1.793 0.608 1.722 0.556 1.363 reproduced reproduced
r2 b2-min n2 e1 loess-0.5 c1 0.978 2.367 0.858 1.578 0.806 1.435 reproduced reproduced
r2 b2-min n2 e1 loess-0.5 c2 0.967 2.367 0.853 1.578 0.803 1.435 reproduced reproduced
r1-dA b1 n1 e1 none c1 0.776 2.116 0.405 2.260 0.345 1.829 reproduced partially
r1-dA b1 n1 e1 none c2 0.078 2.116 0.082 2.260 0.118 1.829 not partially
r1-dA b1 n1 e1 loess-0.25 c1 0.818 2.367 0.769 1.865 0.654 1.758 reproduced reproduced
r1-dA b1 n1 e1 loess-0.25 c2 0.818 2.367 0.739 1.865 0.619 1.758 reproduced reproduced
r1-dA b1 n1 e1 loess-0.5 c1 0.950 2.654 0.919 1.650 0.892 1.614 reproduced reproduced
r1-dA b1 n1 e1 loess-0.5 c2 0.942 2.654 0.918 1.650 0.888 1.614 reproduced reproduced
r1-dA b1 n1 e2-neg none c1 0.675 1.507 0.416 1.973 0.332 1.829 reproduced not
r1-dA b1 n1 e2-neg none c2 0.183 1.507 0.192 1.973 0.121 1.829 partially not
r1-dA b1 n1 e2-neg loess-0.25 c1 0.812 2.367 0.819 1.937 0.594 1.650 partially reproduced
r1-dA b1 n1 e2-neg loess-0.25 c2 0.811 2.367 0.791 1.937 0.576 1.650 reproduced reproduced
r1-dA b1 n1 e2-neg loess-0.5 c1 0.919 2.762 0.913 1.650 0.876 1.542 reproduced reproduced
r1-dA b1 n1 e2-neg loess-0.5 c2 0.914 2.762 0.912 1.650 0.873 1.542 reproduced reproduced
r1-dA b1 n1 e2-pos none c1 0.775 2.116 0.242 2.260 0.347 2.116 partially not
r1-dA b1 n1 e2-pos none c2 0.078 2.116 0.072 2.260 0.117 2.116 not not
r1-dA b1 n1 e2-pos loess-0.25 c1 0.822 2.367 0.716 1.829 0.669 1.793 reproduced reproduced
r1-dA b1 n1 e2-pos loess-0.25 c2 0.822 2.367 0.687 1.829 0.630 1.793 reproduced reproduced
r1-dA b1 n1 e2-pos loess-0.5 c1 0.989 2.439 0.927 1.650 0.897 1.686 reproduced partially
r1-dA b1 n1 e2-pos loess-0.5 c2 0.978 2.439 0.925 1.650 0.894 1.686 reproduced partially
r1-dA b1 n2 e1 none c1 0.675 1.507 0.336 2.260 0.341 1.829 partially not
r1-dA b1 n2 e1 none c2 0.187 1.507 0.096 2.260 0.150 1.829 partially not
r1-dA b1 n2 e1 loess-0.25 c1 0.806 2.367 0.712 1.793 0.597 1.471 reproduced reproduced
r1-dA b1 n2 e1 loess-0.25 c2 0.805 2.367 0.698 1.793 0.563 1.471 reproduced reproduced
r1-dA b1 n2 e1 loess-0.5 c1 0.893 2.762 0.921 1.686 0.857 1.507 partially reproduced
r1-dA b1 n2 e1 loess-0.5 c2 0.889 2.762 0.918 1.686 0.852 1.507 partially reproduced
r1-dA b2-dark n1 e1 none c1 0.776 2.116 0.405 2.260 0.345 1.829 reproduced partially
r1-dA b2-dark n1 e1 none c2 0.078 2.116 0.082 2.260 0.118 1.829 not partially
r1-dA b2-dark n1 e1 loess-0.25 c1 0.819 2.367 0.772 1.865 0.655 1.758 reproduced reproduced
r1-dA b2-dark n1 e1 loess-0.25 c2 0.818 2.367 0.741 1.865 0.620 1.758 reproduced reproduced
r1-dA b2-dark n1 e1 loess-0.5 c1 0.954 2.654 0.919 1.650 0.892 1.614 reproduced reproduced
r1-dA b2-dark n1 e1 loess-0.5 c2 0.945 2.654 0.917 1.650 0.888 1.614 reproduced reproduced
r1-dA b2-dark n1 e2-neg none c1 0.675 1.507 0.417 1.973 0.331 1.829 reproduced not
r1-dA b2-dark n1 e2-neg none c2 0.184 1.507 0.192 1.973 0.120 1.829 partially not
r1-dA b2-dark n1 e2-neg loess-0.25 c1 0.811 2.367 0.823 1.937 0.594 1.650 partially reproduced
r1-dA b2-dark n1 e2-neg loess-0.25 c2 0.811 2.367 0.795 1.937 0.576 1.650 reproduced reproduced
r1-dA b2-dark n1 e2-neg loess-0.5 c1 0.917 2.762 0.913 1.650 0.876 1.542 reproduced reproduced
r1-dA b2-dark n1 e2-neg loess-0.5 c2 0.912 2.762 0.912 1.650 0.873 1.542 partially reproduced
r1-dA b2-dark n1 e2-pos none c1 0.775 2.116 0.241 2.260 0.347 2.116 partially not
r1-dA b2-dark n1 e2-pos none c2 0.078 2.116 0.072 2.260 0.117 2.116 not not
r1-dA b2-dark n1 e2-pos loess-0.25 c1 0.823 2.367 0.716 1.829 0.670 1.829 reproduced partially
r1-dA b2-dark n1 e2-pos loess-0.25 c2 0.822 2.367 0.686 1.829 0.631 1.829 reproduced partially
r1-dA b2-dark n1 e2-pos loess-0.5 c1 1.004 2.439 0.928 1.650 0.898 1.686 reproduced partially
r1-dA b2-dark n1 e2-pos loess-0.5 c2 0.992 2.439 0.925 1.650 0.894 1.686 reproduced partially
r1-dA b2-dark n2 e1 none c1 0.675 1.507 0.336 2.260 0.341 1.829 partially not
r1-dA b2-dark n2 e1 none c2 0.187 1.507 0.096 2.260 0.150 1.829 partially not
r1-dA b2-dark n2 e1 loess-0.25 c1 0.806 2.367 0.712 1.793 0.597 1.471 reproduced reproduced
r1-dA b2-dark n2 e1 loess-0.25 c2 0.805 2.367 0.698 1.793 0.563 1.471 reproduced reproduced
r1-dA b2-dark n2 e1 loess-0.5 c1 0.893 2.762 0.921 1.686 0.857 1.507 partially reproduced
r1-dA b2-dark n2 e1 loess-0.5 c2 0.889 2.762 0.918 1.686 0.852 1.507 partially reproduced
r1-dA b2-min n1 e1 none c1 0.775 2.116 0.405 2.260 0.345 1.829 reproduced partially
r1-dA b2-min n1 e1 none c2 0.078 2.116 0.083 2.260 0.118 1.829 not partially
r1-dA b2-min n1 e1 loess-0.25 c1 0.820 2.367 0.775 1.865 0.656 1.758 reproduced reproduced
r1-dA b2-min n1 e1 loess-0.25 c2 0.820 2.367 0.744 1.865 0.621 1.758 reproduced reproduced
r1-dA b2-min n1 e1 loess-0.5 c1 0.965 2.654 0.919 1.650 0.893 1.614 reproduced reproduced
r1-dA b2-min n1 e1 loess-0.5 c2 0.956 2.654 0.917 1.650 0.889 1.614 reproduced reproduced
r1-dA b2-min n1 e2-neg none c1 0.675 1.507 0.418 1.973 0.331 1.829 reproduced not
r1-dA b2-min n1 e2-neg none c2 0.183 1.507 0.191 1.973 0.120 1.829 partially not
r1-dA b2-min n1 e2-neg loess-0.25 c1 0.813 2.367 0.829 1.937 0.594 1.650 partially reproduced
r1-dA b2-min n1 e2-neg loess-0.25 c2 0.812 2.367 0.800 1.937 0.576 1.650 reproduced reproduced
r1-dA b2-min n1 e2-neg loess-0.5 c1 0.923 2.726 0.912 1.650 0.876 1.542 reproduced reproduced
r1-dA b2-min n1 e2-neg loess-0.5 c2 0.918 2.726 0.912 1.650 0.874 1.542 reproduced reproduced
r1-dA b2-min n1 e2-pos none c1 0.775 2.116 0.240 2.260 0.347 2.116 partially not
r1-dA b2-min n1 e2-pos none c2 0.078 2.116 0.072 2.260 0.117 2.116 not not
r1-dA b2-min n1 e2-pos loess-0.25 c1 0.824 2.367 0.715 1.829 0.671 1.829 reproduced partially
r1-dA b2-min n1 e2-pos loess-0.25 c2 0.824 2.367 0.685 1.829 0.632 1.829 reproduced partially
r1-dA b2-min n1 e2-pos loess-0.5 c1 1.024 2.439 0.929 1.650 0.899 1.686 reproduced partially
r1-dA b2-min n1 e2-pos loess-0.5 c2 1.011 2.439 0.926 1.650 0.895 1.686 reproduced partially
r1-dA b2-min n2 e1 none c1 0.675 1.507 0.336 2.260 0.341 1.829 partially not
r1-dA b2-min n2 e1 none c2 0.187 1.507 0.096 2.260 0.150 1.829 partially not
r1-dA b2-min n2 e1 loess-0.25 c1 0.806 2.367 0.712 1.793 0.597 1.471 reproduced reproduced
r1-dA b2-min n2 e1 loess-0.25 c2 0.805 2.367 0.698 1.793 0.563 1.471 reproduced reproduced
r1-dA b2-min n2 e1 loess-0.5 c1 0.893 2.762 0.921 1.686 0.857 1.507 partially reproduced
r1-dA b2-min n2 e1 loess-0.5 c2 0.889 2.762 0.918 1.686 0.852 1.507 partially reproduced
r1-dB b1 n1 e1 none c1 0.888 1.829 0.748 1.829 0.458 1.327 reproduced reproduced
r1-dB b1 n1 e1 none c2 0.216 1.829 0.318 1.829 0.110 1.327 partially reproduced
r1-dB b1 n1 e1 loess-0.25 c1 0.940 1.829 0.670 1.650 0.569 1.291 reproduced reproduced
r1-dB b1 n1 e1 loess-0.25 c2 0.912 1.829 0.655 1.650 0.561 1.291 reproduced reproduced
r1-dB b1 n1 e1 loess-0.5 c1 1.125 2.439 0.813 1.507 0.801 1.435 reproduced reproduced
r1-dB b1 n1 e1 loess-0.5 c2 1.098 2.439 0.809 1.507 0.800 1.435 reproduced reproduced
r1-dB b1 n1 e2-neg none c1 0.890 1.865 0.676 1.829 0.460 1.327 reproduced reproduced
r1-dB b1 n1 e2-neg none c2 0.219 1.865 0.199 1.829 0.112 1.327 reproduced reproduced
r1-dB b1 n1 e2-neg loess-0.25 c1 0.953 1.865 0.627 1.614 0.570 1.291 reproduced reproduced
r1-dB b1 n1 e2-neg loess-0.25 c2 0.923 1.865 0.598 1.614 0.563 1.291 reproduced reproduced
r1-dB b1 n1 e2-neg loess-0.5 c1 1.110 2.439 0.821 1.471 0.806 1.435 reproduced reproduced
r1-dB b1 n1 e2-neg loess-0.5 c2 1.080 2.439 0.812 1.471 0.805 1.435 reproduced reproduced
r1-dB b1 n1 e2-pos none c1 0.886 1.829 0.858 1.937 0.455 1.327 reproduced partially
r1-dB b1 n1 e2-pos none c2 0.212 1.829 0.316 1.937 0.106 1.327 partially partially
r1-dB b1 n1 e2-pos loess-0.25 c1 0.940 2.583 0.708 1.650 0.568 1.291 reproduced reproduced
r1-dB b1 n1 e2-pos loess-0.25 c2 0.912 2.583 0.702 1.650 0.560 1.291 reproduced reproduced
r1-dB b1 n1 e2-pos loess-0.5 c1 1.141 2.439 0.809 1.507 0.794 1.399 reproduced reproduced
r1-dB b1 n1 e2-pos loess-0.5 c2 1.116 2.439 0.807 1.507 0.794 1.399 reproduced reproduced
r1-dB b1 n2 e1 none c1 0.885 1.829 0.596 1.829 0.454 1.327 reproduced reproduced
r1-dB b1 n2 e1 none c2 0.216 1.829 0.199 1.829 0.108 1.327 reproduced reproduced
r1-dB b1 n2 e1 loess-0.25 c1 0.928 1.829 0.617 1.578 0.569 1.291 reproduced reproduced
r1-dB b1 n2 e1 loess-0.25 c2 0.899 1.829 0.587 1.578 0.564 1.291 reproduced reproduced
r1-dB b1 n2 e1 loess-0.5 c1 1.117 2.439 0.823 1.471 0.785 1.399 reproduced reproduced
r1-dB b1 n2 e1 loess-0.5 c2 1.087 2.439 0.813 1.471 0.784 1.399 reproduced reproduced
r1-dB b2-dark n1 e1 none c1 0.888 1.865 0.753 1.829 0.458 1.327 reproduced reproduced
r1-dB b2-dark n1 e1 none c2 0.216 1.865 0.319 1.829 0.110 1.327 partially reproduced
r1-dB b2-dark n1 e1 loess-0.25 c1 0.942 1.829 0.671 1.650 0.569 1.291 reproduced reproduced
r1-dB b2-dark n1 e1 loess-0.25 c2 0.914 1.829 0.657 1.650 0.561 1.291 reproduced reproduced
r1-dB b2-dark n1 e1 loess-0.5 c1 1.124 2.439 0.813 1.507 0.801 1.435 reproduced reproduced
r1-dB b2-dark n1 e1 loess-0.5 c2 1.096 2.439 0.809 1.507 0.801 1.435 reproduced reproduced
r1-dB b2-dark n1 e2-neg none c1 0.891 1.865 0.676 1.829 0.292 1.327 reproduced reproduced
r1-dB b2-dark n1 e2-neg none c2 0.217 1.865 0.199 1.829 0.112 1.327 reproduced reproduced
r1-dB b2-dark n1 e2-neg loess-0.25 c1 0.958 1.865 0.627 1.614 0.570 1.291 reproduced reproduced
r1-dB b2-dark n1 e2-neg loess-0.25 c2 0.928 1.865 0.598 1.614 0.563 1.291 reproduced reproduced
r1-dB b2-dark n1 e2-neg loess-0.5 c1 1.106 2.439 0.821 1.471 0.806 1.435 reproduced reproduced
r1-dB b2-dark n1 e2-neg loess-0.5 c2 1.076 2.439 0.812 1.471 0.805 1.435 reproduced reproduced
r1-dB b2-dark n1 e2-pos none c1 0.886 1.829 0.859 1.937 0.455 1.327 reproduced partially
r1-dB b2-dark n1 e2-pos none c2 0.212 1.829 0.241 1.937 0.106 1.327 partially partially
r1-dB b2-dark n1 e2-pos loess-0.25 c1 0.941 2.583 0.710 1.650 0.568 1.291 reproduced reproduced
r1-dB b2-dark n1 e2-pos loess-0.25 c2 0.914 2.583 0.705 1.650 0.560 1.291 reproduced reproduced
r1-dB b2-dark n1 e2-pos loess-0.5 c1 1.143 2.439 0.809 1.507 0.794 1.399 reproduced reproduced
r1-dB b2-dark n1 e2-pos loess-0.5 c2 1.118 2.439 0.807 1.507 0.794 1.399 reproduced reproduced
r1-dB b2-dark n2 e1 none c1 0.885 1.829 0.596 1.829 0.454 1.327 reproduced reproduced
r1-dB b2-dark n2 e1 none c2 0.216 1.829 0.199 1.829 0.108 1.327 reproduced reproduced
r1-dB b2-dark n2 e1 loess-0.25 c1 0.928 1.829 0.617 1.578 0.569 1.291 reproduced reproduced
r1-dB b2-dark n2 e1 loess-0.25 c2 0.899 1.829 0.587 1.578 0.564 1.291 reproduced reproduced
r1-dB b2-dark n2 e1 loess-0.5 c1 1.117 2.439 0.823 1.471 0.785 1.399 reproduced reproduced
r1-dB b2-dark n2 e1 loess-0.5 c2 1.087 2.439 0.813 1.471 0.784 1.399 reproduced reproduced
r1-dB b2-min n1 e1 none c1 0.888 1.865 0.758 1.829 0.458 1.327 reproduced reproduced
r1-dB b2-min n1 e1 none c2 0.216 1.865 0.321 1.829 0.110 1.327 partially reproduced
r1-dB b2-min n1 e1 loess-0.25 c1 0.944 1.829 0.674 1.650 0.569 1.291 reproduced reproduced
r1-dB b2-min n1 e1 loess-0.25 c2 0.915 1.829 0.660 1.650 0.561 1.291 reproduced reproduced
r1-dB b2-min n1 e1 loess-0.5 c1 1.126 2.439 0.813 1.507 0.801 1.435 reproduced reproduced
r1-dB b2-min n1 e1 loess-0.5 c2 1.098 2.439 0.808 1.507 0.801 1.435 reproduced reproduced
r1-dB b2-min n1 e2-neg none c1 0.892 1.865 0.677 1.829 0.292 1.327 reproduced reproduced
r1-dB b2-min n1 e2-neg none c2 0.216 1.865 0.200 1.829 0.112 1.327 reproduced reproduced
r1-dB b2-min n1 e2-neg loess-0.25 c1 0.962 1.865 0.628 1.614 0.570 1.291 reproduced reproduced
r1-dB b2-min n1 e2-neg loess-0.25 c2 0.931 1.865 0.599 1.614 0.563 1.291 reproduced reproduced
r1-dB b2-min n1 e2-neg loess-0.5 c1 1.106 2.439 0.821 1.471 0.806 1.435 reproduced reproduced
r1-dB b2-min n1 e2-neg loess-0.5 c2 1.075 2.439 0.812 1.471 0.805 1.435 reproduced reproduced
r1-dB b2-min n1 e2-pos none c1 0.886 1.829 0.861 1.937 0.455 1.327 reproduced partially
r1-dB b2-min n1 e2-pos none c2 0.211 1.829 0.240 1.937 0.106 1.327 partially partially
r1-dB b2-min n1 e2-pos loess-0.25 c1 0.944 2.583 0.713 1.650 0.568 1.291 reproduced reproduced
r1-dB b2-min n1 e2-pos loess-0.25 c2 0.917 2.583 0.708 1.650 0.560 1.291 reproduced reproduced
r1-dB b2-min n1 e2-pos loess-0.5 c1 1.146 2.439 0.809 1.507 0.795 1.399 reproduced reproduced
r1-dB b2-min n1 e2-pos loess-0.5 c2 1.122 2.439 0.806 1.507 0.794 1.399 reproduced reproduced
r1-dB b2-min n2 e1 none c1 0.885 1.829 0.596 1.829 0.454 1.327 reproduced reproduced
r1-dB b2-min n2 e1 none c2 0.216 1.829 0.199 1.829 0.108 1.327 reproduced reproduced
r1-dB b2-min n2 e1 loess-0.25 c1 0.928 1.829 0.617 1.578 0.569 1.291 reproduced reproduced
r1-dB b2-min n2 e1 loess-0.25 c2 0.899 1.829 0.587 1.578 0.564 1.291 reproduced reproduced
r1-dB b2-min n2 e1 loess-0.5 c1 1.117 2.439 0.823 1.471 0.785 1.399 reproduced reproduced
r1-dB b2-min n2 e1 loess-0.5 c2 1.087 2.439 0.813 1.471 0.784 1.399 reproduced reproduced
w1: combinations by outcome {'reproduced': 182, 'partially': 28, 'not': 6} of 216 ; with n1 only: {'reproduced': 140, 'partially': 16, 'not': 6} ; with n2 only: {'reproduced': 42, 'partially': 12}
1Px4: 0.078 to 1.146 mm, median 0.890; not measurable (NaN) in 0
5Px4: 0.072 to 0.929 mm, median 0.681; not measurable (NaN) in 0
10Px4: 0.106 to 0.899 mm, median 0.566; not measurable (NaN) in 0
by smoothing: {'loess-0.25': {'not': 0, 'partially': 3, 'reproduced': 69}, 'loess-0.5': {'not': 0, 'partially': 7, 'reproduced': 65}, 'none': {'not': 6, 'partially': 18, 'reproduced': 48}}
by background: {'b1': {'not': 2, 'partially': 9, 'reproduced': 61}, 'b2-dark': {'not': 2, 'partially': 10, 'reproduced': 60}, 'b2-min': {'not': 2, 'partially': 9, 'reproduced': 61}}
w2: combinations by outcome {'reproduced': 71, 'partially': 28, 'not': 9} of 108 ; with n1 only: {'reproduced': 50, 'partially': 25, 'not': 6} ; with n2 only: {'reproduced': 21, 'partially': 3, 'not': 3}
1Px4: 1.363 to 2.762 mm, median 2.367; not measurable (NaN) in 0
5Px4: 1.471 to 2.260 mm, median 1.722; not measurable (NaN) in 0
10Px4: 1.076 to 2.116 mm, median 1.417; not measurable (NaN) in 0
by smoothing: {'loess-0.25': {'not': 0, 'partially': 7, 'reproduced': 29}, 'loess-0.5': {'not': 0, 'partially': 3, 'reproduced': 33}, 'none': {'not': 9, 'partially': 18, 'reproduced': 9}}
by background: {'b1': {'not': 3, 'partially': 9, 'reproduced': 24}, 'b2-dark': {'not': 3, 'partially': 10, 'reproduced': 23}, 'b2-min': {'not': 3, 'partially': 9, 'reproduced': 24}}
w1 by center reading: {'c1': {'not': 0, 'partially': 12, 'reproduced': 96}, 'c2': {'not': 6, 'partially': 16, 'reproduced': 86}}
Variant b2-fp (not a reading of the claims file): w1 {'reproduced': 60, 'partially': 8, 'not': 4} of 72 ; w2 {'reproduced': 28, 'partially': 6, 'not': 2} of 36
# The primary reading (r2, b1, n1, e1), per treatment, under both center readings, with the positions of the minima.
data = table("r2", "b1")
rows = []
for sm in cancan.SMOOTHING:
for cen in cancan.CENTERS:
for t in TREATMENTS:
pos, P = data[t]
Q = cancan.mean_profile(P, "e1", "n1")
if sm != "none":
Q = cancan.loess(pos, Q, float(sm.split("-")[1]))
ci, mins = cancan.center_index(Q, cen), cancan.side_minima(Q)
start = ci[0] if len(ci) == 1 else (ci[0] if Q[ci[0]] >= Q[ci[1]] else ci[1])
rows.append({"smoothing": sm, "center": cen, "treatment": t, "peak_pct": round(cancan.center_value(Q, ci)[0], 1),
"peak_mm": round(float(np.mean(pos[ci])), 2),
"minima_mm": [round(pos[i], 2) for i in mins], "base_pct": round(cancan.trough_value(Q, mins, "t1")[0], 1),
"w1_mm": round(cancan.half_max_width(pos, Q, start, cancan.center_value(Q, ci)[0], cancan.trough_value(Q, mins, "t1")[0]), 3),
"w2_mm": round(pos[mins[1]] - pos[mins[0]], 3)})
print(pd.DataFrame(rows).to_string(index=False))
# Per dish, w2 on each dish's own LOESS(0.5) normalized profile, to show the spread between dishes.
rows = []
for t in TREATMENTS:
pos, P = data[t]
for d, p in zip(dishes[t], P):
q = cancan.loess(pos, p / cancan.periphery(p, "e1")[0] * 100, 0.5)
mins = cancan.side_minima(q)
rows.append({"treatment": t, "dish": d["dish"], "w2_loess0.5_mm": round(pos[mins[1]] - pos[mins[0]], 3)})
print(pd.DataFrame(rows).to_string(index=False))
smoothing center treatment peak_pct peak_mm minima_mm base_pct w1_mm w2_mm
none c1 1Px4 124.0 0.00 [-0.54, 0.82] 88.6 1.051 1.363
none c1 5Px4 86.7 0.00 [-0.75, 0.97] 40.1 0.545 1.722
none c1 10Px4 58.7 0.00 [-0.54, 0.61] 20.9 0.488 1.148
none c2 1Px4 139.5 0.11 [-0.54, 0.82] 88.6 0.591 1.363
none c2 5Px4 91.7 -0.04 [-0.75, 0.97] 40.1 0.511 1.722
none c2 10Px4 70.8 0.04 [-0.54, 0.61] 20.9 0.437 1.148
loess-0.25 c1 1Px4 126.6 0.00 [-0.9, 0.82] 94.3 0.800 1.722
loess-0.25 c1 5Px4 81.3 0.00 [-0.9, 0.9] 44.9 0.654 1.793
loess-0.25 c1 10Px4 56.6 0.00 [-0.68, 0.68] 22.9 0.560 1.363
loess-0.25 c2 1Px4 127.2 0.04 [-0.9, 0.82] 94.3 0.791 1.722
loess-0.25 c2 5Px4 81.7 -0.04 [-0.9, 0.9] 44.9 0.649 1.793
loess-0.25 c2 10Px4 57.8 0.04 [-0.68, 0.68] 22.9 0.546 1.363
loess-0.5 c1 1Px4 118.8 0.00 [-0.82, 1.54] 97.3 0.992 2.367
loess-0.5 c1 5Px4 69.6 0.00 [-0.82, 0.82] 50.5 0.863 1.650
loess-0.5 c1 10Px4 43.4 0.00 [-0.68, 0.75] 28.0 0.817 1.435
loess-0.5 c2 1Px4 119.1 0.11 [-0.82, 1.54] 97.3 0.980 2.367
loess-0.5 c2 5Px4 69.7 -0.04 [-0.82, 0.82] 50.5 0.860 1.650
loess-0.5 c2 10Px4 43.5 0.04 [-0.68, 0.75] 28.0 0.813 1.435
treatment dish w2_loess0.5_mm
1Px4 23 2.367
1Px4 24 1.722
1Px4 25 1.865
5Px4 9 1.435
5Px4 20 1.578
5Px4 22 1.650
10Px4 4 1.578
10Px4 11 1.435
10Px4 18 1.363
# Variant: ROI extent from the footprints (no pixel size), r2, b1, n1, e1, c1; widths in mm at the assumed scale.
data = table("r2", "b1", "geometric")
for sm in cancan.SMOOTHING:
w = {}
for t in TREATMENTS:
pos, P = data[t]
Q = cancan.mean_profile(P, "e1", "n1")
if sm != "none":
Q = cancan.loess(pos, Q, float(sm.split("-")[1]))
ci, mins = cancan.center_index(Q, "c1"), cancan.side_minima(Q)
start = ci[0] if Q[ci[0]] >= Q[ci[1]] else ci[1]
w[t] = (cancan.half_max_width(pos, Q, start, cancan.center_value(Q, ci)[0], cancan.trough_value(Q, mins, "t1")[0]),
pos[mins[1]] - pos[mins[0]])
print(sm, {t: (round(a, 3), round(b, 3)) for t, (a, b) in w.items()}, "(w1, w2)")
none {'1Px4': (np.float64(0.951), np.float64(2.311)), '5Px4': (np.float64(0.569), np.float64(2.035)), '10Px4': (np.float64(0.475), np.float64(1.097))} (w1, w2)
loess-0.25 {'1Px4': (np.float64(0.795), np.float64(1.699)), '5Px4': (np.float64(0.637), np.float64(1.764)), '10Px4': (np.float64(0.544), np.float64(1.303))} (w1, w2)
loess-0.5 {'1Px4': (np.float64(0.93), np.float64(2.243)), '5Px4': (np.float64(0.85), np.float64(1.561)), '10Px4': (np.float64(0.797), np.float64(1.508))} (w1, w2)
Result: reproduced. On the primary reading (r2, b1, n1, e1) the width at half height above the least affected area (w1) is 1.051, 0.545 and 0.488 mm for 4, 20 and 40 packets; with LOESS of span 0.25 it is 0.800, 0.654 and 0.560 mm, and with span 0.5 0.992, 0.863 and 0.817 mm. Unsmoothed, w1 depends on the center reading: under c2 it is 0.591, 0.511 and 0.437 mm, still in order, while the smoothed widths change by less than 0.02 mm. Over the 216 combinations w1 decreases in 182, 40 is narrower than 4 but 20 out of order in 28, and the 6 others, all unsmoothed with c2, are out of order. The distance between the minima (w2) does not depend on the center reading and is counted once per combination: it decreases in 71 of 108, with 28 partial and 9 out of order, all 9 unsmoothed. On the primary reading it is 2.367, 1.650 and 1.435 mm with LOESS 0.5, and 1.363, 1.722 and 1.148 mm unsmoothed. Per dish, w2 on LOESS 0.5 is 1.722 to 2.367 mm for 1Px4, 1.435 to 1.650 for 5Px4 and 1.363 to 1.578 for 10Px4: 1Px4 and 10Px4 do not overlap, 5Px4 and 10Px4 do, and the criterion asks for no test. With the ROI extent from the footprints w1 keeps the order under all three smoothings. The widths in mm rest on the assumed pixel size; their order does not.
Summary¶
A failure to reproduce here may be a failure of this attempt, not of the paper: see the reasoning and the differences from the paper's method.
| Claim | Data | Outcome |
|---|---|---|
| fig6a-more-packets-more-uptake | dandiset | reproduced |
| fig6b-peak-relative-to-periphery | dandiset | partially reproduced |
| fig6-trough-half-of-center | dandiset | partially reproduced |
| fig6-peak-narrower | dandiset | reproduced |
| fig4-bipolar-cancellation, fig4-twenty-fold-cancellation | dandiset | blocked: data missing |
| fig5a-packet-without-rotation, fig5bc-rotation-focuses-center | dandiset | blocked: data missing |
| fig7ab-amplitude-scales-uptake, fig7-targeting-independent-of-amplitude, fig7-targeting-independent-of-array-size | dandiset | blocked: data missing |
| fig8-packet2-best-targeting, fig8b-normalized-center, fig8-cancellation-predicts-targeting | dandiset | blocked: data missing |
| fig9-gap-fades-periphery, fig9b-six-fold-targeting | dandiset | blocked: data missing |
| fig3-field-simulation | with inputs | blocked: data missing |
How the analysis differs from the paper's. The paper measured the images in MetaMorph with ROIs that it does not deposit; here the ROIs are placed by code on the detected electrode footprints. The layout, background, center, periphery and normalization order are not fixed by the paper, and every reading the claims file names is run. The files hold no dark frame, so the background reading b2 subtracts dark offsets estimated from the darkest blocks of each image or the darkest pixel near the array; the electrode footprints hold a faint monolayer and are not used as a background. The pixel size is assumed (0.65 um); a variant that places the ROIs from the footprints alone gives the same outcomes. The dandiset has 3 dishes per treatment, against 3 to 4 in the Fig. 6 legend.
What was found about the dandiset.
- It holds only the Fig. 6 experiment (9 dishes at 3.2 kV). The single-cell data of Fig. 4 and the monolayer data of Figs. 5, 7, 8 and 9 are not in it.
- The files give no pixel size, no electrode positions and no ROIs, and do not say which array was used; the array is the small one by its geometry at the camera scale. The dark electrode footprints are 1.66 to 2.09 mm across at that scale, wider than the 1.5 mm needles.
- The species is given as NCBITaxon 9913 (Bos taurus) for CHO cells (Chinese hamster), the age as "P1D", and the archive's summary counts 18 subjects for 9 files and 9 subject ids.
- Two pairs of dishes share a session start time to the second, one pair across treatments; the images differ, so no recording is deposited twice.
- The ImageSeries has unit "n.a." and a rate of 2 Hz for a single frame, and the "200ms" in the file names is not explained.
print(f"Notebook ran in {time.time() - started:.0f} s")
Notebook ran in 271 s