Skip to content

Conversation

@Baharis
Copy link
Member

@Baharis Baharis commented Oct 31, 2025

I needed to use the "stagematrix" calibration, i.e. a matrix to (roughly) translate between camera and stage coordinates. I found the code mostly working, but I thought it could use more docs and less repetition. I would like to suggest the following changes. I did not introduce changes other than a few minor convenience features described below.

All the changes below concern file src/instamatic/calibrate/calibrate_stagematrix.py unless stated otherwise.

Minor changes

  • If pixelsize is undefined for a given mag, try to get_or_roughly_estimate_pixelsize it based on other pixel sizes in given mode, assuming the product of mag and pixelsize should be constant (useful for calibrate_stage_all);
  • src/instamatic/utils/iterating.py: Add pairwise that iterates over pairs of subsequent elements e.g. pairwise([1, 2, 3, 4]) yields (1, 2), (2, 3), and (3, 4) (built in Python 3.10 iterable, can be removed alongside Python 3.9 support).

Bug fixes

  • Fix instamatic.caliubrate_stagematrix option --all_mags.

Code maintenance

  • Import and add typing hints, align code with type hints, declare and use Literal mode hints for TEM modes;
  • Rename some internal arguments or variables (like calibrate_stage_from_*'s "args") to be more meaningful;
  • Limit repetition: move repeated plotting into plot_results
  • Favor write_tiff functionality built in get_image over a separate import/op;
  • Removed unused import statements.

@Baharis Baharis requested a review from stefsmeets October 31, 2025 15:14
@Baharis Baharis self-assigned this Oct 31, 2025
Copy link
Member

@stefsmeets stefsmeets left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work, looks good! Left a minor comment.

How do you test the typing? We don't have mypy or similar set up.


np.set_printoptions(suppress=True)

Mode = Literal['mag1', 'mag2', 'lowmag', 'samag']
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enums are also nice for this. I find literal types to be a pain to work with, because you must always pass a literal for this to pass. For example, this will fail mypy:

mode = 'mag1'
get_or_roughly_estimate_pixelsize(mode=mode, ...)
# error: Argument 1 to "get_or_roughly_estimate_pixelsize" has incompatible type "str"; expected "Literal['mag1', 'mag2', 'lowmag', 'samag']"  [arg-type]

So you must always define mode = Literal['mag1'].

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, that sounds absurd. I understand the logic but it does limit the usefulness of Literal indeed. But also I learned that apparently you can use Final (introduced in python 3.8, ~equivalent to Java final) to suppress it:

from typing import Final

mode: Final[str] = 'mag1'
get_or_roughly_estimate_pixelsize(mode=mode, ...)  # passes, apparently

I find it funny how the typing module, especially with mypy, morphs Python into a static-typed language, like a software carcinization 🤣.

Regarding type checking, I am personally relying on the checker built-in PyCharm, it updates live and is not perfect but quite good. But I use typing mostly as a matter of preference rather than a layer of security, IMO it makes understanding code so much easier. My recent go-to is short docstrings and well-named and type-hinted attributes.

Copy link
Member Author

@Baharis Baharis Nov 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added some changes suggested by mypy. I actually did not get any problems with Literal / str, though wow, "fixing" entirety of instamatic to be accepted by mypy, especially --strict would be "fun".

Merging by ~Wednesday unless anyone voices issues.

Copy link
Member

@stefsmeets stefsmeets Nov 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, basedpyright or the now deprecated basedmypy are nice for this, because they record a 'baseline' of issues to work with, so you only get warnings on new code.

@Baharis Baharis merged commit 6ad085c into instamatic-dev:main Nov 5, 2025
6 checks passed
@Baharis Baharis deleted the calibrate_stagematrix_refresh branch November 5, 2025 10:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants