I’m computing peristimulus time histograms (PSTHs) in Python. Each trial aligns spikes to a reach-start timestamp and bins them into fixed-width bins. I see vertical “gaps” (low counts) at exact bin boundaries (e.g., every 20 ms). I thought it was floating-point, so I converted everything to integers and even tried microseconds + half-open bins, but the stripes persist.
Minimal example (synthetic data that reproduces the effect on my machine):
import numpy as np
# ---- synthetic spikes: uniform + weak locking every 20 ms ----
rng = np.random.default_rng(0)
n_trials = 200
pre_s, post_s, bw_s = 1.0, 4.0, 0.02 # 20 ms
TICK = 1_000_000 # microseconds
pre, post, bw = int(pre_s*TICK), int(post_s*TICK), int(bw_s*TICK)
edges_rel = np.arange(-pre, post+1, bw, dtype=np.int64)
# trial starts (ms), here zeros for simplicity
reach_ticks = np.zeros(n_trials, dtype=np.int64)
# build spikes per trial with slight bin-boundary bias
spike_ticks = []
for _ in range(n_trials):
# uniform spikes
base = rng.integers(-pre, post, size=300)
# add a few spikes perturbed around multiples of 20 ms
lock = (np.arange(-pre, post, 20_000) + rng.integers(-200, 200, size=(pre+post)//20_000))
spikes = np.concatenate([base, lock])
spikes.sort()
spike_ticks.append(spikes)
# histogram per trial (half-open [left,right) bins)
H = []
for rs, rels in zip(reach_ticks, spike_ticks):
edges_abs = rs + edges_rel
h, _ = np.histogram(rels, bins=edges_abs)
H.append(h)
H = np.asarray(H, float) / bw_s # Hz
# show that the middle bin near -0.5 s dips relative to neighbors
centers = (edges_rel[:-1] + edges_rel[1:])/(2*TICK)
mid = np.argmin(np.abs(centers + 0.5))
print("Means around -0.5s:", H.mean(0)[mid-1:mid+2])