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