Skip to content

Commit 74419aa

Browse files
Merge pull request #528 from jungmannlab/development
v0.8.1
2 parents 7ada944 + 66cac34 commit 74419aa

30 files changed

+168
-108
lines changed

.bumpversion.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[bumpversion]
2-
current_version = 0.8.0
2+
current_version = 0.8.1
33
commit = True
44
tag = False
55
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(\-(?P<release>[a-z]+)(?P<build>\d+))?

changelog.rst

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
Changelog
22
=========
33

4-
Last change: 06-MAY-2025 MTS
4+
Last change: 15-JUL-2025 MTS
5+
6+
0.8.1
7+
-----
8+
- Added ``n_events`` to cluster centers, i.e., number of binding events per cluster
9+
- .yaml files contain Picasso version number for easier tracking
10+
- Improved fiducial picking
11+
- Bug fixes and other cosmetic changes
512

613
0.8.0
714
-----

distribution/picasso.iss

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
AppName=Picasso
33
AppPublisher=Jungmann Lab, Max Planck Institute of Biochemistry
44

5-
AppVersion=0.8.0
5+
AppVersion=0.8.1
66
DefaultDirName={commonpf}\Picasso
77
DefaultGroupName=Picasso
8-
OutputBaseFilename="Picasso-Windows-64bit-0.8.0"
8+
OutputBaseFilename="Picasso-Windows-64bit-0.8.1"
99
ArchitecturesAllowed=x64
1010
ArchitecturesInstallIn64BitMode=x64
1111

docs/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
# The short X.Y version
2727
version = ""
2828
# The full version, including alpha/beta/rc tags
29-
release = "0.8.0"
29+
release = "0.8.1"
3030

3131
# -- General configuration ---------------------------------------------------
3232

picasso/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import os.path as _ospath
99
import yaml as _yaml
1010

11-
__version__ = "0.8.0"
11+
__version__ = "0.8.1"
1212

1313
_this_file = _ospath.abspath(__file__)
1414
_this_dir = _ospath.dirname(_this_file)

