def done(self): """ Run when GUI is exited. Cleanly terminates the dataset with NaN values. """ dStamp = dateStamp() # If the dataset was being logged. if self.hasData: depvars = [] vars = [] vars.append(dStamp.utcNowFloat()) # Append NaN. try: for y in range(1, self.dataSet.getParameter("DataWidth")): depvars.append(float(np.nan)) newdepvars = [ getattr(np, self.dataType)(var) for var in depvars ] vars.extend(newdepvars) print "appending:", vars self.dataSet.addData([vars]) except: traceback.print_exc()
def save(self): '''Stores the data''' # For all datasets, check if there are readings #for i in range(0, len(self.devices)): if(self.device.getFrame().getReadings() is not None): # If the device did not have any readings and now it does # then we want to create a dataset. if(not self.hasData): self.configureDataSets() # For all datasets # for i in range(0, len(self.dataSets)): # If there is data in this dataset if(self.hasData): depvars = [] indepvars = [] vars = [] readings = [] # Get the newest data #print self.devices[i].getFrame().getReadings() for y in range(0, len(self.device.getFrame() .getNicknames())): # This checks if the reading is displayed on the GUI # if it is not, then it does not include it in the # dataset. if(self.device.getFrame().getNicknames() [y] is not None): # If the device has readings if(self.device.getFrame().getReadings() is not None): if(self.device.getFrame().getReadings()[y] is not None): readings.append(float(self.device .getFrame().getReadings()[y])) else: readings.append(np.nan) else: readings.append(np.nan) dStamp = dateStamp() # If the device has readings, add data to dataset if(readings is not None): indepvars.append(dStamp.utcNowFloat()) depvars.extend(readings) vars.extend(indepvars) vars.extend(depvars) varslist = self.dataSet.getVariables() try: self.dataSet.addData([vars]) except: print self.device.getFrame().getTitle()+( "ERROR: could not store data, this might be due " "to a change made to the parameters of the device, " "if this is the case thene either delete the " "data set from the current storage directory or " "move it somewhere else." )
def done(self): '''Run when GUI is exited. Cleanly terminates the dataset with Nan values.''' dStamp = dateStamp() # If the dataset was being logged if(self.hasData): vars = [] vars.append(dStamp.utcNowFloat()) # Append Nan for y in range(1, self.dataSet.getParameter("DataWidth")): vars.append(np.nan) #print(vars) self.dataSet.addData([vars])
def __init__(self, device, **kwargs): """Initiallize the dataChest.""" # Define the current time. now = dt.datetime.now() # Create a devices reference that can be accessed # outside of this scope. self.device = device self.device.getFrame().setDataChestWrapper(self) # These arrays will hold all dataChest data sets. self.dataSet = None # The done function must be called when the GUI exits. self.dataType = kwargs.get("data_type", 'float32') self.dataSet = None self.hasData = False self.keepLoggingNan = True self.dStamp = dateStamp() self.restoreState()
def plot(self, timeRange): if not self.hidden: if timeRange != self.currTimeRange: self.timer.stop() self.timer.timeout.disconnect() self.currTimeRange = timeRange self.timer.timeout.connect(lambda: self.plot(self.currTimeRange)) self.timer.start(self.refreshRateSec * 1000) if self.refreshRateSec != self.device.getFrame().getPlotRefreshRate(): # print "New plot refresh rate: ", self.device.getFrame().getPlotRefreshRate() self.refreshRateSec = self.device.getFrame().getPlotRefreshRate() self.timer.stop() self.timer.timeout.disconnect() self.currTimeRange = timeRange self.timer.timeout.connect(lambda: self.plot(self.currTimeRange)) self.timer.start(self.refreshRateSec * 1000) dataSet = self.device.getFrame().getDataSet() # If the dataset exists if dataSet is not None: # Get all data from the dataset data = dataSet.getData() self.ax.hold(False) try: # for each entry in the dataset [[time], [[data], [data], [data...]]] # print data # Get the corresponding times that the values were recorded for i in range(1, len(data[-1])): # Get colum. aka all values from parameter i over time column = [row[i] for row in data] # print times # If the there is no defined a time range if self.currTimeRange is None: times = [datetime.datetime.fromtimestamp(row[0]) for row in data] # Plot all of the data (columns) vs time # self.ax.plot_date(times, column, label = # dataSet.getVariables()[1][i-1][0]) pass else: # Otherwise, if the user PREVIOUSLY defined a time range, # we need to look for the beginning of it. # Start by getting the current time dstamp = dateStamp() # The dataset should be from now to -timerange # time(now)-time(range) startTime = dstamp.utcNowFloat() - self.currTimeRange # If timeRange is not None, then we know we need # to display only a certain range of values # However, if the starttime defined is less than the lowest time, we # do not have enough data to display the whole thing, so we must # display all that we have instead. We do this by setting # currTimeRange = 0. if timeRange is not None and startTime < float(data[0][0]): self.currTimeRange = None # For all entries in data for y in range(len(data)): # We are searching backwards through the dataset to find a time # just before the time range specified if data[len(data) - y - 1][0] < startTime: # once we find it, we know the beginning index of the data to be # displayed index = y # Get the times and datafrom the index and columns to the end of the dataset times = [datetime.datetime.fromtimestamp(row[0]) for row in data[-index:]] # print times[0] column = [row[i] for row in data[-index:]] # Exit the loop break try: while len(self.line) <= i: self.line.append(self.ax.plot(1, 1, label=dataSet.getVariables()[1][i - 1][0])[0]) self.line[i].set_data(times, column) self.ax.legend(loc="upper left", shadow=True, fancybox=True) # maxi = max(column) # mini = min(column) # newMax = max(column) # newMini = min(column) # if(newMax>maxi) # maxi=newMax # self.ax.set_ylim(mini-mini/2, maxi+maxi/2) # if(newMini<mini) # self.ax.set_ylim(mini-mini/2, maxi+maxi/2) # maxi = max(column) # mini = min(column) # self.ax.set_ylim(mini-mini/2, maxi+maxi/2) # self.ax.set_xlim(min(times), max(times)) # self.ax.draw_artist(self.line[i]) except: traceback.print_exc() # print "Failed to log data" # Add a legend legend = self.ax.legend(loc="upper left") self.ax.set_title( self.device.getFrame().getTitle(), color=(189.0 / 255, 195.0 / 255, 199.0 / 255) ) if ( self.device.getFrame().getYLabel() is not None and len(self.device.getFrame().getCustomUnits()) is not 0 ): self.ax.set_ylabel( self.device.getFrame().getYLabel() + " (" + self.device.getFrame().getCustomUnits() + ")" ) elif ( self.device.getFrame().getYLabel() is not None and len(self.device.getFrame().getUnits()[i - 1]) is not 0 ): self.ax.set_ylabel( self.device.getFrame().getYLabel() + " (" + self.device.getFrame().getUnits()[i - 1] + ")" ) self.ax.set_xlabel("Time") self.ax.hold(True) # locator = AutoDateLocator() # self.ax.fmt_xdata = AutoDateFormatter() # self.ax.xaxis.set_major_locator(locator) # self.ax.xaxis.set_major_locator(locator) # self.ax.xaxis.set_major_formatter(DateFormatter('%m/%d')) # self.ax.fmt_xdata = mdates.DateFormatter('%m/%d %H:%M:%S') # print "type: ", type(times[-1]) # print "time[-1]: ",times[-1] # self.ax.set_ylim(bottom = 733681, top = 733682) # self.figure.tight_layout() self.ax.grid(True) except Exception as e: print "Error" try: self.ax.grid(True) # self.ax.clear(self.ax.yaxis) # self.ax.cla() if self.home: self.ax.set_xlim(times[0], times[-1]) self.ax.relim() self.ax.autoscale() # print self.ax.get_data_interval() self.ax.draw_artist(self.figure) self.ax.draw_artist(self.ax.patch) locator = AutoDateLocator() self.ax.xaxis.set_major_locator(locator) self.ax.xaxis.set_major_formatter(DateFormatter("%m/%d %H:%M:%S")) self.figure.autofmt_xdate() # print [time.toordinal() for time in times] self.ax.draw_artist(self.ax.yaxis) self.ax.draw_artist(self.ax.xaxis) for line in self.line: self.ax.draw_artist(line) # self.ax.axis('off') self.ax.draw_artist(legend) self.canvas.update() self.canvas.flush_events() except: times = [datetime.datetime.fromtimestamp(row[0]) for row in data] traceback.print_exc() self.ax.set_xlim(times[0], times[-1]) self.ax.relim() self.ax.autoscale() # print self.ax.get_data_interval() pass
def configureDataSets(self): '''Initialize the datalogger, if datasets already exist, use them. Otherwise create new ones.''' now = datetime.datetime.now() self.hasData = True # Generate a title for the dataset. NOTE: if # the title of the device is changed in the device's constructor # in the main class, then a different data set will be created. # This is because datasets are stored using the name of the device, # which is what the program looks for when checking if there are # data files that already exist. title = str(self.device.getFrame().getTitle()).replace(" ", "") # Datasets are stored in the folder 'DATA_CHEST_ROOT\year\month\' # Try to access the current month's folder, if it does not exist, # make it. try: self.dataSet.cd(str(now.month)) except: self.dataSet.mkdir(str(now.month)) self.dataSet.cd(str(now.month)) try: self.dataSet.cd(str(int(now.day/7))) except: self.dataSet.mkdir(str(int(now.day/7))) self.dataSet.cd(str(int(now.day/7))) # Look at the names of all existing datasets and check if the # name contains the title of the current device. existingFiles = self.dataSet.ls() # foundit becomes true if a dataset file already exists foundit = False # Go through all existing dataset files for y in range(0, len(existingFiles[0])): # If the name of the file contains the (persistant) title # generated by the code, open that dataset and use it. if(title in existingFiles[0][y]): self.dataSet.openDataset(existingFiles[0][y], modify = True) foundit = True # if(foundit): print("Existing data set found for "+title+": " +existingFiles[0][y]) if(foundit): pass # If the dataset does not already exist, we must create it. else: print("Creating dataset for "+title) # Name of the parameter. This is the name of the parameter # displayed on the gui except without spaces or # non-alphanumerical characters. paramName = None # Arrays to hold any variables depvars = [] indepvars = [] # For each device, assume it is not connected and we should not log # data until the gui actually gets readings. # Loop through all parameters in the device for y in range (0, len(self.device.getFrame().getNicknames())): # If the name of the parameter has not been defined as None # in the constructor, then we want to log it. if(self.device.getFrame().getNicknames()[y] is not None): # The name of the parameter in the dataset is the same # name displayed on the GUI except without # non-alphanumerical characters. Use regular expressions # to do this. paramName = str(self.device.getFrame().getNicknames() [y]).replace(" ","") paramName = re.sub(r'\W+', '', paramName) # Create the tuple that defines the parameter. tup = (paramName, [1], "float64", str(self.device .getFrame().getUnits()[y])) # Add it to the array of dependent variables depvars.append(tup) # Get the datestamp from the datachest helper class. dStamp = dateStamp() # Time is the only independent variable indepvars.append(("time", [1], "utc_datetime", "s")) # The vars variable holds ALL variables vars = [] vars.extend(indepvars) vars.extend(depvars) # Construct the data set #print indepvars #print depvars self.dataSet.createDataset(title, indepvars, depvars) # The datawidth parameter says how many variables # (independent and dependent) make up the dataset. # DataWidth is used internally only. self.dataSet.addParameter("DataWidth", len(vars)) if(self.device.getFrame().getYLabel() is not None): # Configure the label of the y axis given in the device'same # constructor. self.dataSet.addParameter("Y Label", self.device .getFrame().getYLabel()) self.device.getFrame().setDataSet(self.dataSet)
def configureDataSets(self, **kwargs): """ Initialize the datalogger, if datasets already exist, use them. Otherwise create new ones. """ now = dt.datetime.now() # Force creation of new dataset? force_new = kwargs.get('force_new', False) self.hasData = True # Generate a title for the dataset. NOTE: if # the title of the device is changed in the device's constructor # in the main class, then a different data set will be created. # This is because datasets are stored using the name of # the device, which is what the program looks for when checking # if there are data files that already exist. title = str(self.device.getFrame().DataLoggingInfo()['name']).replace( " ", "_") # Datasets are stored in the folder 'DATA_CHEST_ROOT\year\month\' # Try to access the current month's folder, if it does not # exist, make it. location = self.device.getFrame().DataLoggingInfo()['location'] # print "Location1:", location # root = os.environ['DATA_CHEST_ROOT'] # relativePath = os.path.relpath(root, dir) # print "Configuring datalogging for", str(self.device)+" located at", # location if location != None: root = os.environ['DATA_CHEST_ROOT'] root = root.replace("/", "\\") relativePath = os.path.relpath(location, root) #print "relativePath:", relativePath #if relativePath == '.': # raise IOError( # "Cannot create dataset directly under DATA_CHEST_ROOT.") path = relativePath.split("\\") if force_new: try: print "Could not store in:", path[-1] folder_version = int(path[-1][path[-1].index('__') + 2::]) path[-1] = path[-1][:path[-1].index('__')] folder_version += 1 path[-1] += str('__' + str(folder_version)) except: traceback.print_exc() path[-1] += '__0' #print str(self.device)+":", "New data location forced:", path print "Path:", path self.dataSet = dataChest(str(path[0])) self.dataSet.cd('') # relativepath = os.path.relpath( # location, self.dataSet.pwd().replace("/", "\\")) # path = relativePath.split("\\") #print "path:", str(path) # dateFolderName = time.strftime('%x').replace(' ', '_') # dateFolderName = dateFolderName.replace('/', '_') folder_version = 0 #path[-1]+=str("__"+str(folder_version)) for folder in path[1::]: try: #print "folder:", folder self.dataSet.cd(folder) except: try: self.dataSet.mkdir(folder) self.dataSet.cd(folder) except: print "ERROR: Could not create dataset at:", path #folder_version += 1 #path[-1] = folder[0:folder.index('__')]+str("__"+str(folder_version)) traceback.print_exc() # print "Configuring datalogging for", str(self.device)+" located # at", location if location == None: folderName = time.strftime('%x').replace(' ', '_') folderName = folderName.replace('/', '_') self.dataSet = dataChest(folderName) # try: # self.dataSet.cd(folderName) # except: # self.dataSet.mkdir(folderName) # self.dataSet.cd(folderName) try: self.device.getFrame().DataLoggingInfo( )['location'] = os.path.abspath(self.dataSet.pwd()) except: traceback.print_exc() # Look at the names of all existing datasets and check # if the name contains the title of the current device. existingFiles = self.dataSet.ls() # foundit becomes true if a dataset file already exists. foundit = False # Go through all existing dataset files. for y in range(len(existingFiles[0])): # If the name of the file contains the (persistant) title # generated by the code, open that dataset and use it. if title in existingFiles[0][y]: self.dataSet.openDataset(existingFiles[0][y], modify=True) foundit = True # If the number of variables in the data set has changed since last time, # Then we do not want to use the old dataset. if len(self.dataSet.getVariables()[1]) != len( self.device.getFrame().getNicknames()): foundit = False else: # print("Existing data set found for %s: %s." # %(title, existingFiles[0][y])) pass # If the dataset does not already exist, we must create it. if not foundit: # print("Creating dataset for %s." %title) # Name of the parameter. This is the name of the parameter # displayed on the gui except without spaces or # non-alphanumerical characters. paramName = None # Arrays to hold any variables. depvars = [] indepvars = [] # For each device, assume it is not connected and we should # not log data until the GUI actually gets readings. # Loop through all parameters in the device. # print "Setting up datalogging for device", # self.device.getFrame().getTitle() nicknames = self.device.getFrame().getNicknames() # print "Nicknames:", self.device.getFrame().getNicknames() for y, name in enumerate(nicknames): # If the name of the parameter has not been defined as # None in the constructor, then we want to log it. if name is not None: # The name of the parameter in the dataset is # the same name displayed on the GUI except without # non-alphanumerical characters. Use regular # expressions to do this. paramName = str(name).replace(" ", "_") paramName = re.sub(r'\W+', '', paramName) # Create the tuple that defines the parameter. # print self.device, "device units: ", self.device.getFrame().getUnits() # print "nicknames:", nicknames #print self.device, "datatype:", self.dataType tup = (paramName, [1], self.dataType, str(self.device.getUnit(name))) # Add it to the array of dependent variables. depvars.append(tup) # Get the datestamp from the datachest helper class. dStamp = dateStamp() # Time is the only independent variable. indepvars.append(("time", [1], "utc_datetime", "s")) # The vars variable holds ALL variables. vars = [] vars.extend(indepvars) vars.extend(depvars) # Construct the data set self.dataSet.createDataset(title, indepvars, depvars) # The DataWidth parameter says how many variables # (independent and dependent) make up the dataset. # DataWidth is used internally only. self.dataSet.addParameter("DataWidth", len(vars)) # if self.device.getFrame().getYLabel() is not None: # Configure the label of the y axis given in the # device's constructor. self.device.getFrame().DataLoggingInfo( )['location'] = self.dataSet.pwd() self.device.getFrame().setDataSet(self.dataSet)