source: sasview/src/sas/sasgui/perspectives/file_converter/converter_panel.py @ f2b3f28

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since f2b3f28 was f2b3f28, checked in by lewis, 8 years ago

Allow user to input some CanSAS metadata

  • Property mode set to 100644
File size: 7.6 KB
Line 
1"""
2This module provides a GUI for the file converter
3"""
4
5import wx
6import sys
7import numpy as np
8from wx.lib.scrolledpanel import ScrolledPanel
9from sas.sasgui.guiframe.panel_base import PanelBase
10from sas.sasgui.perspectives.calculator import calculator_widgets as widget
11from sas.sasgui.guiframe.events import StatusEvent
12from sas.sasgui.guiframe.dataFitting import Data1D
13from sas.sascalc.dataloader.readers.cansas_reader import Reader as CansasReader
14from sas.sascalc.dataloader.data_info import Detector
15
16# Panel size
17if sys.platform.count("win32") > 0:
18    PANEL_TOP = 0
19    _STATICBOX_WIDTH = 410
20    _BOX_WIDTH = 200
21    PANEL_SIZE = 460
22    FONT_VARIANT = 0
23else:
24    PANEL_TOP = 60
25    _STATICBOX_WIDTH = 430
26    _BOX_WIDTH = 200
27    PANEL_SIZE = 480
28    FONT_VARIANT = 1
29
30class ConverterPanel(ScrolledPanel, PanelBase):
31
32    def __init__(self, parent, base=None, *args, **kwargs):
33        ScrolledPanel.__init__(self, parent, *args, **kwargs)
34        PanelBase.__init__(self)
35        self.SetupScrolling()
36        self.SetWindowVariant(variant=FONT_VARIANT)
37
38        self.base = base
39        self.parent = parent
40
41        self.q_input = None
42        self.iq_input = None
43        self.output = None
44
45        self.metadata = {
46            'title': None,
47            'run': None,
48            'run_name': None,
49            'instrument': None,
50            'detector': None,
51        }
52
53        self._do_layout()
54        self.SetAutoLayout(True)
55        self.Layout()
56
57    def convert_to_cansas(self, data, filename):
58        reader = CansasReader()
59        reader.write(filename, data)
60
61    def extract_data(self, filename):
62        data = np.loadtxt(filename, dtype=str)
63
64        if len(data.shape) != 1:
65            msg = "Error reading {}: Only one column of data is allowed"
66            raise Exception(msg.format(filename.split('\\')[-1]))
67
68        is_float = True
69        try:
70            float(data[0])
71        except:
72            is_float = False
73
74        if not is_float:
75            end_char = data[0][-1]
76            # If lines end with comma or semi-colon, trim the last character
77            if end_char == ',' or end_char == ';':
78                data = map(lambda s: s[0:-1], data)
79            else:
80                msg = ("Error reading {}: Lines must end with a digit, comma "
81                    "or semi-colon").format(filename.split('\\')[-1])
82                raise Exception(msg)
83
84        return np.array(data, dtype=np.float32)
85
86    def on_convert(self, event):
87        try:
88            qdata = self.extract_data(self.q_input.GetPath())
89            iqdata = self.extract_data(self.iq_input.GetPath())
90        except Exception as ex:
91            msg = str(ex)
92            wx.PostEvent(self.parent.manager.parent,
93                StatusEvent(status=msg, info='error'))
94            return
95
96        output_path = self.output.GetPath()
97        data = Data1D(x=qdata, y=iqdata)
98        data.filename = output_path.split('\\')[-1]
99
100        if self.metadata['run'] is not None:
101            run = self.metadata['run']
102            run_name = self.metadata['run_name']
103            self.metadata['run'] = [run]
104            if run_name is not None:
105                self.metadata['run_name'] = { run: run_name }
106        if self.metadata['detector'] is not None:
107            name = self.metadata['detector']
108            detector = Detector()
109            detector.name = name
110            self.metadata['detector'] = [detector]
111
112        for attr, value in self.metadata.iteritems():
113            setattr(data, attr, value)
114
115        self.convert_to_cansas(data, output_path)
116        wx.PostEvent(self.parent.manager.parent,
117            StatusEvent(status="Conversion completed."))
118
119    def metadata_changed(self, event):
120        event.Skip()
121        textbox = event.GetEventObject()
122        attr = textbox.GetName()
123        value = textbox.GetValue().strip()
124        if value == '':
125            self.metadata[attr] = None
126        else:
127            self.metadata[attr] = value
128
129
130    def _do_layout(self):
131        vbox = wx.BoxSizer(wx.VERTICAL)
132
133        instructions = ("Select the 1 column ASCII files containing the Q Axis"
134            "and Intensity data, chose where to save the converted file, then "
135            "click Convert to convert them to CanSAS XML format")
136        instruction_label = wx.StaticText(self, -1, instructions,
137            size=(_STATICBOX_WIDTH+40, -1))
138        instruction_label.Wrap(_STATICBOX_WIDTH+40)
139        vbox.Add(instruction_label, flag=wx.TOP | wx.LEFT | wx.RIGHT, border=5)
140
141        section = wx.StaticBox(self, -1)
142        section_sizer = wx.StaticBoxSizer(section, wx.VERTICAL)
143        section_sizer.SetMinSize((_STATICBOX_WIDTH, -1))
144
145        input_grid = wx.GridBagSizer(5, 5)
146
147        q_label = wx.StaticText(self, -1, "Q Axis: ")
148        input_grid.Add(q_label, (0,0), (1,1), wx.ALIGN_CENTER_VERTICAL, 5)
149
150        self.q_input = wx.FilePickerCtrl(self, -1,
151            size=(_STATICBOX_WIDTH-80, -1),
152            message="Chose the Q Axis data file.")
153        input_grid.Add(self.q_input, (0,1), (1,1), wx.ALL, 5)
154
155        iq_label = wx.StaticText(self, -1, "Intensity Data: ")
156        input_grid.Add(iq_label, (1,0), (1,1), wx.ALIGN_CENTER_VERTICAL, 5)
157
158        self.iq_input = wx.FilePickerCtrl(self, -1,
159            size=(_STATICBOX_WIDTH-80, -1),
160            message="Chose the Intensity data file.")
161        input_grid.Add(self.iq_input, (1,1), (1,1), wx.ALL, 5)
162
163        output_label = wx.StaticText(self, -1, "Output File: ")
164        input_grid.Add(output_label, (2,0), (1,1), wx.ALIGN_CENTER_VERTICAL, 5)
165
166        self.output = wx.FilePickerCtrl(self, -1,
167            size=(_STATICBOX_WIDTH-80, -1),
168            message="Chose the Intensity data file.",
169            style=wx.FLP_SAVE | wx.FLP_OVERWRITE_PROMPT | wx.FLP_USE_TEXTCTRL,
170            wildcard="*.xml")
171        input_grid.Add(self.output, (2,1), (1,1), wx.ALL, 5)
172
173        convert_btn = wx.Button(self, -1, "Convert")
174        input_grid.Add(convert_btn, (3,0), (1,1), wx.ALL, 5)
175        convert_btn.Bind(wx.EVT_BUTTON, self.on_convert)
176
177        section_sizer.Add(input_grid)
178
179        vbox.Add(section_sizer, flag=wx.ALL, border=5)
180
181        metadata_section = wx.CollapsiblePane(self, -1, "Metadata",
182            size=(_STATICBOX_WIDTH+40, -1))
183
184        metadata_grid = wx.GridBagSizer(5, 5)
185
186        y = 0
187        for item in self.metadata.keys():
188            label = wx.StaticText(metadata_section.GetPane(), -1, item,
189                style=wx.ALIGN_CENTER_VERTICAL)
190            input_box = wx.TextCtrl(metadata_section.GetPane(), name=item,
191                size=(_STATICBOX_WIDTH-80, -1))
192            input_box.Bind(wx.EVT_TEXT, self.metadata_changed)
193            metadata_grid.Add(label, (y,0), (1,1),
194                wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
195            metadata_grid.Add(input_box, (y,1), (1,1), wx.EXPAND)
196            y += 1
197
198        metadata_section.GetPane().SetSizer(metadata_grid)
199
200        vbox.Add(metadata_section, proportion=0, flag=wx.ALL, border=5)
201
202        vbox.Fit(self)
203        self.SetSizer(vbox)
204
205class ConverterWindow(widget.CHILD_FRAME):
206
207    def __init__(self, parent=None, title='File Converter', base=None,
208        manager=None, size=(PANEL_SIZE * 1.05, PANEL_SIZE / 1.55),
209        *args, **kwargs):
210        kwargs['title'] = title
211        kwargs['size'] = size
212        widget.CHILD_FRAME.__init__(self, parent, *args, **kwargs)
213
214        self.manager = manager
215        self.panel = ConverterPanel(self, base=None)
216        self.Bind(wx.EVT_CLOSE, self.on_close)
217        self.SetPosition((wx.LEFT, PANEL_TOP))
218        self.Show(True)
219
220    def on_close(self, event):
221        if self.manager is not None:
222            self.manager.converter_frame = None
223        self.Destroy()
Note: See TracBrowser for help on using the repository browser.