picasso/__main__.py

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
:copyright: Copyright (c) 2016-2019 Jungmann Lab, MPI of Biochemistry
1010
"""
1111
import os.path
12+
from . import __version__
1213

1314

1415
def picasso_logo():
@@ -137,7 +138,7 @@ def _csv2hdf(path, pixelsize):
137138
locs.sort(kind="mergesort", order="frame")
138139

139140
img_info = {}
140-
img_info["Generated by"] = "Picasso csv2hdf"
141+
img_info["Generated by"] = f"Picasso v{__version__} csv2hdf"
141142
img_info["Frames"] = int(_np.max(frames)) + 1
142143
img_info["Height"] = int(_np.ceil(_np.max(y)))
143144
img_info["Width"] = int(_np.ceil(_np.max(x)))
@@ -203,7 +204,7 @@ def _link(files, d_max, tolerance):
203204
link_info = {
204205
"Maximum Distance": d_max,
205206
"Maximum Transient Dark Time": tolerance,
206-
"Generated by": "Picasso Link",
207+
"Generated by": f"Picasso v{__version__} Link",
207208
}
208209
info.append(link_info)
209210
io.save_locs(base + "_link.hdf5", linked_locs, info)
@@ -268,7 +269,7 @@ def _cluster_combine(files):
268269
continue
269270
combined_locs = postprocess.cluster_combine(locs)
270271
base, ext = os.path.splitext(path)
271-
combined_info = {"Generated by": "Picasso Combine"}
272+
combined_info = {"Generated by": f"Picasso v{__version__} Combine"}
272273
info.append(combined_info)
273274
io.save_locs(base + "_comb.hdf5", combined_locs, info)
274275

@@ -287,7 +288,7 @@ def _cluster_combine_dist(files):
287288
continue
288289
combinedist_locs = postprocess.cluster_combine_dist(locs)
289290
base, ext = os.path.splitext(path)
290-
cluster_combine_dist_info = {"Generated by": "Picasso Combineidst"}
291+
cluster_combine_dist_info = {"Generated by": f"Picasso v{__version__} Combineidst"}
291292
info.append(cluster_combine_dist_info)
292293
io.save_locs(base + "_cdist.hdf5", combinedist_locs, info)
293294

@@ -329,7 +330,7 @@ def _clusterfilter(files, clusterfile, parameter, minval, maxval):
329330

330331
base, ext = os.path.splitext(path)
331332
clusterfilter_info = {
332-
"Generated by": "Picasso Clusterfilter - in",
333+
"Generated by": f"Picasso v{__version__} Clusterfilter - in",
333334
"Paramter": parameter,
334335
"Minval": minval,
335336
"Maxval": maxval,
@@ -353,7 +354,7 @@ def _clusterfilter(files, clusterfile, parameter, minval, maxval):
353354

354355
base, ext = os.path.splitext(path)
355356
clusterfilter_info = {
356-
"Generated by": "Picasso Clusterfilter - out",
357+
"Generated by": f"Picasso v{__version__} Clusterfilter - out",
357358
"Paramter": parameter,
358359
"Minval": minval,
359360
"Maxval": maxval,
@@ -375,7 +376,7 @@ def _undrift(files, segmentation, display=True, fromfile=None):
375376
from numpy import genfromtxt, savetxt
376377

377378
paths = glob.glob(files)
378-
undrift_info = {"Generated by": "Picasso Undrift"}
379+
undrift_info = {"Generated by": f"Picasso v{__version__} Undrift"}
379380
if fromfile is not None:
380381
undrift_info["From File"] = fromfile
381382
drift = genfromtxt(fromfile)
@@ -457,7 +458,7 @@ def _density(files, radius):
457458
locs = postprocess.compute_local_density(locs, info, radius)
458459
base, ext = os.path.splitext(path)
459460
density_info = {
460-
"Generated by": "Picasso Density",
461+
"Generated by": f"Picasso v{__version__} Density",
461462
"Radius": radius,
462463
}
463464
info.append(density_info)
@@ -478,7 +479,7 @@ def _dbscan(files, radius, min_density, pixelsize=None):
478479
clusters = clusterer.find_cluster_centers(locs, pixelsize)
479480
base, _ = os.path.splitext(path)
480481
dbscan_info = {
481-
"Generated by": "Picasso DBSCAN",
482+
"Generated by": f"Picasso v{__version__} DBSCAN",
482483
"Radius": radius,
483484
"Minimum local density": min_density,
484485
}
@@ -506,7 +507,7 @@ def _hdbscan(files, min_cluster, min_samples, pixelsize=None):
506507
clusters = clusterer.find_cluster_centers(locs, pixelsize)
507508
base, ext = os.path.splitext(path)
508509
hdbscan_info = {
509-
"Generated by": "Picasso HDBSCAN",
510+
"Generated by": f"Picasso v{__version__} HDBSCAN",
510511
"Min. cluster": min_cluster,
511512
"Min. samples": min_samples,
512513
}
@@ -540,7 +541,7 @@ def _smlm_clusterer(
540541
clusters = clusterer.find_cluster_centers(locs, pixelsize)
541542
base, ext = os.path.splitext(path)
542543
smlm_cluster_info = {
543-
"Generated by": "Picasso SMLM clusterer",
544+
"Generated by": f"Picasso v{__version__} SMLM clusterer",
544545
"Radius_xy": radius,
545546
"Radius_z": radius_z,
546547
"Min locs": min_locs,
@@ -590,7 +591,7 @@ def _dark(files):
590591
locs, info = io.load_locs(path)
591592
locs = postprocess.compute_dark_times(locs)
592593
base, ext = os.path.splitext(path)
593-
d_info = {"Generated by": "Picasso Dark"}
594+
d_info = {"Generated by": f"Picasso v{__version__} Dark"}
594595
info.append(d_info)
595596
io.save_locs(base + "_dark.hdf5", locs, info)
596597

@@ -610,7 +611,7 @@ def _align(files, display):
610611
locs = [_[0] for _ in locs_infos]
611612
infos = [_[1] for _ in locs_infos]
612613
aligned_locs = align(locs, infos, display=display)
613-
align_info = {"Generated by": "Picasso Align", "Files": files}
614+
align_info = {"Generated by": f"Picasso v{__version__} Align", "Files": files}
614615
for file, locs_, info in zip(files, aligned_locs, infos):
615616
info.append(align_info)
616617
base, ext = splitext(file)
@@ -625,7 +626,7 @@ def _join(files, keep_index=True):
625626

626627
locs, info = load_locs(files[0])
627628
total_frames = info[0]["Frames"]
628-
join_info = {"Generated by": "Picasso Join", "Files": [files[0]]}
629+
join_info = {"Generated by": f"Picasso v{__version__} Join", "Files": [files[0]]}
629630
for path in files[1:]:
630631
locs_, info_ = load_locs(path)
631632
try:
@@ -977,7 +978,7 @@ def prompt_info():
977978
px = None
978979

979980
localize_info = {
980-
"Generated by": "Picasso Localize",
981+
"Generated by": f"Picasso v{__version__} Localize",
981982
"ROI": None, #TODO: change if ROI is given
982983
"Box Size": box,
983984
"Min. Net Gradient": min_net_gradient,
@@ -1477,12 +1478,20 @@ def _spinna_batch_analysis(parameters_filename, asynch=True, bootstrap=False, ve
14771478
nn_counts[f"{t1}-{t2}"] = nn_plotted
14781479
mixer.nn_counts = nn_counts
14791480
n_total = sum(n_simulated.values())
1480-
dist_sim = spinna.get_NN_dist_simulated(
1481-
mixer.convert_props_to_counts(opt_props[0], n_total),
1482-
sim_repeats,
1483-
mixer,
1484-
duplicate=True,
1485-
)
1481+
if isinstance(opt_props, tuple):
1482+
dist_sim = spinna.get_NN_dist_simulated(
1483+
mixer.convert_props_to_counts(opt_props[0], n_total),
1484+
sim_repeats,
1485+
mixer,
1486+
duplicate=True,
1487+
)
1488+
else:
1489+
dist_sim = spinna.get_NN_dist_simulated(
1490+
mixer.convert_props_to_counts(opt_props, n_total),
1491+
sim_repeats,
1492+
mixer,
1493+
duplicate=True,
1494+
)
14861495
for i, (t1, t2, _) in enumerate(mixer.get_neighbor_idx(duplicate=True)):
14871496
fig, ax = spinna.plot_NN(
14881497
dist=dist_sim[i], mode='plot', show_legend=False,

picasso/__version__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
VERSION_NO = "0.8.0"
1+
VERSION_NO = "0.8.1"

picasso/aim.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from scipy.interpolate import InterpolatedUnivariateSpline as \
1919
_InterpolatedUnivariateSpline
2020
from tqdm import tqdm as _tqdm
21+
from . import __version__
2122

2223

2324
def intersect1d(a, b):
@@ -739,7 +740,7 @@ def aim(
739740
locs["z"] = z_pdc
740741

741742
new_info = {
742-
"Generated by": "AIM undrift",
743+
"Generated by": f"Picasso v{__version__} AIM",
743744
"Intersect distance (nm)": intersect_d * pixelsize,
744745
"Segmentation": segmentation,
745746
"Search regions radius (nm)": roi_r * pixelsize,

picasso/clusterer.py

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
("ellipticity", "f4"),
3535
("net_gradient", "f4"),
3636
("n", "u4"),
37+
("n_events", "i4"),
3738
("area", "f4"),
3839
("convexhull", "f4"),
3940
("group", "i4"),
@@ -56,6 +57,7 @@
5657
("ellipticity", "f4"),
5758
("net_gradient", "f4"),
5859
("n", "u4"),
60+
("n_events", "u4"),
5961
("volume", "f4"),
6062
("convexhull", "f4"),
6163
("group", "i4"),
@@ -325,9 +327,10 @@ def cluster(
325327
326328
Returns
327329
-------
328-
np.array
329-
Cluster labels for each localization (-1 means no cluster
330-
assigned)
330+
locs : np.recarray
331+
Clusterered localizations, with column 'group' added, which
332+
specifies cluster label for each localization. Noise (label -1)
333+
is removed.
331334
"""
332335

