def refreshGuiTimeExtents(self, timeExtents): """Update time extents showing in labels and represented by horizontalTimeSlider :param timeExtents: a tuple of start and end datetimes """ self.setPropagateGuiChanges(False) if timeExtents[1] is not None: # timeExtents[0] is set in different places, so only check timeExtents[1] startText = time_util.datetime_to_str(timeExtents[0], time_util.DEFAULT_FORMAT) endText = time_util.datetime_to_str(timeExtents[1], time_util.DEFAULT_FORMAT) self.guiControl.dock.labelStartTime.setText(startText) self.guiControl.dock.labelEndTime.setText(endText) timeLength = time_util.datetime_to_epoch(timeExtents[1]) - time_util.datetime_to_epoch(timeExtents[0]) if timeLength > MAX_TIME_LENGTH_SECONDS_SLIDER: new_granularity = int(math.ceil(1.0 * timeLength / MAX_TIME_LENGTH_SECONDS_SLIDER)) self.setGranularitySeconds(new_granularity) # trick because timeLength must fit in an integer # since it interfaces with a C++ class newTimeLength = int(math.ceil(1.0 * timeLength / new_granularity)) timeLength = newTimeLength else: self.setGranularitySeconds(conf.DEFAULT_GRANULARITY_IN_SECONDS) self.guiControl.dock.horizontalTimeSlider.setMinimum(0) self.guiControl.dock.horizontalTimeSlider.setMaximum(timeLength) else: # set to default values self.setGranularitySeconds(conf.DEFAULT_GRANULARITY_IN_SECONDS) self.guiControl.dock.labelStartTime.setText('not set') self.guiControl.dock.labelEndTime.setText('not set') self.guiControl.dock.horizontalTimeSlider.setMinimum(conf.MIN_TIMESLIDER_DEFAULT) self.guiControl.dock.horizontalTimeSlider.setMaximum(conf.MAX_TIMESLIDER_DEFAULT) self.setPropagateGuiChanges(True)
def getMinMaxValues(self): """Return min and max value strings""" if self.minValue is None or self.maxValue is None: # if not already computed fmt = self.getTimeFormat() if self.getDateType() == time_util.DateTypes.IntegerTimestamps: self.minValue = self.getRawMinValue() self.maxValue = self.getRawMaxValue() else: # strings or qdate(time) values # need to find min max by looking at all the unique values # because QGIS doesn't get sorting right uniques = self.getUniques(self.fromTimeAttribute) def vals_to_dt(vals, fmt): res = [] for val in vals: try: dt = time_util.timeval_to_datetime(val, fmt) res.append(dt) # info("{} converted to {}".format(val, dt)) except Exception as e: error(traceback.format_exc(e)) warn( QCoreApplication.translate( 'TimeManager', "Unparseable value {0} in layer {1} ignored. Cause {2}" ).format(val, self.layer.name(), e)) return res unique_vals = vals_to_dt(uniques, fmt) if len(unique_vals) == 0: raise Exception( QCoreApplication.translate( 'TimeManager', "Could not parse any dates while trying to get time extents." "None of the values (for example {0}) matches the format {1}" ).format(uniques[-1], fmt)) minValue = time_util.datetime_to_str(min(unique_vals), fmt) if self.fromTimeAttribute == self.toTimeAttribute: maxValue = time_util.datetime_to_str(max(unique_vals), fmt) else: unique_vals = self.getUniques(self.toTimeAttribute) unique_vals = vals_to_dt(unique_vals, fmt) maxValue = time_util.datetime_to_str(max(unique_vals), fmt) if type(minValue) in [QDate, QDateTime]: minValue = time_util.datetime_to_str( time_util.QDateTime_to_datetime(minValue), fmt) maxValue = time_util.datetime_to_str( time_util.QDateTime_to_datetime(maxValue), fmt) self.minValue = minValue self.maxValue = maxValue return self.minValue, self.maxValue
def setTimeRestriction(self, timePosition, timeFrame): """Constructs the query, including the original subset""" if not self.timeEnabled: self.deleteTimeRestriction() return startTime = timePosition + timedelta(seconds=self.offset) endTime = timePosition + timeFrame + timedelta(seconds=self.offset) timeString = "TIME={}/{}".format( time_util.datetime_to_str(startTime, self.timeFormat), time_util.datetime_to_str(endTime, self.timeFormat)) dataUrl = self.IGNORE_PREFIX + self.originalUri + self.addUrlMark() + timeString #print "original URL: " + self.originalUri #print "final URL: " + dataUrl self.layer.dataProvider().setDataSourceUri(dataUrl) self.layer.dataProvider().reloadData()
def writeSettings(self): """Write all relevant settings to the project file XML """ if not self.getTimeLayerManager().isEnabled(): return (timeLayerManagerSettings, timeLayerList) = self.getTimeLayerManager().getSaveString() if timeLayerManagerSettings is not None: settings = {'animationFrameLength': self.animationFrameLength, 'playBackwards': self.playBackwards, 'loopAnimation': self.loopAnimation, 'timeLayerManager': timeLayerManagerSettings, 'timeLayerList': timeLayerList, 'currentMapTimePosition': time_util.datetime_to_str( self.getTimeLayerManager().getCurrentTimePosition(), time_util.DEFAULT_FORMAT ), 'timeFrameType': self.getTimeLayerManager().getTimeFrameType(), 'timeFrameSize': self.getTimeLayerManager().getTimeFrameSize(), 'active': self.getTimeLayerManager().isEnabled(), 'mode': int(time_util.is_archaelogical()), 'digits': time_util.getArchDigits(), 'labelFormat': self.guiControl.getLabelFormat(), 'labelFont': self.guiControl.getLabelFont(), 'labelSize': self.guiControl.getLabelSize(), 'labelColor': self.guiControl.getLabelColor(), 'labelBgColor': self.guiControl.getLabelBgColor(), 'labelPlacement': self.guiControl.getLabelPlacement()} TimeManagerProjectHandler.writeSettings(settings)
def setTimeRestriction(self, timePosition, timeFrame): """Constructs the query, including the original subset""" if not self.timeEnabled: self.deleteTimeRestriction() return startTime = timePosition + timedelta(seconds=self.offset) endTime = timePosition + timeFrame + timedelta(seconds=self.offset) timeString = "TIME={}/{}".format( time_util.datetime_to_str(startTime, self.timeFormat), time_util.datetime_to_str(endTime, self.timeFormat)) dataUrl = self.IGNORE_PREFIX + self.originalUri + self.addUrlMark( ) + timeString #print "original URL: " + self.originalUri #print "final URL: " + dataUrl self.layer.dataProvider().setDataSourceUri(dataUrl) self.layer.dataProvider().reloadData()
def getMinMaxValues(self): """Return min and max value strings""" if self.minValue is None or self.maxValue is None: # if not already computed fmt = self.getTimeFormat() if self.getDateType() == time_util.DateTypes.IntegerTimestamps: self.minValue = self.getRawMinValue() self.maxValue = self.getRawMaxValue() else: # strings or qdate(time) values # need to find min max by looking at all the unique values # because QGIS doesn't get sorting right uniques = self.getUniques(self.fromTimeAttribute) def vals_to_dt(vals, fmt): res = [] for val in vals: try: dt = time_util.timeval_to_datetime(val, fmt) res.append(dt) # info("{} converted to {}".format(val, dt)) except Exception as e: error(traceback.format_exc(e)) warn(QCoreApplication.translate('TimeManager', "Unparseable value {0} in layer {1} ignored. Cause {2}").format(val, self.layer.name(), e)) return res unique_vals = vals_to_dt(uniques, fmt) if len(unique_vals) == 0: raise Exception( QCoreApplication.translate( 'TimeManager', "Could not parse any dates while trying to get time extents." "None of the values (for example {0}) matches the format {1}" ).format(uniques[-1], fmt) ) minValue = time_util.datetime_to_str(min(unique_vals), fmt) if self.fromTimeAttribute == self.toTimeAttribute: maxValue = time_util.datetime_to_str(max(unique_vals), fmt) else: unique_vals = self.getUniques(self.toTimeAttribute) unique_vals = vals_to_dt(unique_vals, fmt) maxValue = time_util.datetime_to_str(max(unique_vals), fmt) if type(minValue) in [QDate, QDateTime]: minValue = time_util.datetime_to_str(time_util.QDateTime_to_datetime(minValue), fmt) maxValue = time_util.datetime_to_str(time_util.QDateTime_to_datetime(maxValue), fmt) self.minValue = minValue self.maxValue = maxValue return self.minValue, self.maxValue
def getSaveString(self): """create a save string that can be put into project file""" tdfmt = time_util.SAVE_STRING_FORMAT saveListLayers = [] try: # test if projectTimeExtens are populated with datetimes time_util.datetime_to_str(self.getProjectTimeExtents()[0], tdfmt) except Exception: return (None, None) saveString = conf.SAVE_DELIMITER.join( [time_util.datetime_to_str(self.getProjectTimeExtents()[0], tdfmt), time_util.datetime_to_str(self.getProjectTimeExtents()[1], tdfmt), time_util.datetime_to_str(self.getCurrentTimePosition(), tdfmt)]) for timeLayer in self.getTimeLayerList(): saveListLayers.append(timeLayer.getSaveString()) return (saveString, saveListLayers)
def refreshGuiTimeExtents(self, timeExtents): """Update time extents showing in labels and represented by horizontalTimeSlider :param timeExtents: a tuple of start and end datetimes """ self.setPropagateGuiChanges(False) if timeExtents[ 1] is not None: # timeExtents[0] is set in different places, so only check timeExtents[1] startText = time_util.datetime_to_str(timeExtents[0], time_util.DEFAULT_FORMAT) endText = time_util.datetime_to_str(timeExtents[1], time_util.DEFAULT_FORMAT) self.guiControl.dock.labelStartTime.setText(startText) self.guiControl.dock.labelEndTime.setText(endText) timeLength = time_util.datetime_to_epoch( timeExtents[1]) - time_util.datetime_to_epoch(timeExtents[0]) if timeLength > MAX_TIME_LENGTH_SECONDS_SLIDER: new_granularity = int( math.ceil(1.0 * timeLength / MAX_TIME_LENGTH_SECONDS_SLIDER)) self.setGranularitySeconds(new_granularity) # trick because timeLength must fit in an integer # since it interfaces with a C++ class newTimeLength = int( math.ceil(1.0 * timeLength / new_granularity)) timeLength = newTimeLength else: self.setGranularitySeconds(conf.DEFAULT_GRANULARITY_IN_SECONDS) self.guiControl.dock.horizontalTimeSlider.setMinimum(0) self.guiControl.dock.horizontalTimeSlider.setMaximum(timeLength) else: # set to default values self.setGranularitySeconds(conf.DEFAULT_GRANULARITY_IN_SECONDS) self.guiControl.dock.labelStartTime.setText('not set') self.guiControl.dock.labelEndTime.setText('not set') self.guiControl.dock.horizontalTimeSlider.setMinimum( conf.MIN_TIMESLIDER_DEFAULT) self.guiControl.dock.horizontalTimeSlider.setMaximum( conf.MAX_TIMESLIDER_DEFAULT) self.setPropagateGuiChanges(True)
def getLabel(self, dt): if self.type == "dt": return time_util.datetime_to_str(dt, self.fmt) if self.type == "epoch": return QCoreApplication.translate("TimeManagerGuiControl", "Seconds elapsed: {}").format((dt - datetime(1970, 1, 1, 0, 0)).total_seconds()) if self.type == "beginning": min_dt = self.model.getProjectTimeExtents()[0] return QCoreApplication.translate("TimeManagerGuiControl", "Seconds elapsed: {}").format((dt - min_dt).total_seconds()) else: raise Exception("Unsupported type {}".format(self.type))
def getSaveString(self): """create a save string that can be put into project file""" tdfmt = time_util.SAVE_STRING_FORMAT saveListLayers = [] try: # test if projectTimeExtens are populated with datetimes time_util.datetime_to_str(self.getProjectTimeExtents()[0], tdfmt) except Exception: return (None, None) saveString = conf.SAVE_DELIMITER.join([ time_util.datetime_to_str(self.getProjectTimeExtents()[0], tdfmt), time_util.datetime_to_str(self.getProjectTimeExtents()[1], tdfmt), time_util.datetime_to_str(self.getCurrentTimePosition(), tdfmt) ]) for timeLayer in self.getTimeLayerList(): saveListLayers.append(timeLayer.getSaveString()) return (saveString, saveListLayers)
def getLabel(self, dt): if self.type == "dt": return time_util.datetime_to_str(dt, self.fmt) if self.type == "epoch": return QCoreApplication.translate("TimeManagerGuiControl", "Seconds elapsed: {}").format((dt - datetime(1970, 1, 1, 0, 0)).total_seconds()) if self.type == "beginning": min_dt = self.model.getProjectTimeExtents()[0] return QCoreApplication.translate("TimeManagerGuiControl", "Seconds elapsed: {}").format((dt - min_dt).total_seconds()) else: raise Exception("Unsupported type {}".format(self.type))
def build_query(start_dt, end_dt, from_attr, to_attr, date_type, date_format, query_idiom, acc): """Build subset query""" if acc: # features never die start_dt = time_util.get_min_dt() comparison = "<" # simplified because of: https://github.com/anitagraser/TimeManager/issues/235 # (original: # comparison = "<" if to_attr == from_attr else "<=") if date_type == time_util.DateTypes.IntegerTimestamps: start_epoch = time_util.datetime_to_epoch(start_dt) end_epoch = time_util.datetime_to_epoch(end_dt) return INT_FORMAT.format(from_attr, comparison, end_epoch, to_attr, start_epoch) start_str = time_util.datetime_to_str(start_dt, date_format) end_str = time_util.datetime_to_str(end_dt, date_format) if date_type == time_util.DateTypes.DatesAsStringsArchaelogical: # kept <= option here since I'm not sure about implications in archaelogical mode comparison = "<" if to_attr == from_attr else "<=" return build_query_archaelogical(start_str, end_str, from_attr, to_attr, comparison, query_idiom) if can_compare_lexicographically(date_format): if query_idiom == QueryIdioms.OGR: return STRINGCAST_FORMAT.format(from_attr, comparison, end_str, to_attr, start_str) else: return STRING_FORMAT.format(from_attr, comparison, end_str, to_attr, start_str) else: # thankfully, SQL & OGR syntax agree on substr and concat if date_type != time_util.DateTypes.DatesAsStrings: raise QueryBuildingException() ioy = date_format.find("%Y") iom = date_format.find("%m") iod = date_format.find("%d") ioh = date_format.find("%H") sub1 = create_ymd_substring(ioy, iom, iod, ioh, from_attr, quote_type='"') # quote type for column names sub2 = create_ymd_substring(ioy, iom, iod, ioh, end_str, quote_type='\'') # quote type for values sub3 = create_ymd_substring(ioy, iom, iod, ioh, to_attr, quote_type='"') sub4 = create_ymd_substring(ioy, iom, iod, ioh, start_str, quote_type='\'') query = "CONCAT({}) {} CONCAT({}) AND CONCAT({})>=CONCAT({})".format(sub1, comparison, sub2, sub3, sub4) return query
def writeSettings(self): """Write all relevant settings to the project file XML """ if not self.getTimeLayerManager().isEnabled(): return (timeLayerManagerSettings, timeLayerList) = self.getTimeLayerManager().getSaveString() if timeLayerManagerSettings is not None: settings = { 'animationFrameLength': self.animationFrameLength, 'playBackwards': self.playBackwards, 'loopAnimation': self.loopAnimation, 'timeLayerManager': timeLayerManagerSettings, 'timeLayerList': timeLayerList, 'currentMapTimePosition': time_util.datetime_to_str( self.getTimeLayerManager().getCurrentTimePosition(), time_util.DEFAULT_FORMAT), 'timeFrameType': self.getTimeLayerManager().getTimeFrameType(), 'timeFrameSize': self.getTimeLayerManager().getTimeFrameSize(), 'active': self.getTimeLayerManager().isEnabled(), 'mode': int(time_util.is_archaelogical()), 'digits': time_util.getArchDigits(), 'labelFormat': self.guiControl.getLabelFormat(), 'labelFont': self.guiControl.getLabelFont(), 'labelSize': self.guiControl.getLabelSize(), 'labelColor': self.guiControl.getLabelColor(), 'labelBgColor': self.guiControl.getLabelBgColor(), 'labelPlacement': self.guiControl.getLabelPlacement() } TimeManagerProjectHandler.writeSettings(settings)
def animation_end_datetime(values, feature, parent): """Last time stamp""" return time_util.datetime_to_str(control.getTimeLayerManager().getProjectTimeExtents()[1], time_util.DEFAULT_FORMAT)
def animation_datetime(values, feature, parent): """Current animation time""" return time_util.datetime_to_str(control.getTimeLayerManager().getCurrentTimePosition(), time_util.DEFAULT_FORMAT)
def build_query(start_dt, end_dt, from_attr, to_attr, date_type, date_format, query_idiom, acc): """Build subset query""" if acc: # features never die start_dt = time_util.get_min_dt() comparison = "<" # simplified because of: https://github.com/anitagraser/TimeManager/issues/235 # (original: # comparison = "<" if to_attr == from_attr else "<=") if date_type == time_util.DateTypes.IntegerTimestamps: start_epoch = time_util.datetime_to_epoch(start_dt) end_epoch = time_util.datetime_to_epoch(end_dt) return INT_FORMAT.format(from_attr, comparison, end_epoch, to_attr, start_epoch) start_str = time_util.datetime_to_str(start_dt, date_format) end_str = time_util.datetime_to_str(end_dt, date_format) if date_type == time_util.DateTypes.DatesAsStringsArchaelogical: # kept <= option here since I'm not sure about implications in archaelogical mode comparison = "<" if to_attr == from_attr else "<=" return build_query_archaelogical(start_str, end_str, from_attr, to_attr, comparison, query_idiom) if can_compare_lexicographically(date_format): if query_idiom == QueryIdioms.OGR: return STRINGCAST_FORMAT.format(from_attr, comparison, end_str, to_attr, start_str) else: return STRING_FORMAT.format(from_attr, comparison, end_str, to_attr, start_str) else: # thankfully, SQL & OGR syntax agree on substr and concat if date_type != time_util.DateTypes.DatesAsStrings: raise QueryBuildingException() ioy = date_format.find("%Y") iom = date_format.find("%m") iod = date_format.find("%d") ioh = date_format.find("%H") sub1 = create_ymd_substring( ioy, iom, iod, ioh, from_attr, quote_type='"') # quote type for column names sub2 = create_ymd_substring(ioy, iom, iod, ioh, end_str, quote_type='\'') # quote type for values sub3 = create_ymd_substring(ioy, iom, iod, ioh, to_attr, quote_type='"') sub4 = create_ymd_substring(ioy, iom, iod, ioh, start_str, quote_type='\'') query = "CONCAT({}) {} CONCAT({}) AND CONCAT({})>=CONCAT({})".format( sub1, comparison, sub2, sub3, sub4) return query
def animation_end_datetime(values, feature, parent): """Last time stamp""" return time_util.datetime_to_str( control.getTimeLayerManager().getProjectTimeExtents()[1], time_util.DEFAULT_FORMAT)
def animation_datetime(values, feature, parent): """Current animation time""" return time_util.datetime_to_str( control.getTimeLayerManager().getCurrentTimePosition(), time_util.DEFAULT_FORMAT)