def getMinMaxValues(self): """Returns str""" if self.minValue is None or self.maxValue is None: # if not already computed fmt = self.getTimeFormat() if self.getDateType() == DateTypes.IntegerTimestamps: self.minValue = self.getRawMinValue() self.maxValue = self.getRawMaxValue() else: # need to find min max by looking at all the unique values # QGIS doesn't get sorting right uniques = self.getUniques(self.fromTimeAttribute) # those can be either strings or qdate(time) values def vals_to_dt(vals, fmt): res = [] for val in vals: try: dt = timeval_to_datetime(val, fmt) res.append(dt) # info("{} converted to {}".format(val, dt)) except Exception, e: warn( "Unparseable value {} in layer {} ignored. Cause {}" .format(val, self.layer.name(), e)) pass return res unique_vals = vals_to_dt(uniques, fmt) if len(unique_vals) == 0: raise Exception( "Could not parse any dates while trying to get time extents." + "None of the values (for example {}) matches the format {}" .format(uniques[-1], fmt)) minValue = datetime_to_str(min(unique_vals), fmt) if self.fromTimeAttribute == self.toTimeAttribute: maxValue = datetime_to_str(max(unique_vals), fmt) else: unique_vals = self.getUniques(self.toTimeAttribute) unique_vals = vals_to_dt(unique_vals, fmt) maxValue = datetime_to_str(max(unique_vals), fmt) if type(minValue) in [QtCore.QDate, QtCore.QDateTime]: minValue = datetime_to_str(QDateTime_to_datetime(minValue), self.getTimeFormat()) maxValue = datetime_to_str(QDateTime_to_datetime(maxValue), self.getTimeFormat()) self.minValue = minValue self.maxValue = maxValue
def renderLabel(self, painter): """render the current timestamp on the map canvas""" if not self.showLabel: return labelString = datetime_to_str(QDateTime_to_datetime(self.dock.dateTimeEditCurrentTime.dateTime()),\ self.labelOptions.fmt) # Determine placement of label given cardinal directions flags = 0 for direction, flag in ('N', Qt.AlignTop), ('S', Qt.AlignBottom), ( 'E', Qt.AlignRight), ('W', Qt.AlignLeft): if direction in self.labelOptions.placement: flags |= flag # Get canvas dimensions width = painter.device().width() height = painter.device().height() painter.setRenderHint(painter.Antialiasing, True) txt = QTextDocument() html = '<span style="background-color:%s; padding: 5px;"><font face="%s" size="%s" color="%s">%s</font></span>' % \ (self.labelOptions.bgcolor, self.labelOptions.font, self.labelOptions.size, self.labelOptions.color, labelString) txt.setHtml(html) layout = txt.documentLayout() size = layout.documentSize() x = width - 5 - size.width() if flags & Qt.AlignRight else 5 y = height - 5 - size.height() if flags & Qt.AlignBottom else 5 painter.translate(x, y) layout.draw(painter, QAbstractTextDocumentLayout.PaintContext()) painter.translate(-x, -y) # translate back
def renderLabel(self, painter): """render the current timestamp on the map canvas""" if not self.showLabel or not self.model.hasLayers(): return dt = self.model.getCurrentTimePosition() if dt is None: dt = self.getTimeValueFromUI() labelString = datetime_to_str(dt, self.labelOptions.fmt) # Determine placement of label given cardinal directions flags = 0 for direction, flag in ('N', Qt.AlignTop), ('S', Qt.AlignBottom), ('E', Qt.AlignRight), ('W', Qt.AlignLeft): if direction in self.labelOptions.placement: flags |= flag # Get canvas dimensions width = painter.device().width() height = painter.device().height() painter.setRenderHint(painter.Antialiasing, True) txt = QTextDocument() html = '<span style="background-color:%s; padding: 5px;"><font face="%s" size="%s" color="%s">%s</font></span>' % \ (self.labelOptions.bgcolor, self.labelOptions.font, self.labelOptions.size, self.labelOptions.color, labelString) txt.setHtml(html) layout = txt.documentLayout() size = layout.documentSize() x = width - 5 - size.width() if flags & Qt.AlignRight else 5 y = height - 5 - size.height() if flags & Qt.AlignBottom else 5 painter.translate(x, y) layout.draw(painter, QAbstractTextDocumentLayout.PaintContext()) painter.translate(-x, -y) # translate back
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 = "<" if to_attr == from_attr else "<=" if date_type == 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 == DateTypes.DatesAsStringsArchaelogical: 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 != 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 getMinMaxValues(self): """Returns str""" if self.minValue is None or self.maxValue is None: # if not already computed fmt = self.getTimeFormat() if self.getDateType() == DateTypes.IntegerTimestamps: self.minValue = self.getRawMinValue() self.maxValue = self.getRawMaxValue() else: # need to find min max by looking at all the unique values # QGIS doesn't get sorting right uniques = self.getUniques(self.fromTimeAttribute) # those can be either strings or qdate(time) values def vals_to_dt(vals, fmt): res = [] for val in vals: try: dt = timeval_to_datetime(val, fmt) res.append(dt) # info("{} converted to {}".format(val, dt)) except Exception, e: warn("Unparseable value {} in layer {} ignored. Cause {}".format(val, self.layer.name(), e)) pass return res unique_vals = vals_to_dt(uniques, fmt) if len(unique_vals) == 0: raise Exception("Could not parse any dates while trying to get time extents." + "None of the values (for example {}) matches the format {}" .format(uniques[-1], fmt)) minValue = datetime_to_str(min(unique_vals), fmt) if self.fromTimeAttribute == self.toTimeAttribute: maxValue = datetime_to_str(max(unique_vals), fmt) else: unique_vals = self.getUniques(self.toTimeAttribute) unique_vals = vals_to_dt(unique_vals, fmt) maxValue = datetime_to_str(max(unique_vals), fmt) if type(minValue) in [QtCore.QDate, QtCore.QDateTime]: minValue = datetime_to_str(QDateTime_to_datetime(minValue), self.getTimeFormat()) maxValue = datetime_to_str(QDateTime_to_datetime(maxValue), self.getTimeFormat()) self.minValue = minValue self.maxValue = maxValue
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 datetime_to_str(dt, self.fmt) if self.type=="epoch": return "Seconds elapsed: {}".format((dt - datetime(1970,1,1,0,0)).total_seconds()) if self.type=="beginning": min_dt = self.model.getProjectTimeExtents()[0] return "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: 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 "Seconds elapsed: {}".format((dt - datetime(1970,1,1,0,0)).total_seconds()) if self.type=="beginning": min_dt = self.model.getProjectTimeExtents()[0] return "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 build_query(start_dt, end_dt, from_attr, to_attr, date_type, date_format, query_idiom): """Build subset query""" comparison = "<" if to_attr == from_attr else "<=" if date_type == 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 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 != DateTypes.DatesAsStrings: raise QueryBuildingException() ioy = date_format.find("%Y") iom = date_format.find("%m") iod = date_format.find("%d") sub1 = create_ymd_substring(ioy, iom, iod, from_attr, quote_type='"') sub2 = create_ymd_substring(ioy, iom, iod, end_str, quote_type='\'') sub3 = create_ymd_substring(ioy, iom, iod, to_attr, quote_type='"') sub4 = create_ymd_substring(ioy, iom, iod, start_str, quote_type='\'') return "CONCAT({}) {} CONCAT({}) AND CONCAT({})>=CONCAT({})".format( sub1, comparison, sub2, sub3, sub4)
def getMinMaxValues(self): """Returns str""" if self.minValue is None or self.maxValue is None: # if not already computed provider = self.layer.dataProvider() fmt = self.getTimeFormat() fromTimeAttributeIndex = provider.fieldNameIndex( self.fromTimeAttribute) toTimeAttributeIndex = provider.fieldNameIndex( self.toTimeAttribute) if query_builder.can_compare_lexicographically(fmt): minValue = provider.minimumValue(fromTimeAttributeIndex) maxValue = provider.maximumValue(toTimeAttributeIndex) else: # need to find min max by looking at all the unique values # QGIS doesn't get sorting right unique_vals = provider.uniqueValues(fromTimeAttributeIndex) unique_vals = map(lambda x: str_to_datetime(x, fmt), unique_vals) minValue = datetime_to_str(min(unique_vals), fmt) if fromTimeAttributeIndex == toTimeAttributeIndex: maxValue = datetime_to_str(max(unique_vals), fmt) else: unique_vals = provider.uniqueValues(toTimeAttributeIndex) unique_vals = map(lambda x: str_to_datetime(x, fmt), unique_vals) maxValue = datetime_to_str(max(unique_vals), fmt) if type(minValue) in [QtCore.QDate, QtCore.QDateTime]: minValue = datetime_to_str(QDateTime_to_datetime(minValue), self.getTimeFormat()) maxValue = datetime_to_str(QDateTime_to_datetime(maxValue), self.getTimeFormat()) self.minValue = minValue self.maxValue = maxValue return self.minValue, self.maxValue
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_datetime(values, feature, parent): """called by QGIS to determine the current animation time""" return time_util.datetime_to_str(control.getTimeLayerManager().getCurrentTimePosition(), time_util.DEFAULT_FORMAT)
def epoch_to_str(seconds_from_epoch): return time_util.datetime_to_str( time_util.epoch_to_datetime(seconds_from_epoch))
def animation_datetime(values, feature, parent): """called by QGIS to determine the current animation time""" return time_util.datetime_to_str( control.getTimeLayerManager().getCurrentTimePosition(), time_util.DEFAULT_FORMAT)
def animation_end_datetime(values, feature, parent): """Last time stamp""" return time_util.datetime_to_str( control.getTimeLayerManager().getProjectTimeExtents()[1], time_util.DEFAULT_FORMAT)