333336
if hasattr(locs, "z"): # 3D
@@ -405,8 +408,9 @@ def dbscan(locs, radius, min_samples, pixelsize=None):
405408
Returns
406409
-------
407410
locs : np.recarray
408-
Clustered localizations; cluster labels are assigned to the
409-
"group" column
411+
Clusterered localizations, with column 'group' added, which
412+
specifies cluster label for each localization. Noise (label -1)
413+
is removed.
410414
"""
411415

412416
if hasattr(locs, "z"):
@@ -479,8 +483,9 @@ def hdbscan(
479483
Returns
480484
-------
481485
locs : np.recarray
482-
Clustered localizations; cluster labels are assigned to the
483-
"group" column
486+
Clusterered localizations, with column 'group' added, which
487+
specifies cluster label for each localization. Noise (label -1)
488+
is removed.
484489
"""
485490

486491
if hasattr(locs, "z"):
@@ -593,12 +598,13 @@ def find_cluster_centers(locs, pixelsize=None):
593598
ellipticity = _np.array([_[12] for _ in centers_])
594599
net_gradient = _np.array([_[13] for _ in centers_])
595600
n = _np.array([_[14] for _ in centers_])
601+
n_events = _np.array([_[15] for _ in centers_]) # number of localizations in cluster
596602

