fastmolwidget 0.5.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,24 @@
1
+ BSD 2-Clause License
2
+
3
+ Copyright (c) 2026, Daniel Kratzert
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,285 @@
1
+ Metadata-Version: 2.3
2
+ Name: fastmolwidget
3
+ Version: 0.5.1
4
+ Summary: A PyQt widget to display crystal structures
5
+ Keywords: chemistry,crystallography,qt,widget,molecule
6
+ Author: Daniel Kratzert
7
+ Author-email: Daniel Kratzert <dkratzert@gmx.de>
8
+ License: BSD 2-Clause License
9
+
10
+ Copyright (c) 2026, Daniel Kratzert
11
+
12
+ Redistribution and use in source and binary forms, with or without
13
+ modification, are permitted provided that the following conditions are met:
14
+
15
+ 1. Redistributions of source code must retain the above copyright notice, this
16
+ list of conditions and the following disclaimer.
17
+
18
+ 2. Redistributions in binary form must reproduce the above copyright notice,
19
+ this list of conditions and the following disclaimer in the documentation
20
+ and/or other materials provided with the distribution.
21
+
22
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
26
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
+ Classifier: Development Status :: 4 - Beta
33
+ Classifier: License :: OSI Approved :: MIT License
34
+ Classifier: Intended Audience :: Science/Research
35
+ Classifier: Programming Language :: Python :: 3
36
+ Classifier: Programming Language :: Python :: 3.12
37
+ Classifier: Programming Language :: Python :: 3.13
38
+ Classifier: Topic :: Scientific/Engineering :: Chemistry
39
+ Classifier: Topic :: Software Development :: User Interfaces
40
+ Requires-Dist: gemmi>=0.7.5
41
+ Requires-Dist: numpy>=2.2.0
42
+ Requires-Dist: qtpy>=2.4.3
43
+ Requires-Dist: shelxfile>=22
44
+ Requires-Dist: pyqt6>=6.9.0 ; extra == 'pyqt6'
45
+ Requires-Dist: pyside6-essentials>=6.11.0 ; extra == 'pyside6'
46
+ Requires-Python: >=3.12
47
+ Project-URL: Homepage, https://github.com/dkratzert/Fastmolwidget
48
+ Project-URL: Repository, https://github.com/dkratzert/Fastmolwidget
49
+ Project-URL: Issues, https://github.com/dkratzert/Fastmolwidget/issues
50
+ Provides-Extra: pyqt6
51
+ Provides-Extra: pyside6
52
+ Description-Content-Type: text/markdown
53
+
54
+ # Fastmolwidget
55
+
56
+ **A PyQt/PySide6 widget to display crystal structures**
57
+
58
+ Fastmolwidget is a lightweight, embeddable Qt widget that renders molecular and crystal structures in 2D projection with interactive mouse controls.
59
+ It supports anisotropic displacement parameter (ADP) ellipsoids, ball-and-stick diagrams, and plain sphere representations —
60
+ all drawn with a pure-Python QPainter backend (no OpenGL required).
61
+
62
+ ## Screenshot
63
+
64
+ ![Fastmolwidget showing an ORTEP-style crystal structure](https://github.com/dkratzert/Fastmolwidget/raw/main/docs/images/screenshot.png)
65
+
66
+ *View of a crystal structure from a CIF file with ADP ellipsoids. The control bar allows toggling display options interactively.*
67
+
68
+ ## Features
69
+
70
+ - **ADP ellipsoids** at the 50 % probability level, rendered from anisotropic displacement parameters
71
+ - **Ball-and-stick** and **isotropic sphere** representations as fallbacks or when speed is more important than detail
72
+ - **Interactive mouse controls**: rotate (left-drag), zoom (right-drag), pan (middle-drag), scroll wheel to resize labels
73
+ - **Atom and bond selection**: single click or Ctrl+click for multi-selection; emits `atomClicked` / `bondClicked` Qt signals
74
+ - **Hydrogen visibility toggle**
75
+ - **Atom label display toggle** with adjustable font size
76
+ - **Bond width** adjustment via spin box
77
+ - **Multiple file formats**: CIF, SHELX `.res`/`.ins`, and plain XYZ. More to come...
78
+ - **Embeddable** — `MoleculeWidget` is a plain `QWidget` subclass; drop it into any layout
79
+ - **Ready-to-use** `MoleculeViewerWidget` bundles the renderer with a full control bar
80
+
81
+ ## Supported File Formats
82
+
83
+ | Extension | Format | Notes |
84
+ |-----------|--------|-------|
85
+ | `.cif` | Crystallographic Information File | Reads atoms, unit cell, and ADPs |
86
+ | `.res` / `.ins` | SHELXL instruction file | Reads atoms and unit cell via [shelxfile](https://github.com/dkratzert/ShelXFile) |
87
+ | `.xyz` | Standard XYZ coordinate file | Cartesian coordinates, no cell or ADPs |
88
+
89
+ ## Installation
90
+
91
+ ```bash
92
+ pip install fastmolwidget
93
+ ```
94
+
95
+ By default, `fastmolwidget` installs **without a concrete Qt binding**.
96
+ Install one binding explicitly via extras:
97
+
98
+ ```bash
99
+ pip install "fastmolwidget[pyside6]"
100
+ pip install "fastmolwidget[pyqt6]"
101
+ ```
102
+
103
+ **Requirements**: Python >= 3.12, NumPy, gemmi, shelxfile, qtpy, and either PySide6 or PyQt6.
104
+
105
+ ## Quick Start
106
+
107
+ ### Standalone viewer
108
+
109
+ ```python
110
+ from qtpy.QtWidgets import QApplication
111
+ from fastmolwidget import MoleculeViewerWidget
112
+
113
+ app = QApplication([])
114
+ viewer = MoleculeViewerWidget()
115
+ viewer.load_file("structure.cif")
116
+ viewer.show()
117
+ app.exec()
118
+ ```
119
+
120
+ ### Embedding in your own layout
121
+
122
+ ```python
123
+ from fastmolwidget import MoleculeWidget, MoleculeLoader
124
+
125
+ mol = MoleculeWidget(parent=self)
126
+ loader = MoleculeLoader(mol)
127
+ # The loader recognizes the file format from the extension and populates `mol` accordingly
128
+ loader.load_file("structure.cif")
129
+
130
+ # drop `mol` into any QLayout
131
+ layout.addWidget(mol)
132
+ ```
133
+
134
+ ### Loading a different file at runtime
135
+
136
+ ```python
137
+ viewer.load_file("new_structure.res")
138
+ ```
139
+
140
+ ### Reacting to atom / bond clicks
141
+
142
+ ```python
143
+ mol.atomClicked.connect(lambda label: print(f"Clicked atom: {label}"))
144
+ mol.bondClicked.connect(lambda a, b: print(f"Clicked bond: {a}–{b}"))
145
+ ```
146
+
147
+ ## Mouse Controls
148
+
149
+ | Action | Effect |
150
+ |--------|--------|
151
+ | Left-drag | Rotate the molecule |
152
+ | Right-drag | Zoom in / out |
153
+ | Middle-drag | Pan the view |
154
+ | Scroll wheel | Increase / decrease label font size |
155
+ | Left-click | Select a single atom or bond |
156
+ | Ctrl + Left-click | Toggle multi-selection |
157
+
158
+ ## Control Bar Options (`MoleculeViewerWidget`)
159
+
160
+ | Control | Default | Description |
161
+ |---------|---------|-------------|
162
+ | Show ADP | ✓ | Toggle ORTEP ellipsoid / isotropic sphere rendering |
163
+ | Show Labels | ✗ | Toggle non-hydrogen atom labels |
164
+ | Round Bonds | ✓ | Switch between 3D-shaded and flat bond drawing |
165
+ | Show Hydrogens | ✓ | Show or hide hydrogen atoms and their bonds |
166
+ | Bond Width | 3 | Stroke width for bonds (1–15 px) |
167
+
168
+ ## API Overview
169
+
170
+ ### `MoleculeViewerWidget(parent=None)`
171
+
172
+ A self-contained widget combining `MoleculeWidget` with the control bar described above.
173
+
174
+ - `load_file(path)` — load a structure file (format auto-detected from extension)
175
+ - `render_widget` — read-only property exposing the underlying `MoleculeWidget`
176
+
177
+ ### `MoleculeWidget(parent=None)`
178
+
179
+ The low-level renderer widget. It is a plain `QWidget` subclass that you can drop into any layout.
180
+ Provide atom data directly via `open_molecule()` instead of loading a file through `MoleculeLoader`.
181
+
182
+ #### Qt Signals
183
+
184
+ | Signal | Signature | Emitted when |
185
+ |--------|-----------|--------------|
186
+ | `atomClicked` | `(label: str)` | The user clicks on an atom; `label` is the atom name (e.g. `"C1"`) |
187
+ | `bondClicked` | `(label1: str, label2: str)` | The user clicks on a bond; both atom labels are passed |
188
+
189
+ #### Data Methods
190
+
191
+ - **`open_molecule(atoms, cell=None, adps=None, keep_view=False)`**
192
+ Load a new set of atoms and reset (or optionally preserve) the view.
193
+ - `atoms` — list of `Atomtuple(label, type, x, y, z, part)` in Cartesian coordinates (Å)
194
+ - `cell` — optional `(a, b, c, α, β, γ)` tuple of unit-cell parameters (Å / °); required for ADP rendering
195
+ - `adps` — optional `dict` mapping atom labels to `(U11, U22, U33, U23, U13, U12)` ADP tensors
196
+ - `keep_view` — when `True`, the current zoom, pan, and rotation are preserved (useful for live updates)
197
+
198
+ - **`grow_molecule(atoms, cell=None, adps=None)`**
199
+ Replace the atom set while always preserving the current view.
200
+ Equivalent to calling `open_molecule(..., keep_view=True)`.
201
+
202
+ - **`clear()`**
203
+ Remove all atoms and bonds from the display.
204
+
205
+ #### Display Methods
206
+
207
+ - **`show_adps(value: bool)`**
208
+ Toggle ORTEP-style ADP ellipsoid rendering. When `False`, atoms are drawn as isotropic spheres.
209
+
210
+ - **`show_labels(value: bool)`**
211
+ Show or hide non-hydrogen atom labels.
212
+
213
+ - **`show_hydrogens(value: bool)`**
214
+ Show or hide hydrogen / deuterium atoms and their bonds.
215
+
216
+ - **`show_round_bonds(value: bool)`**
217
+ Switch between 3D-shaded cylinder-style bonds (`True`, default) and flat single-colour bonds (`False`).
218
+
219
+ - **`set_bond_width(width: int)`**
220
+ Set the stroke width for bonds in pixels (valid range: 1–15).
221
+
222
+ - **`setLabelFont(font_size: int)`**
223
+ Set the pixel size used for atom labels.
224
+
225
+ - **`set_background_color(color: QColor)`**
226
+ Change the widget background colour.
227
+
228
+ - **`reset_view()`**
229
+ Reset zoom, pan, and rotation to their defaults.
230
+
231
+ #### Example — feeding atom data directly
232
+
233
+ ```python
234
+ from fastmolwidget import MoleculeWidget
235
+ from fastmolwidget.sdm import Atomtuple
236
+
237
+ mol = MoleculeWidget(parent=self)
238
+
239
+ atoms = [
240
+ Atomtuple(label="C1", type="C", x=0.0, y=0.0, z=0.0, part=0),
241
+ Atomtuple(label="O1", type="O", x=1.22, y=0.0, z=0.0, part=0),
242
+ Atomtuple(label="H1", type="H", x=-0.5, y=0.94, z=0.0, part=0),
243
+ ]
244
+
245
+ # ADP tensors: {atom_label: (U11, U22, U33, U23, U13, U12)}
246
+ adps = {
247
+ "C1": (0.02, 0.02, 0.02, 0.0, 0.0, 0.0),
248
+ "O1": (0.03, 0.03, 0.03, 0.0, 0.0, 0.0),
249
+ }
250
+
251
+ cell = (5.0, 5.0, 5.0, 90.0, 90.0, 90.0) # optional
252
+
253
+ mol.open_molecule(atoms=atoms, cell=cell, adps=adps)
254
+ mol.atomClicked.connect(lambda label: print(f"Selected: {label}"))
255
+
256
+ layout.addWidget(mol)
257
+ ```
258
+
259
+ ### `MoleculeLoader(widget)`
260
+
261
+ Format-aware loader that populates a `MoleculeWidget`.
262
+
263
+ - `load_file(path, keep_view=False)` — parse file and call `open_molecule` / `grow_molecule`
264
+
265
+ ## License
266
+
267
+ BSD 2-Clause License — see [LICENSE](LICENSE) for details.
268
+
269
+ © 2026 Daniel Kratzert
270
+
271
+ ## Maintainer Release Workflow
272
+
273
+ The release workflow is tag-driven and currently publishes to **TestPyPI** only.
274
+
275
+ 1. Ensure `project.version` in `pyproject.toml` is the version to publish.
276
+ 2. Create and push a matching tag in the format `version-X.Y.Z`.
277
+ 3. GitHub Actions builds sdist/wheel and uploads to TestPyPI.
278
+
279
+ Example:
280
+
281
+ ```bash
282
+ git tag version-0.1.0
283
+ git push origin version-0.1.0
284
+ ```
285
+
@@ -0,0 +1,232 @@
1
+ # Fastmolwidget
2
+
3
+ **A PyQt/PySide6 widget to display crystal structures**
4
+
5
+ Fastmolwidget is a lightweight, embeddable Qt widget that renders molecular and crystal structures in 2D projection with interactive mouse controls.
6
+ It supports anisotropic displacement parameter (ADP) ellipsoids, ball-and-stick diagrams, and plain sphere representations —
7
+ all drawn with a pure-Python QPainter backend (no OpenGL required).
8
+
9
+ ## Screenshot
10
+
11
+ ![Fastmolwidget showing an ORTEP-style crystal structure](https://github.com/dkratzert/Fastmolwidget/raw/main/docs/images/screenshot.png)
12
+
13
+ *View of a crystal structure from a CIF file with ADP ellipsoids. The control bar allows toggling display options interactively.*
14
+
15
+ ## Features
16
+
17
+ - **ADP ellipsoids** at the 50 % probability level, rendered from anisotropic displacement parameters
18
+ - **Ball-and-stick** and **isotropic sphere** representations as fallbacks or when speed is more important than detail
19
+ - **Interactive mouse controls**: rotate (left-drag), zoom (right-drag), pan (middle-drag), scroll wheel to resize labels
20
+ - **Atom and bond selection**: single click or Ctrl+click for multi-selection; emits `atomClicked` / `bondClicked` Qt signals
21
+ - **Hydrogen visibility toggle**
22
+ - **Atom label display toggle** with adjustable font size
23
+ - **Bond width** adjustment via spin box
24
+ - **Multiple file formats**: CIF, SHELX `.res`/`.ins`, and plain XYZ. More to come...
25
+ - **Embeddable** — `MoleculeWidget` is a plain `QWidget` subclass; drop it into any layout
26
+ - **Ready-to-use** `MoleculeViewerWidget` bundles the renderer with a full control bar
27
+
28
+ ## Supported File Formats
29
+
30
+ | Extension | Format | Notes |
31
+ |-----------|--------|-------|
32
+ | `.cif` | Crystallographic Information File | Reads atoms, unit cell, and ADPs |
33
+ | `.res` / `.ins` | SHELXL instruction file | Reads atoms and unit cell via [shelxfile](https://github.com/dkratzert/ShelXFile) |
34
+ | `.xyz` | Standard XYZ coordinate file | Cartesian coordinates, no cell or ADPs |
35
+
36
+ ## Installation
37
+
38
+ ```bash
39
+ pip install fastmolwidget
40
+ ```
41
+
42
+ By default, `fastmolwidget` installs **without a concrete Qt binding**.
43
+ Install one binding explicitly via extras:
44
+
45
+ ```bash
46
+ pip install "fastmolwidget[pyside6]"
47
+ pip install "fastmolwidget[pyqt6]"
48
+ ```
49
+
50
+ **Requirements**: Python >= 3.12, NumPy, gemmi, shelxfile, qtpy, and either PySide6 or PyQt6.
51
+
52
+ ## Quick Start
53
+
54
+ ### Standalone viewer
55
+
56
+ ```python
57
+ from qtpy.QtWidgets import QApplication
58
+ from fastmolwidget import MoleculeViewerWidget
59
+
60
+ app = QApplication([])
61
+ viewer = MoleculeViewerWidget()
62
+ viewer.load_file("structure.cif")
63
+ viewer.show()
64
+ app.exec()
65
+ ```
66
+
67
+ ### Embedding in your own layout
68
+
69
+ ```python
70
+ from fastmolwidget import MoleculeWidget, MoleculeLoader
71
+
72
+ mol = MoleculeWidget(parent=self)
73
+ loader = MoleculeLoader(mol)
74
+ # The loader recognizes the file format from the extension and populates `mol` accordingly
75
+ loader.load_file("structure.cif")
76
+
77
+ # drop `mol` into any QLayout
78
+ layout.addWidget(mol)
79
+ ```
80
+
81
+ ### Loading a different file at runtime
82
+
83
+ ```python
84
+ viewer.load_file("new_structure.res")
85
+ ```
86
+
87
+ ### Reacting to atom / bond clicks
88
+
89
+ ```python
90
+ mol.atomClicked.connect(lambda label: print(f"Clicked atom: {label}"))
91
+ mol.bondClicked.connect(lambda a, b: print(f"Clicked bond: {a}–{b}"))
92
+ ```
93
+
94
+ ## Mouse Controls
95
+
96
+ | Action | Effect |
97
+ |--------|--------|
98
+ | Left-drag | Rotate the molecule |
99
+ | Right-drag | Zoom in / out |
100
+ | Middle-drag | Pan the view |
101
+ | Scroll wheel | Increase / decrease label font size |
102
+ | Left-click | Select a single atom or bond |
103
+ | Ctrl + Left-click | Toggle multi-selection |
104
+
105
+ ## Control Bar Options (`MoleculeViewerWidget`)
106
+
107
+ | Control | Default | Description |
108
+ |---------|---------|-------------|
109
+ | Show ADP | ✓ | Toggle ORTEP ellipsoid / isotropic sphere rendering |
110
+ | Show Labels | ✗ | Toggle non-hydrogen atom labels |
111
+ | Round Bonds | ✓ | Switch between 3D-shaded and flat bond drawing |
112
+ | Show Hydrogens | ✓ | Show or hide hydrogen atoms and their bonds |
113
+ | Bond Width | 3 | Stroke width for bonds (1–15 px) |
114
+
115
+ ## API Overview
116
+
117
+ ### `MoleculeViewerWidget(parent=None)`
118
+
119
+ A self-contained widget combining `MoleculeWidget` with the control bar described above.
120
+
121
+ - `load_file(path)` — load a structure file (format auto-detected from extension)
122
+ - `render_widget` — read-only property exposing the underlying `MoleculeWidget`
123
+
124
+ ### `MoleculeWidget(parent=None)`
125
+
126
+ The low-level renderer widget. It is a plain `QWidget` subclass that you can drop into any layout.
127
+ Provide atom data directly via `open_molecule()` instead of loading a file through `MoleculeLoader`.
128
+
129
+ #### Qt Signals
130
+
131
+ | Signal | Signature | Emitted when |
132
+ |--------|-----------|--------------|
133
+ | `atomClicked` | `(label: str)` | The user clicks on an atom; `label` is the atom name (e.g. `"C1"`) |
134
+ | `bondClicked` | `(label1: str, label2: str)` | The user clicks on a bond; both atom labels are passed |
135
+
136
+ #### Data Methods
137
+
138
+ - **`open_molecule(atoms, cell=None, adps=None, keep_view=False)`**
139
+ Load a new set of atoms and reset (or optionally preserve) the view.
140
+ - `atoms` — list of `Atomtuple(label, type, x, y, z, part)` in Cartesian coordinates (Å)
141
+ - `cell` — optional `(a, b, c, α, β, γ)` tuple of unit-cell parameters (Å / °); required for ADP rendering
142
+ - `adps` — optional `dict` mapping atom labels to `(U11, U22, U33, U23, U13, U12)` ADP tensors
143
+ - `keep_view` — when `True`, the current zoom, pan, and rotation are preserved (useful for live updates)
144
+
145
+ - **`grow_molecule(atoms, cell=None, adps=None)`**
146
+ Replace the atom set while always preserving the current view.
147
+ Equivalent to calling `open_molecule(..., keep_view=True)`.
148
+
149
+ - **`clear()`**
150
+ Remove all atoms and bonds from the display.
151
+
152
+ #### Display Methods
153
+
154
+ - **`show_adps(value: bool)`**
155
+ Toggle ORTEP-style ADP ellipsoid rendering. When `False`, atoms are drawn as isotropic spheres.
156
+
157
+ - **`show_labels(value: bool)`**
158
+ Show or hide non-hydrogen atom labels.
159
+
160
+ - **`show_hydrogens(value: bool)`**
161
+ Show or hide hydrogen / deuterium atoms and their bonds.
162
+
163
+ - **`show_round_bonds(value: bool)`**
164
+ Switch between 3D-shaded cylinder-style bonds (`True`, default) and flat single-colour bonds (`False`).
165
+
166
+ - **`set_bond_width(width: int)`**
167
+ Set the stroke width for bonds in pixels (valid range: 1–15).
168
+
169
+ - **`setLabelFont(font_size: int)`**
170
+ Set the pixel size used for atom labels.
171
+
172
+ - **`set_background_color(color: QColor)`**
173
+ Change the widget background colour.
174
+
175
+ - **`reset_view()`**
176
+ Reset zoom, pan, and rotation to their defaults.
177
+
178
+ #### Example — feeding atom data directly
179
+
180
+ ```python
181
+ from fastmolwidget import MoleculeWidget
182
+ from fastmolwidget.sdm import Atomtuple
183
+
184
+ mol = MoleculeWidget(parent=self)
185
+
186
+ atoms = [
187
+ Atomtuple(label="C1", type="C", x=0.0, y=0.0, z=0.0, part=0),
188
+ Atomtuple(label="O1", type="O", x=1.22, y=0.0, z=0.0, part=0),
189
+ Atomtuple(label="H1", type="H", x=-0.5, y=0.94, z=0.0, part=0),
190
+ ]
191
+
192
+ # ADP tensors: {atom_label: (U11, U22, U33, U23, U13, U12)}
193
+ adps = {
194
+ "C1": (0.02, 0.02, 0.02, 0.0, 0.0, 0.0),
195
+ "O1": (0.03, 0.03, 0.03, 0.0, 0.0, 0.0),
196
+ }
197
+
198
+ cell = (5.0, 5.0, 5.0, 90.0, 90.0, 90.0) # optional
199
+
200
+ mol.open_molecule(atoms=atoms, cell=cell, adps=adps)
201
+ mol.atomClicked.connect(lambda label: print(f"Selected: {label}"))
202
+
203
+ layout.addWidget(mol)
204
+ ```
205
+
206
+ ### `MoleculeLoader(widget)`
207
+
208
+ Format-aware loader that populates a `MoleculeWidget`.
209
+
210
+ - `load_file(path, keep_view=False)` — parse file and call `open_molecule` / `grow_molecule`
211
+
212
+ ## License
213
+
214
+ BSD 2-Clause License — see [LICENSE](LICENSE) for details.
215
+
216
+ © 2026 Daniel Kratzert
217
+
218
+ ## Maintainer Release Workflow
219
+
220
+ The release workflow is tag-driven and currently publishes to **TestPyPI** only.
221
+
222
+ 1. Ensure `project.version` in `pyproject.toml` is the version to publish.
223
+ 2. Create and push a matching tag in the format `version-X.Y.Z`.
224
+ 3. GitHub Actions builds sdist/wheel and uploads to TestPyPI.
225
+
226
+ Example:
227
+
228
+ ```bash
229
+ git tag version-0.1.0
230
+ git push origin version-0.1.0
231
+ ```
232
+
@@ -0,0 +1,60 @@
1
+ [project]
2
+ name = "fastmolwidget"
3
+ version = "0.5.1"
4
+ description = "A PyQt widget to display crystal structures"
5
+ readme = "README.md"
6
+ license = { file = "LICENSE" }
7
+ authors = [
8
+ { name = "Daniel Kratzert", email = "dkratzert@gmx.de" }
9
+ ]
10
+ requires-python = ">=3.12"
11
+ keywords = ["chemistry", "crystallography", "qt", "widget", "molecule"]
12
+ classifiers = [
13
+ "Development Status :: 4 - Beta",
14
+ "License :: OSI Approved :: MIT License",
15
+ "Intended Audience :: Science/Research",
16
+ "Programming Language :: Python :: 3",
17
+ "Programming Language :: Python :: 3.12",
18
+ "Programming Language :: Python :: 3.13",
19
+ "Topic :: Scientific/Engineering :: Chemistry",
20
+ "Topic :: Software Development :: User Interfaces",
21
+ ]
22
+ dependencies = [
23
+ "gemmi>=0.7.5",
24
+ "numpy>=2.2.0",
25
+ "qtpy>=2.4.3",
26
+ "shelxfile>=22",
27
+ ]
28
+
29
+ [project.optional-dependencies]
30
+ pyside6 = [
31
+ "pyside6-essentials>=6.11.0",
32
+ ]
33
+ pyqt6 = [
34
+ "pyqt6>=6.9.0",
35
+ ]
36
+
37
+ [project.urls]
38
+ Homepage = "https://github.com/dkratzert/Fastmolwidget"
39
+ Repository = "https://github.com/dkratzert/Fastmolwidget"
40
+ Issues = "https://github.com/dkratzert/Fastmolwidget/issues"
41
+
42
+ [dependency-groups]
43
+ dev = [
44
+ "pytest",
45
+ "ruff",
46
+ "ty",
47
+ "pyside6-stubs",
48
+ ]
49
+
50
+ doc = [
51
+ "sphinx>=8.1.3",
52
+ "sphinx-rtd-theme",
53
+ ]
54
+
55
+ [project.scripts]
56
+ fastmolwidget = "fastmolwidget:main"
57
+
58
+ [build-system]
59
+ requires = ["uv_build>=0.11.6,<0.12.0"]
60
+ build-backend = "uv_build"
@@ -0,0 +1,9 @@
1
+ from fastmolwidget.viewer_widget import MoleculeViewerWidget
2
+ from fastmolwidget.molecule2D import MoleculeWidget
3
+ from fastmolwidget.loader import MoleculeLoader
4
+
5
+ __all__ = ["MoleculeViewerWidget", "MoleculeWidget", "MoleculeLoader"]
6
+
7
+
8
+ def main() -> None:
9
+ print("Hello from fastmolwidget!")