Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
95a30ad
add optional installation of picasso modules in innosetup
rafalkowalewski1 Feb 17, 2026
7b76f63
add picasso and nanotron installers
rafalkowalewski1 Feb 17, 2026
a2cb9cc
claude-generated installer for macos
rafalkowalewski1 Feb 17, 2026
cca8b69
add .sh script for making macos installer, not finished yet!
rafalkowalewski1 Feb 18, 2026
1d1c270
macos installer - get separate "apps" for each module, can be install…
rafalkowalewski1 Feb 19, 2026
03faab7
some attempts at fixing macos installer
rafalkowalewski1 Feb 19, 2026
6afda18
fix the new installer instructions for plugins and camera config file…
rafalkowalewski1 Feb 19, 2026
fdb1bae
FIX frame anlaysis in smlm clusterer
rafalkowalewski1 Feb 19, 2026
dd0e744
Fixed automatic Localize loading/unloading z-calibration paths when c…
rafalkowalewski1 Feb 19, 2026
b0961e3
Fixed labels of the vertical lines in the subcluster test plot
rafalkowalewski1 Feb 19, 2026
5341970
FIXED SUBCLUSTERING TEST PLOT
rafalkowalewski1 Feb 19, 2026
e5e35c5
fix windwos installer - icons, remove pyimariswriter for now
rafalkowalewski1 Feb 19, 2026
c2c41b9
Merge branch 'development' into feature-optional-installer-tools
rafalkowalewski1 Feb 19, 2026
02ac7aa
Fixed ``rel_sigma_z`` in G5M
rafalkowalewski1 Feb 19, 2026
26bd36d
fixed loading square picks
rafalkowalewski1 Feb 20, 2026
a8c2657
enhance apply dialog's tool tip
rafalkowalewski1 Feb 20, 2026
a2e13e8
FIX g5m's output lpz; add more saved columns
rafalkowalewski1 Feb 20, 2026
7401f25
apply expression dialog - variables wrap text
rafalkowalewski1 Feb 20, 2026
9dbae0e
Further enhancement of G5M documentation
rafalkowalewski1 Feb 20, 2026
4757fa3
add warnings about moving a bunch of postprocess functions to lib
rafalkowalewski1 Feb 20, 2026
de0e975
Fixed initial x, y and N in LQ Gaussian fitting
rafalkowalewski1 Feb 20, 2026
08baea7
Fixed picking circular regions around left and top edges of the FOV
rafalkowalewski1 Feb 20, 2026
a634be2
CLEAN some of the gui code
rafalkowalewski1 Feb 20, 2026
03a735d
implement filter by nlocs for multichannel data
rafalkowalewski1 Feb 20, 2026
f3fe801
add remove columns to render
rafalkowalewski1 Feb 20, 2026
5e99bac
add remove columns to Filter
rafalkowalewski1 Feb 20, 2026
ac11010
FIX macos installer
rafalkowalewski1 Feb 20, 2026
c532dd8
clean up macos installer
rafalkowalewski1 Feb 20, 2026
62818ae
added icons for macos installer
rafalkowalewski1 Feb 21, 2026
356cee9
Merge branch 'development' into feature-optional-installer-tools
rafalkowalewski1 Feb 22, 2026
f8a115a
small clean up, add readme.txt for macos installer
rafalkowalewski1 Feb 23, 2026
f4e69c8
add readme file for the windows installer
rafalkowalewski1 Feb 23, 2026
af29244
convert readme from txt to rst
rafalkowalewski1 Feb 23, 2026
8fd0893
clean up docs and add instructions for macos installer
rafalkowalewski1 Feb 23, 2026
1771689
FIX optional install modules on windows + clean up
rafalkowalewski1 Feb 23, 2026
df60311
clean up changelog
rafalkowalewski1 Feb 23, 2026
af1822d
Bump version: 0.9.6 → 0.9.7
rafalkowalewski1 Feb 23, 2026
045a8af
Merge pull request #624 from rafalkowalewski1/development
rafalkowalewski1 Feb 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .bumpversion.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 0.9.6
current_version = 0.9.7
commit = True
tag = False
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(\-(?P<release>[a-z]+)(?P<build>\d+))?
Expand All @@ -15,10 +15,16 @@ serialize =

[bumpversion:file:./picasso/version.py]

