Coverage for /builds/debichem-team/python-ase/ase/gui/save.py: 79.59%
49 statements
« prev ^ index » next coverage.py v7.5.3, created at 2025-03-06 04:00 +0000
« prev ^ index » next coverage.py v7.5.3, created at 2025-03-06 04:00 +0000
1"""Dialog for saving one or more configurations."""
3import numpy as np
5import ase.gui.ui as ui
6from ase.gui.i18n import _
7from ase.io.formats import (
8 filetype,
9 get_ioformat,
10 parse_filename,
11 string2index,
12 write,
13)
15text = _("""\
16Append name with "@n" in order to write image
17number "n" instead of the current image. Append
18"@start:stop" or "@start:stop:step" if you want
19to write a range of images. You can leave out
20"start" and "stop" so that "name@:" will give
21you all images. Negative numbers count from the
22last image. Examples: "name@-1": last image,
23"name@-2:": last two.""")
26def save_dialog(gui, filename=None):
27 dialog = ui.SaveFileDialog(gui.window.win, _('Save ...'))
28 # fix tkinter not automatically setting dialog type
29 # remove from Python3.8+
30 # see https://github.com/python/cpython/pull/25187
31 # and https://bugs.python.org/issue43655
32 # and https://github.com/python/cpython/pull/25592
33 ui.set_windowtype(dialog.top, 'dialog')
34 ui.Text(text).pack(dialog.top)
35 filename = filename or dialog.go()
36 if not filename:
37 return
39 filename, index = parse_filename(filename)
40 if index is None:
41 index = slice(gui.frame, gui.frame + 1)
42 elif isinstance(index, str):
43 index = string2index(index)
44 elif isinstance(index, slice):
45 pass
46 else:
47 if index < 0:
48 index += len(gui.images)
49 index = slice(index, index + 1)
50 format = filetype(filename, read=False)
51 io = get_ioformat(format)
53 extra = {}
54 remove_hidden = False
55 if format in ['png', 'eps', 'pov']:
56 bbox = np.empty(4)
57 size = gui.window.size / gui.scale
58 bbox[0:2] = np.dot(gui.center, gui.axes[:, :2]) - size / 2
59 bbox[2:] = bbox[:2] + size
60 extra['rotation'] = gui.axes
61 extra['show_unit_cell'] = gui.window['toggle-show-unit-cell']
62 extra['bbox'] = bbox
63 colors = gui.get_colors(rgb=True)
64 extra['colors'] = [rgb for rgb, visible
65 in zip(colors, gui.images.visible)
66 if visible]
67 remove_hidden = True
69 images = [gui.images.get_atoms(i, remove_hidden=remove_hidden)
70 for i in range(*index.indices(len(gui.images)))]
72 if len(images) > 1 and io.single:
73 # We want to write multiple images, but the file format does not
74 # support it. The solution is to write multiple files, inserting
75 # a number in the file name before the suffix.
76 j = filename.rfind('.')
77 filename = filename[:j] + '{0:05d}' + filename[j:]
78 for i, atoms in enumerate(images):
79 write(filename.format(i), atoms, **extra)
80 else:
81 try:
82 write(filename, images, **extra)
83 except Exception as err:
84 from ase.gui.ui import showerror
85 showerror(_('Error'), err)
86 raise