597603
if hasattr(locs, "z"):
598-
z = _np.array([_[15] for _ in centers_])
599-
std_z = _np.array([_[16] for _ in centers_])
600-
volume = _np.array([_[17] for _ in centers_])
601-
convexhull = _np.array([_[18] for _ in centers_])
604+
z = _np.array([_[16] for _ in centers_])
605+
std_z = _np.array([_[17] for _ in centers_])
606+
volume = _np.array([_[18] for _ in centers_])
607+
convexhull = _np.array([_[19] for _ in centers_])
602608
centers = _np.rec.array(
603609
(
604610
frame,
@@ -618,15 +624,16 @@ def find_cluster_centers(locs, pixelsize=None):
618624
ellipticity,
619625
net_gradient,
620626
n,
627+
n_events,
621628
volume,
622629
convexhull,
623630
res.index.values, # group id
624631
),
625632
dtype=CLUSTER_CENTERS_DTYPE_3D,
626633
)
627634
else:
628-
area = _np.array([_[15] for _ in centers_])
629-
convexhull = _np.array([_[16] for _ in centers_])
635+
area = _np.array([_[16] for _ in centers_])
636+
convexhull = _np.array([_[17] for _ in centers_])
630637
centers = _np.rec.array(
631638
(
632639
frame,
@@ -644,6 +651,7 @@ def find_cluster_centers(locs, pixelsize=None):
644651
ellipticity,
645652
net_gradient,
646653
n,
654+
n_events,
647655
area,
648656
convexhull,
649657
res.index.values, # group id
@@ -713,6 +721,10 @@ def cluster_center(grouplocs, pixelsize=None, separate_lp=False):
713721
net_gradient = grouplocs.net_gradient.mean()
714722
# n_locs in cluster
715723
n = len(grouplocs)
724+
# number of binding events
725+
split_idx = _np.where(_np.diff(grouplocs.frame) > 3)[0] + 1 # split locs by consecutive frames
726+
x_events = _np.split(grouplocs.x, split_idx)
727+
n_events = len(x_events) # number of binding events
716728
if hasattr(grouplocs, "z"):
717729
if pixelsize is None:
718730
raise ValueError(
@@ -753,6 +765,7 @@ def cluster_center(grouplocs, pixelsize=None, separate_lp=False):
753765
ellipticity,
754766
net_gradient,
755767
n,
768+
n_events,
756769
z,
757770
std_z,
758771
# lpz,
@@ -783,6 +796,7 @@ def cluster_center(grouplocs, pixelsize=None, separate_lp=False):
783796
ellipticity,
784797
net_gradient,
785798
n,
799+
n_events,
786800
area,
787801
convexhull,
788802
]

picasso/gui/average.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ def save(self, path):
294294
cy = self.info[0]["Height"] / 2
295295
self.locs.x += cx
296296
self.locs.y += cy
297-
info = self.info + [{"Generated by": "Picasso Average"}]
297+
info = self.info + [{"Generated by": f"Picasso v{__version__} Average"}]
298298
out_locs = self.locs
299299
io.save_locs(path, out_locs, info)
300300
self.window.status_bar.showMessage("File saved to {}.".format(path))

0 commit comments

Comments
 (0)