[bumpversion:file:./release/pyinstaller/picasso.spec]

[bumpversion:file:./release/pyinstaller/picassow.spec]

[bumpversion:file:./release/one_click_windows_gui/picasso_innoinstaller.iss]

[bumpversion:file:./release/one_click_windows_gui/create_installer_windows.bat]

[bumpversion:file:./release/one_click_macos_gui/create_macos_dmg.sh]

[bumpversion:file:./docs/conf.py]

[bumpversion:file:pyproject.toml]
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ picasso/config.yaml

# One-click-installer output
release/one_click_windows_gui/Output/
release/one_click_macos_gui/*.dmg

# PyInstaller
# Usually these files are written by a python script from a template
Expand Down
32 changes: 31 additions & 1 deletion changelog.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,37 @@
Changelog
=========

Last change: 16-FEB-2026 CEST
Last change: 23-FEB-2026 CEST

0.9.7
-----
Important updates:
^^^^^^^^^^^^^^^^^^
- Windows one-click-installer allows for selecting only a subset of Picasso modules to install
- Added ToRaw and Nanotron to one-click-installer
- *Experimental* One-click-installer for macOS (only for Apple Silicon), see `here <https://github.com/jungmannlab/picasso/tree/master/release/one_click_macos_gui>`__

Small improvements:
+++++++++++++++++++
- Adjusted the ``config.yaml`` and plugins instructions for the one-click-installer Picasso release (new Pyinstaller stores everything in the ``_internal`` folder)
- G5M output can save more columns (if present in the input localizations)
- Further enhancement of G5M documentation
- Render GUI: implemented filter by number of localizations for multichannel data
- Render GUI: allow removal of any column from localizations, not only ``group``
- Filter GUI: allow removal of any column from localizations
- ``REQUIRED_COLUMNS`` moved from ``picasso.localize`` to ``picasso.lib``

Bug fixes:
++++++++++
- Fixed basic frame analysis in SMLM clusterer
- Fixed labels of the vertical lines in the subcluster test plot
- Fixed automatic Localize loading/unloading z-calibration paths when changing cameras
- Fixed ``rel_sigma_z`` in G5M (previously incorrectly divided by pixel size)
- Fixed G5M molmap ``lpz`` output
- Fixed loading square picks in Render
- Fixed appearance of the Apply expression dialog in Render for files with many columns
- Fixed initial x, y and N in LQ Gaussian fitting (might results in faster convergence and slightly different (<< NeNA) results) (#616)
- Fixed picking circular regions around left and top edges of the FOV

0.9.6
-----
Expand Down
3 changes: 3 additions & 0 deletions distribution/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
# Packaging Picasso and Creating an Installer

**This folder will be removed in Picasso v0.11 as it is mostly a duplicate of picasso/release.**

This document describes the procedure to generate a Windows installer for Picasso end-users. The result is that Picasso (and Python) is installed in a single folder, the command line interface is exposed and start menu shortcuts are created. The first step is to package Picasso and its underlying Python distribution into a single folder.

## Requirements
Expand Down
4 changes: 2 additions & 2 deletions distribution/picasso.iss
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
AppName=Picasso
AppPublisher=Jungmann Lab, Max Planck Institute of Biochemistry

AppVersion=0.9.6
AppVersion=0.9.7
DefaultDirName={commonpf}\Picasso
DefaultGroupName=Picasso
OutputBaseFilename="Picasso-Windows-64bit-0.9.6"
OutputBaseFilename="Picasso-Windows-64bit-0.9.7"
ArchitecturesAllowed=x64
ArchitecturesInstallIn64BitMode=x64

Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
# The short X.Y version
version = ""
# The full version, including alpha/beta/rc tags
release = "0.9.6"
release = "0.9.7"

# -- General configuration ---------------------------------------------------

Expand Down
38 changes: 37 additions & 1 deletion docs/localize.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,43 @@ Identification and fitting of single-molecule spots
Camera Config
-------------

Picasso can remember default cameras and will use saved camera parameters. In order to use camera configs, create a file named ``config.yaml`` in the picasso folder. To start with a template, modify ``config_template.yaml`` that can be found in the folder by default. Picasso will compare the entries with Micro-Manager-Metadata and match the sensitivity values. If no matching entries can be found (e.g., if the file was not created with Micro-Manager) the config file will still be used to create a dropdown menu to select the different categories. The camera config can also be used to define a default camera that will always be used. Indentions are used for definitions.
Picasso can remember default cameras and will use saved camera parameters. In order to use camera configs, create a file named ``config.yaml`` in the ``picasso`` folder. See below on how to locate it.

To start with a template, modify ``config_template.yaml`` that can be found in the folder by default. Picasso will compare the entries with Micro-Manager-Metadata and match the sensitivity values. If no matching entries can be found (e.g., if the file was not created with Micro-Manager) the config file will still be used to create a dropdown menu to select the different categories. The camera config can also be used to define a default camera that will always be used. Indentions are used for definitions.

One click installer (Windows)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

If you downloaded an .exe Picasso file from the `release page <https://github.com/jungmannlab/picasso/releases>`_:

- Navigate to the installation folder, by default, it's ``C:/Picasso``. *Before version 0.8.3, the default location was* ``C:/Program Files/Picasso``.
- Go to the folder ``_internal/picasso``. *Before version 0.9.6, the folder was simply* ``picasso``.
- Add your config file there.

One click installer (macOS)
~~~~~~~~~~~~~~~~~~~~~~~~~~~

If you downloaded a .dmg Picasso file from the `release page <https://github.com/jungmannlab/picasso/releases>`_:

- Navigate to your Applications folder and right-click on the picasso app, then select "Show Package Contents".
- Go to the folder ``Contents/Frameworks/picasso``.
- Add your config file there.

PyPI
~~~~
If you installed Picasso using ``pip install picassosr``:

- Activate your conda environment where ``picassosr`` is installed by typing ``conda activate YOUR_ENVIRONMENT``.
- To find the location of the package, type ``pip show picassosr`` and look for the line starting with ``Location:``.
- Navigate to this location and go to ``picasso``.
- Add your config file there.

GitHub
~~~~~~
If you cloned the GitHub repository, you can add plugins by following these steps:
- Find the directory where you cloned the GitHub repository with Picasso.
- Go to ``picasso/picasso/``.
- Copy the config file to this folder.

Example: Default Camera
~~~~~~~~~~~~~~~~~~~~~~~
Expand Down
14 changes: 11 additions & 3 deletions docs/others.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,18 @@ If you installed Picasso using ``pip install picassosr``, you can add sound noti
- Copy the sound files to this folder.


One click installer
-------------------
One click installer (Windows)
-----------------------------
If you installed Picasso using the one click installer from `the Picasso release page <https://github.com/jungmannlab/picasso/releases/>`__ , you can add sound notifications by following these steps:

- Find the location where you installed Picasso. By default, it is ``C:/Picasso``. *Before version 0.8.3, the default location was* ``C:/Program Files/Picasso``.
- Go to the following subfolder: ``picasso/gui/notification_sounds``.
- Copy the sound files to this folder.
- Copy the sound files to this folder.


One click installer (macOS)
---------------------------
If you installed Picasso using the one click installer from `the Picasso release page <https://github.com/jungmannlab/picasso/releases/>`__ , you can add sound notifications by following these steps:

- Navigate to your Applications folder and right-click on the picasso app, then select "Show Package Contents".
- Add your sound files to ``Contents/Frameworks/picasso/gui/notification_sounds``.
16 changes: 12 additions & 4 deletions docs/plugins.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,24 @@ Starting in version 0.5.0, Picasso supports plugins. Below are the instructions

*Keep in mind that the* ``__init__.py`` *file in the* ``picasso/picasso/gui/plugins`` *folder must not be modified or deleted.*

One click installer
~~~~~~~~~~~~~~~~~~~
**NOTE**: After uninstalling Picasso, ``Picasso`` folder needs to be deleted manually, as the uninstaller currently does not remove the plugins automatically.
One click installer (Windows)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**NOTE**: After uninstalling Picasso, ``Picasso`` folder may need to be deleted manually, as the uninstaller currently does not remove the plugins automatically.

- Find the location where you installed Picasso. By default, it is ``C:/Picasso``. *Before version 0.8.3, the default location was* ``C:/Program Files/Picasso``.
- Then go to the folder ``picasso/gui/plugins``.
- Then go to the folder ``_internal/picasso/gui/plugins``. *Before version 0.9.6, the folder was* ``/picasso/gui/plugins``
- Copy the plugin(s) to this folder.

**NOTE**: Plugins added in this distribution will not be able to use packages that are not installed automatically (dependencies in the file ``pyproject.toml``).

One click installer (macOS)
~~~~~~~~~~~~~~~~~~~~~~~~~~~

- Navigate to your Applications folder and right-click on the picasso app, then select "Show Package Contents".
- Add your plugin(s) to ``Contents/Frameworks/picasso/gui/plugins``.

**NOTE**: Plugins added in this distribution will not be able to use packages that are not installed automatically (dependencies in the file ``pyproject.toml``).

PyPI
~~~~
If you installed Picasso using ``pip install picassosr``, you can add plugins by following these steps:
Expand Down
2 changes: 1 addition & 1 deletion docs/render.rst
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ If the outcome of G5M seems unsatisfactory, please check the following:
- Another reason why the loc. precision values can be off is due to the small box size in the localization step; especially in 3D astigmatic imaging, single-emitter images can be quite large, potentially exceeding the user-defined box size; in such cases, we recommend increasing the box size in the localization step and rerunning the analysis;
- Inspect if the localizations were preprocessed as described above;
- Rerun the analysis without postprocessing (filtering) and redo it manually, since the step may be too stringent, especially for short acquisition times;
- Adjust min./max. σ, especially too low max. σ may lead to high false positive error rates (i.e., overfitting);
- Adjust min./max. σ, especially too low max. σ may lead to high false positive error rates (i.e., overfitting); We suggest inspecting ``rel_sigma`` values of the assigned molecules, which are calculated as the fitted σ divided by the mean localization precision of the surrounding localizations. If the values are close to the user-selected min./max. σ, min./max. σ might need to be adjusted. Alternatively, this might be a sign of inaccurate/inprecise loc. precision values, see above;
- Adjust min. locs;
- Adjust DBSCAN (or other clustering algorithm) parameters. For example, if G5M takes too long to run, the DBSCAN clusters most likely contain too many molecules. In such a case, we recommend splitting such clusters further;

Expand Down
11 changes: 5 additions & 6 deletions picasso/clusterer.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,7 @@ def _frame_analysis(frame: pd.SeriesGroupBy, n_frames: int) -> int:
return passed


def frame_analysis(
labels: np.ndarray, frame: pd.Series | np.ndarray
) -> np.ndarray:
def frame_analysis(labels: np.ndarray, frame: np.ndarray) -> np.ndarray:
"""Perform basic frame analysis on clustered localizations. Reject
clusters whose mean frame is outside of the [20, 80] % (max frame)
range or any 1/20th of measurement's time contains more than 80 % of
Expand All @@ -87,7 +85,7 @@ def frame_analysis(
----------
labels : np.ndarray
Cluster labels (-1 means no cluster assigned).
frame : pd.Series or np.ndarray
frame : np.ndarray
Frame number for each localization.

Returns
Expand Down Expand Up @@ -195,7 +193,8 @@ def _cluster(
labels[np.isin(labels, to_discard)] = -1

if frame is not None:
labels = frame_analysis(labels, frame)
# must convert frames to an array, do not change!
labels = frame_analysis(labels, frame.to_numpy())

return labels

Expand Down Expand Up @@ -956,7 +955,7 @@ def test_subclustering(
sparse_dist: float = 80,
) -> tuple[np.ndarray, np.ndarray]:
"""Extract number of events from molecular maps based on their
numbers of binding events assinged.
numbers of binding events assigned.

The reasoning is that 'subclustered' molecules will tend to have
fewer binding events assigned to them since multiple molecules
Expand Down
45 changes: 21 additions & 24 deletions picasso/g5m.py
Original file line number Diff line number Diff line change
Expand Up @@ -1768,7 +1768,7 @@ def convert_G5M_results(
sigma_x = np.sqrt(covariances[:, 0]) * pixelsize
sigma_y = np.sqrt(covariances[:, 1]) * pixelsize
sigma_z = np.sqrt(covariances[:, 2]) * pixelsize
lpz = sem[:, 2]
lpz = sem[:, 2] * pixelsize
weighted_lpx = (
(resp * locs_group["lpx"].to_numpy().reshape(-1, 1)).sum(0) / rsum
).reshape(-1)
Expand All @@ -1780,7 +1780,7 @@ def convert_G5M_results(
).reshape(-1)
rel_sigma_x = sigma_x / weighted_lpx / pixelsize
rel_sigma_y = sigma_y / weighted_lpy / pixelsize
rel_sigma_z = sigma_z / weighted_lpz / pixelsize
rel_sigma_z = sigma_z / weighted_lpz
else:
sigma = np.sqrt(covariances) * pixelsize
# relative sigma
Expand Down Expand Up @@ -1810,20 +1810,6 @@ def convert_G5M_results(
log_likelihood = g5m.score_samples(X)
locs_group["log_likelihood"] = log_likelihood

# photons, PSF size and background (weighted average)
photons = (
(resp * locs_group["photons"].to_numpy().reshape(-1, 1)).sum(0) / rsum
).reshape(-1)
sx = (
(resp * locs_group["sx"].to_numpy().reshape(-1, 1)).sum(0) / rsum
).reshape(-1)
sy = (
(resp * locs_group["sy"].to_numpy().reshape(-1, 1)).sum(0) / rsum
).reshape(-1)
bg = (
(resp * locs_group["bg"].to_numpy().reshape(-1, 1)).sum(0) / rsum
).reshape(-1)

# extract the number of binding events, i.e., link localizations
# and assign them to molecules - sticky events will likely have only
# one or two such events associated
Expand Down Expand Up @@ -1861,10 +1847,6 @@ def convert_G5M_results(
"x": x.astype(np.float32),
"y": y.astype(np.float32),
"z": z.astype(np.float32),
"photons": photons.astype(np.float32),
"sx": sx.astype(np.float32),
"sy": sy.astype(np.float32),
"bg": bg.astype(np.float32),
"lpx": lpx.astype(np.float32),
"lpy": lpy.astype(np.float32),
"lpz": lpz.astype(np.float32),
Expand All @@ -1889,10 +1871,6 @@ def convert_G5M_results(
"std_frame": std_frame.astype(np.float32),
"x": x.astype(np.float32),
"y": y.astype(np.float32),
"photons": photons.astype(np.float32),
"sx": sx.astype(np.float32),
"sy": sy.astype(np.float32),
"bg": bg.astype(np.float32),
"lpx": lpx.astype(np.float32),
"lpy": lpy.astype(np.float32),
"fitted_sigma": sigma.astype(np.float32),
Expand All @@ -1905,6 +1883,25 @@ def convert_G5M_results(
"group_input": group_input.astype(np.int32),
}
)
# add mean values of extra columns from locs_group so that
# the info is not lost, e.g., mean photons
ignore_columns = [
"frame",
"x",
"y",
"z",
"lpx",
"lpy",
"lpz",
"group",
"group_input",
]
for col in locs_group.columns:
if col not in ignore_columns:
centers[f"{col}_mean"] = (
(resp * locs_group[col].to_numpy().reshape(-1, 1)).sum(0)
/ rsum
).reshape(-1)
return centers, locs_group


Expand Down
8 changes: 4 additions & 4 deletions picasso/gausslq.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,16 @@ def _sum_and_center_of_mass(
size: int,
) -> tuple[float, float, float]:
"""Calculate the sum and center of mass of a 2D spot."""
x = 0.0
y = 0.0
x = 0.0
_sum_ = 0.0
for i in range(size):
for j in range(size):
x += spot[i, j] * i
y += spot[i, j] * j
y += spot[i, j] * i
x += spot[i, j] * j
_sum_ += spot[i, j]
x /= _sum_
y /= _sum_
x /= _sum_
return _sum_, y, x


Expand Down
8 changes: 4 additions & 4 deletions picasso/gaussmle.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,16 @@ def _sum_and_center_of_mass(
size: int,
) -> tuple[float, float, float]:
"""Calculate the sum and center of mass of a 2D spot."""
x = 0.0
y = 0.0
x = 0.0
_sum_ = 0.0
for i in range(size):
for j in range(size):
x += spot[i, j] * i
y += spot[i, j] * j
y += spot[i, j] * i
x += spot[i, j] * j
_sum_ += spot[i, j]
x /= _sum_
y /= _sum_
x /= _sum_
return _sum_, y, x


Expand Down
Loading