Coverage for /builds/ase/ase/ase/gui/save.py : 79.59%

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