diff --git a/dstat_interface/experiments/chronoamp.py b/dstat_interface/experiments/chronoamp.py index a57ae83943bcd8472c0879de8e72e151edf5c25e..1f098552ee1639f539fffb39489e68f30862a0bf 100644 --- a/dstat_interface/experiments/chronoamp.py +++ b/dstat_interface/experiments/chronoamp.py @@ -25,9 +25,10 @@ class Chronoamp(Experiment): self.datalength = 2 self.databytes = 8 self.data = {'current_time' : [([],[])]} + self.columns = ['Time (s)', 'Current (A)'] self.plot_format = { 'current_time' : { - 'labels' : ('Time (s)','Current (A)'), + 'labels' : self.columns, 'xlims' : (0, sum(self.parameters['time'])) } } @@ -72,9 +73,10 @@ class PDExp(Chronoamp): self.datalength = 2 self.databytes = 8 self.data = {'current_time' : [([],[])]} + self.columns = ['Time (s)', 'Current (A)'] self.plot_format = { 'current_time' : { - 'labels' : ('Time (s)','Current (A)'), + 'labels' : self.columns, 'xlims' : (0, int(self.parameters['time'])) } } diff --git a/dstat_interface/experiments/experiment_template.py b/dstat_interface/experiments/experiment_template.py index 3cc2d6612c468f267fe21ab9377616e12a83bff9..72e1e25215161beb49d94658761d1a54f22888e1 100755 --- a/dstat_interface/experiments/experiment_template.py +++ b/dstat_interface/experiments/experiment_template.py @@ -19,6 +19,8 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. import logging import struct +from datetime import datetime +from collections import OrderedDict from copy import deepcopy from math import ceil @@ -36,7 +38,9 @@ import matplotlib.pyplot as plt from matplotlib.backends.backend_gtk3agg \ import FigureCanvasGTK3Agg as FigureCanvas - + +from pandas import DataFrame + try: import seaborn as sns sns.set(context='paper', style='darkgrid') @@ -100,18 +104,22 @@ class Experiment(object): p=self.parameters) self.setup() + self.time = [datetime.utcnow()] def setup(self): - self.data = {'current_voltage' : [([],[])]} + self.data = OrderedDict( + (('current_voltage', [([],[])])) + ) + + self.columns = ['Voltage (mV)', 'Current (A)'] self.plot_format = { - 'current_voltage' : {'labels' : ('Voltage (mV)', - 'Current (A)' - ), + 'current_voltage' : {'labels' : self.columns, 'xlims' : (0, 1) } } # list of scans, tuple of dimensions, list of data self.line_data = ([], []) + self.columns = ('Voltage (mV)', 'Current (A)') self.plots.append(PlotBox(['current_voltage'])) @@ -235,6 +243,11 @@ class Experiment(object): return data + def experiment_done(self): + """Runs when experiment is finished (all data acquired)""" + self.data_to_pandas() + self.time += [datetime.utcnow()] + def export(self): """Return a dict containing data for saving.""" output = { @@ -250,7 +263,34 @@ class Experiment(object): return output - + def data_to_pandas(self): + """Convert data to pandas DataFrame and set as member of .df + attribute.""" + self.df = OrderedDict() + + for name, data in self.data.items(): + df = DataFrame(columns=['Scan'] + self.columns) + + for n, line in enumerate(data): + df = df.append(DataFrame( + OrderedDict(zip(['Scan'] + self.columns, + [n] + list(line)) + ) + ), ignore_index = True + ) + + self.df[name] = df + + def get_info_text(self): + """Return string of text to disply on Info tab.""" + buf = "#Time: S{} E{}\n".format(self.time[0], self.time[1]) + buf += "#Commands:\n" + + for line in self.commands: + buf += '#{}\n'.format(line) + + return buf + class PlotBox(object): """Contains data plot and associated methods.""" def __init__(self, plots): diff --git a/dstat_interface/experiments/pot.py b/dstat_interface/experiments/pot.py index b4de2250b9acf5a6487098479e5e74f336e50564..2859e4681aae4350acf71250eb7dcbad711140cf 100644 --- a/dstat_interface/experiments/pot.py +++ b/dstat_interface/experiments/pot.py @@ -25,11 +25,10 @@ class PotExp(Experiment): self.datalength = 2 self.databytes = 8 self.data = {'voltage_time' : [([],[])]} + self.columns = ['Time (s)', 'Voltage (V)'] self.plot_format = { 'voltage_time' : { - 'labels' : ('Time (s)', - 'Voltage (V)' - ), + 'labels' : self.columns, 'xlims' : (0, int(self.parameters['time'])) } } diff --git a/dstat_interface/experiments/swv.py b/dstat_interface/experiments/swv.py index f4b328f523b112441fc1584cef5d3415c21b7650..2f3ba803da10e61f15078946485867b641081547 100644 --- a/dstat_interface/experiments/swv.py +++ b/dstat_interface/experiments/swv.py @@ -32,7 +32,8 @@ class SWVExp(Experiment): self.line_data = ([], [], [], []) self.datalength = 2 * self.parameters['scans'] self.databytes = 10 - + self.columns = ['Voltage (mV)', 'Net Current (A)', + 'Forward Current (A)', 'Reverse Current (A)'] self.plot_format = { 'swv' : {'labels' : ('Voltage (mV)', 'Current (A)' @@ -109,7 +110,8 @@ class DPVExp(SWVExp): self.line_data = ([], [], [], []) self.datalength = 2 self.databytes = 10 - + self.columns = ['Voltage (mV)', 'Net Current (A)', + 'Forward Current (A)', 'Reverse Current (A)'] self.plot_format = { 'swv' : {'labels' : ('Voltage (mV)', 'Current (A)' diff --git a/dstat_interface/interface/data_view.py b/dstat_interface/interface/data_view.py new file mode 100644 index 0000000000000000000000000000000000000000..2ef8ff58c2d39646c5b33f835abbb5b029ee03ed --- /dev/null +++ b/dstat_interface/interface/data_view.py @@ -0,0 +1,76 @@ +from __future__ import division, absolute_import, print_function, unicode_literals + +import logging +logger = logging.getLogger("dstat.interface.data_view") + +from collections import OrderedDict + +try: + import gi + gi.require_version('Gtk', '3.0') + from gi.repository import Gtk +except ImportError: + print("ERR: GTK not available") + sys.exit(1) + +class DataPage(object): + def __init__(self, notebook, name="Data"): + """Make new notebook page and adds to notebook.""" + self.box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) + self.combobox = Gtk.ComboBoxText() + self.scroll = Gtk.ScrolledWindow(vexpand=True) + self.textview = Gtk.TextView(cursor_visible=False, monospace=True, + editable=False) + self.scroll.add(self.textview) + self.box.add(self.combobox) + self.box.add(self.scroll) + self.name = name + self.buffers = {} + + self.combobox.connect('changed', self.combobox_changed) + + notebook.append_page(self.box, Gtk.Label(label=name)) + + def add_exp(self, exp): + """Add all data from exp to page.""" + for name, df in exp.df.items(): + self.combobox.append(id=name, text=name) + self.buffers[name] = Gtk.TextBuffer() + self.buffers[name].set_text(df.to_string()) + self.box.show_all() + + self.combobox.set_active(0) + + def clear_exps(self): + self.combobox.remove_all() + self.buffers = {} + + def combobox_changed(self, object): + """Switch displayed data buffer.""" + self.textview.set_buffer(self.buffers[self.combobox.get_active_id()]) + +class InfoPage(object): + def __init__(self, notebook, name="Info"): + """Make new notebook page and adds to notebook.""" + self.box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) + self.buffer = Gtk.TextBuffer() + self.scroll = Gtk.ScrolledWindow(vexpand=True) + self.textview = Gtk.TextView(cursor_visible=False, monospace=True, + editable=False, buffer=self.buffer) + self.scroll.add(self.textview) + self.box.add(self.scroll) + + self.name = name + + notebook.append_page(self.box, Gtk.Label(label=name)) + self.box.show_all() + + def clear(self): + """Clear buffer""" + self.buffer.set_text('') + + def set_text(self, text): + self.buffer.set_text(text) + + def add_line(self, line): + self.buffer.insert_at_cursor('{}\n'.format(line)) \ No newline at end of file diff --git a/dstat_interface/interface/dstatinterface.glade b/dstat_interface/interface/dstatinterface.glade index 02aab91f98344971444470fc676593c4e7e46437..09dfb6cbcf6ad8740b4256a982dec50d3328ecce 100644 --- a/dstat_interface/interface/dstatinterface.glade +++ b/dstat_interface/interface/dstatinterface.glade @@ -1007,7 +1007,7 @@ Thanks to Christian Fobel for help with Dropbot Plugin</property> </packing> </child> <child> - <object class="GtkNotebook" id="notebook1"> + <object class="GtkNotebook" id="main_notebook"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="scrollable">True</property> @@ -1122,64 +1122,16 @@ Thanks to Christian Fobel for help with Dropbot Plugin</property> </packing> </child> <child> - <object class="GtkScrolledWindow" id="scrolledwindow1"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <child> - <object class="GtkTextView" id="datatextview1"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="editable">False</property> - <property name="left_margin">10</property> - <property name="right_margin">10</property> - <property name="buffer">databuffer1</property> - </object> - </child> - </object> - <packing> - <property name="position">1</property> - </packing> + <placeholder/> </child> <child type="tab"> - <object class="GtkLabel" id="label3"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">Raw Data</property> - </object> - <packing> - <property name="position">1</property> - <property name="tab_fill">False</property> - </packing> + <placeholder/> </child> <child> - <object class="GtkScrolledWindow" id="scrolledwindow2"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <child> - <object class="GtkTextView" id="datatextview2"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="editable">False</property> - <property name="left_margin">10</property> - <property name="right_margin">10</property> - <property name="buffer">databuffer2</property> - </object> - </child> - </object> - <packing> - <property name="position">2</property> - </packing> + <placeholder/> </child> <child type="tab"> - <object class="GtkLabel" id="label5"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">Extra Data</property> - </object> - <packing> - <property name="position">2</property> - <property name="tab_fill">False</property> - </packing> + <placeholder/> </child> </object> <packing> diff --git a/dstat_interface/main.py b/dstat_interface/main.py index 27c017d94b7a875400c557d113993671a92d426c..f30fbff0ac305142b14d48862c138f4f6f45acdd 100755 --- a/dstat_interface/main.py +++ b/dstat_interface/main.py @@ -53,6 +53,7 @@ import experiments as exp import interface.exp_window as exp_window import interface.adc_pot as adc_pot import interface.plot_ui +import interface.data_view import plot import params import parameter_test @@ -88,8 +89,6 @@ class Main(object): self.ocp_disp = self.builder.get_object('ocp_disp') self.window = self.builder.get_object('window1') self.aboutdialog = self.builder.get_object('aboutdialog1') - self.rawbuffer = self.builder.get_object('databuffer1') - self.databuffer = self.builder.get_object('databuffer2') self.stopbutton = self.builder.get_object('pot_stop') self.startbutton = self.builder.get_object('pot_start') self.adc_pot = adc_pot.adc_pot() @@ -107,6 +106,9 @@ class Main(object): # Setup Plots self.plot_notebook = self.builder.get_object('plot_notebook') + self.main_notebook = self.builder.get_object('main_notebook') + self.data_view = interface.data_view.DataPage(self.main_notebook) + self.info_page = interface.data_view.InfoPage(self.main_notebook) #fill adc_pot_box self.adc_pot_box = self.builder.get_object('gain_adc_box') @@ -446,8 +448,11 @@ class Main(object): self.plot_notebook, self.current_exp, self.window ) - for plots in self.current_exp.plots: - plots.changetype(self.current_exp) + for plot in self.current_exp.plots: + plot.changetype(self.current_exp) + + self.data_view.clear_exps() + self.info_page.clear() comm.serial_instance.proc_pipe_p.send(self.current_exp) @@ -594,46 +599,40 @@ class Main(object): copy data to raw data tab. Saves data if autosave enabled. """ try: - self.current_exp.time = datetime.now() + self.current_exp.experiment_done() GObject.source_remove(self.experiment_proc[0]) GObject.source_remove(self.plot_proc) # stop automatic plot update self.experiment_running_plot(force_refresh=True) - self.databuffer.set_text("") - self.databuffer.place_cursor(self.databuffer.get_start_iter()) - self.rawbuffer.insert_at_cursor("\n") - self.rawbuffer.set_text("") - self.rawbuffer.place_cursor(self.rawbuffer.get_start_iter()) - - # Shutter stuff - if (self.current_exp.parameters['shutter_true'] and - self.current_exp.parameters['sync_true']): - self.ft_plot.updateline(self.current_exp, 0) - self.ft_plot.redraw() - - line_buffer = [] - - for scan in self.current_exp.data['ft']: - for dimension in scan: - for i in range(len(dimension)): - try: - line_buffer[i] += "%s " % dimension[i] - except IndexError: - line_buffer.append("") - line_buffer[i] += "%s " % dimension[i] - - for i in line_buffer: - self.databuffer.insert_at_cursor("%s\n" % i) + + # # Shutter stuff + # if (self.current_exp.parameters['shutter_true'] and + # self.current_exp.parameters['sync_true']): + # self.ft_plot.updateline(self.current_exp, 0) + # self.ft_plot.redraw() + # + # line_buffer = [] + # + # for scan in self.current_exp.data['ft']: + # for dimension in scan: + # for i in range(len(dimension)): + # try: + # line_buffer[i] += "%s " % dimension[i] + # except IndexError: + # line_buffer.append("") + # line_buffer[i] += "%s " % dimension[i] + # + # for i in line_buffer: + # self.databuffer.insert_at_cursor("%s\n" % i) # Run Analysis analysis.do_analysis(self.current_exp) - + + self.current_exp.experiment_done() + # Write DStat commands - for i in self.current_exp.commands: - self.rawbuffer.insert_at_cursor(i) - - self.rawbuffer.insert_at_cursor("\n") - + self.info_page.set_text(self.current_exp.get_info_text()) + try: self.statusbar.push( self.message_context_id, @@ -656,21 +655,9 @@ class Main(object): ) for i in analysis_buffer: - self.rawbuffer.insert_at_cursor("%s\n" % i) + self.info_page.add_line(i) - # line_buffer = [] - # - # for scan in self.current_exp.data['data']: - # for dimension in scan: - # for i in range(len(dimension)): - # try: - # line_buffer[i] += "%s " % dimension[i] - # except IndexError: - # line_buffer.append("") - # line_buffer[i] += "%s " % dimension[i] - # - # for i in line_buffer: - # self.rawbuffer.insert_at_cursor("%s\n" % i) + self.data_view.add_exp(self.current_exp) # Autosaving if self.autosave_checkbox.get_active():