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

1# fmt: off 

2 

3"""Dialog for saving one or more configurations.""" 

4 

5import numpy as np 

6 

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) 

16 

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.""") 

26 

27 

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 

34 

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) 

48 

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 

64 

65 images = [gui.images.get_atoms(i, remove_hidden=remove_hidden) 

66 for i in range(*index.indices(len(gui.images)))] 

67 

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