Ejemplo n.º 1
0
 def new_value(value):
     if self.custom_step_size:
         step_amount = self.STEP_SIZES[self.step_size]
         time = fromtimestamp(self.slider.scale(value))
         newTime = add_time(time, step_amount, -1 if backward else 1)
         return self.slider.unscale(timestamp(newTime))
     return value + (-delta if backward else delta)
Ejemplo n.º 2
0
    def unscale(self, value):
        # Unscale e.g. absolute time to slider value
        dt_val = fromtimestamp(round(value))
        delta = self.__time_delta
        if isinstance(delta, Number):
            diff = dt_val - self.__scale_minimum
            return round(diff / datetime.timedelta(milliseconds=1000 * delta))
        elif delta:
            if delta[1] == 'month':
                return self.minimum() + delta[0] \
                       * ((dt_val.year - self.__scale_minimum.year) * 12
                          + max(dt_val.month - self.__scale_minimum.month,
                                0))
            else:  # elif delta[1] == 'year':
                return self.minimum() + delta[0] \
                       * (dt_val.year - self.__scale_minimum.year)

        return self.minimum() + (
            (dt_val - self.__scale_minimum) *
            (self.maximum() - self.minimum()) /
            (self.__scale_maximum - self.__scale_minimum) + self.minimum())
Ejemplo n.º 3
0
    def setSeries(self, timeseries, attr, xdim, ydim, fagg):
        if timeseries is None or not attr:
            self.clear()
            return
        if isinstance(xdim, str) and xdim.isdigit():
            xdim = [str(i) for i in range(1, int(xdim) + 1)]
        if isinstance(ydim, str) and ydim.isdigit():
            ydim = [str(i) for i in range(1, int(ydim) + 1)]

        if isinstance(xdim, DiscreteVariable):
            xcol = timeseries.get_column_view(xdim)[0]
            xvals, xfunc = xdim.values, lambda i, _: xdim.repr_val(xcol[i])
        else:
            xvals, xfunc = xdim.value
        if isinstance(ydim, DiscreteVariable):
            ycol = timeseries.get_column_view(ydim)[0]
            yvals, yfunc = ydim.values, lambda i, _: ydim.repr_val(ycol[i])
        else:
            yvals, yfunc = ydim.value

        attr = attr[0]
        values = timeseries.get_column_view(attr)[0]
        time_values = [
            fromtimestamp(i, tz=timeseries.time_variable.timezone)
            for i in timeseries.time_values
        ]

        if not yvals:
            yvals = sorted(
                set(
                    yfunc(i, v) for i, v in enumerate(time_values)
                    if v is not None))
        if not xvals:
            xvals = sorted(
                set(
                    xfunc(i, v) for i, v in enumerate(time_values)
                    if v is not None))

        indices = defaultdict(list)
        for i, tval in enumerate(time_values):
            if tval is not None:
                indices[(xfunc(i, tval), yfunc(i, tval))].append(i)

        if self._owwidget.invert_date_order:
            yvals = yvals[::-1]

        series = []
        aggvals = []
        self.indices = []
        xname = self.AxesCategories.name_it(xdim)
        yname = self.AxesCategories.name_it(ydim)
        for yval in yvals:
            data = []
            series.append(dict(name=yname(yval), data=data))
            self.indices.append([])
            for xval in xvals:
                inds = indices.get((xval, yval), ())
                self.indices[-1].append(inds)
                point = dict(y=1)
                data.append(point)
                if inds:
                    try:
                        aggval = np.round(fagg(values[inds]), 4)
                    except ValueError:
                        aggval = np.nan
                else:
                    aggval = np.nan
                if isinstance(aggval, Number) and np.isnan(aggval):
                    aggval = 'N/A'
                    point['select'] = ''
                    point['color'] = 'white'
                else:
                    aggvals.append(aggval)
                point['n'] = aggval

        # TODO: allow scaling over just rows or cols instead of all values as currently
        try:
            maxval, minval = np.max(aggvals), np.min(aggvals)
        except ValueError:
            self.clear()
            return
        ptpval = maxval - minval
        color = GradientPaletteGenerator('#ffcccc', '#cc0000')
        selected_color = GradientPaletteGenerator('#cdd1ff', '#0715cd')
        for serie in series:
            for point in serie['data']:
                n = point['n']
                if isinstance(n, Number):
                    val = (n - minval) / ptpval

                    if attr.is_discrete:
                        point['n'] = attr.repr_val(n)
                    elif isinstance(attr, TimeVariable):
                        point['n'] = attr.repr_val(n)

                    if attr.is_discrete:
                        point['color'] = color = color_to_hex(
                            attr.colors[int(n)])
                        sel_color = QColor(color).darker(150).name()
                    else:
                        point['color'] = color[val]
                        sel_color = selected_color[val]
                    point['states'] = dict(
                        select=dict(borderColor="black", color=sel_color))

        # TODO: make a white hole in the middle. Center w/o data.
        self.chart(series=series,
                   xAxis_categories=[xname(i) for i in xvals],
                   yAxis_categories=[yname(i) for i in reversed(yvals)],
                   javascript_after='''
                       // Force zoomType which is by default disabled for polar charts
                       chart.options.chart.zoomType = 'xy';
                       chart.pointer.init(chart, chart.options);
                   ''')
Ejemplo n.º 4
0
 def time_key(i):
     return timestamp(
         aggreagate_time(
             fromtimestamp(data.time_values[i],
                           tz=data.time_variable.timezone)))
Ejemplo n.º 5
0
    def setSeries(self, timeseries, attr, xdim, ydim, fagg):
        if timeseries is None or not attr:
            self.clear()
            return
        if isinstance(xdim, str) and xdim.isdigit():
            xdim = [str(i) for i in range(1, int(xdim) + 1)]
        if isinstance(ydim, str) and ydim.isdigit():
            ydim = [str(i) for i in range(1, int(ydim) + 1)]

        if isinstance(xdim, DiscreteVariable):
            xcol = timeseries.get_column_view(xdim)[0]
            xvals, xfunc = xdim.values, lambda i, _: xdim.repr_val(xcol[i])
        else:
            xvals, xfunc = xdim.value
        if isinstance(ydim, DiscreteVariable):
            ycol = timeseries.get_column_view(ydim)[0]
            yvals, yfunc = ydim.values, lambda i, _: ydim.repr_val(ycol[i])
        else:
            yvals, yfunc = ydim.value

        attr = attr[0]
        values = timeseries.get_column_view(attr)[0]
        time_values = [fromtimestamp(i) for i in timeseries.time_values]

        if not yvals:
            yvals = sorted(set(yfunc(i, v) for i, v in enumerate(time_values) if v is not None))
        if not xvals:
            xvals = sorted(set(xfunc(i, v) for i, v in enumerate(time_values) if v is not None))

        indices = defaultdict(list)
        for i, tval in enumerate(time_values):
            if tval is not None:
                indices[(xfunc(i, tval), yfunc(i, tval))].append(i)

        if self._owwidget.invert_date_order:
            yvals = yvals[::-1]

        series = []
        aggvals = []
        self.indices = []
        xname = self.AxesCategories.name_it(xdim)
        yname = self.AxesCategories.name_it(ydim)
        for yval in yvals:
            data = []
            series.append(dict(name=yname(yval), data=data))
            self.indices.append([])
            for xval in xvals:
                inds = indices.get((xval, yval), ())
                self.indices[-1].append(inds)
                point = dict(y=1)
                data.append(point)
                if inds:
                    try:
                        aggval = np.round(fagg(values[inds]), 4)
                    except ValueError:
                        aggval = np.nan
                else:
                    aggval = np.nan
                if isinstance(aggval, Number) and np.isnan(aggval):
                    aggval = 'N/A'
                    point['select'] = ''
                    point['color'] = 'white'
                else:
                    aggvals.append(aggval)
                point['n'] = aggval

        # TODO: allow scaling over just rows or cols instead of all values as currently
        try:
            maxval, minval = np.max(aggvals), np.min(aggvals)
        except ValueError:
            self.clear()
            return
        ptpval = maxval - minval
        color = GradientPaletteGenerator('#ffcccc', '#cc0000')
        selected_color = GradientPaletteGenerator('#cdd1ff', '#0715cd')
        for serie in series:
            for point in serie['data']:
                n = point['n']
                if isinstance(n, Number):
                    val = (n - minval) / ptpval

                    if attr.is_discrete:
                        point['n'] = attr.repr_val(n)
                    elif isinstance(attr, TimeVariable):
                        point['n'] = attr.repr_val(n)

                    if attr.is_discrete:
                        point['color'] = color = color_to_hex(attr.colors[int(n)])
                        sel_color = QColor(color).darker(150).name()
                    else:
                        point['color'] = color[val]
                        sel_color = selected_color[val]
                    point['states'] = dict(select=dict(borderColor="black",
                                                       color=sel_color))

        # TODO: make a white hole in the middle. Center w/o data.
        self.chart(series=series,
                   xAxis_categories=[xname(i) for i in xvals],
                   yAxis_categories=[yname(i) for i in reversed(yvals)],
                   javascript_after='''
                       // Force zoomType which is by default disabled for polar charts
                       chart.options.chart.zoomType = 'xy';
                       chart.pointer.init(chart, chart.options);
                   ''')
Ejemplo n.º 6
0
    def set_data(self, data):
        slider = self.slider
        self.data = data = None if data is None else Timeseries.from_data_table(
            data)

        def disabled():
            slider.setFormatter(str)
            slider.setHistogram(None)
            slider.setScale(0, 0, None)
            slider.setValues(0, 0)
            self._set_disabled(True)
            self.Outputs.subset.send(None)

        if data is None:
            disabled()
            return

        if not isinstance(data.time_variable, TimeVariable):
            self.Error.no_time_variable()
            disabled()
            return
        if not data.time_delta.deltas:
            self.Error.no_time_delta()
            disabled()
            return
        self.Error.clear()
        var = data.time_variable

        time_values = data.time_values

        min_dt = fromtimestamp(round(time_values.min()))
        max_dt = fromtimestamp(round(time_values.max()))

        # Depending on time delta:
        #   - set slider maximum (granularity)
        #   - set range for end dt (+ 1 timedelta)
        #   - set date format
        #   - set time overlap options
        delta = data.time_delta.gcd
        range = max_dt - min_dt
        if isinstance(delta, Number):
            maximum = round(range.total_seconds() / delta)

            timedelta = datetime.timedelta(milliseconds=delta * 1000)
            min_dt2 = min_dt + timedelta
            max_dt2 = max_dt + timedelta

            if delta >= 86400:  # more than a day
                date_format = ''.join(self.DATE_FORMATS[0:3])
            else:
                date_format = ''.join(self.DATE_FORMATS)

            for k, n in [(k, n) for k, n in self.STEP_SIZES.items()
                         if isinstance(n, Number)]:
                if delta <= n:
                    min_overlap = k
                    break
            else:
                min_overlap = '1 day'
        else:  # isinstance(delta, tuple)
            if delta[1] == 'month':
                months = (max_dt.year - min_dt.year) * 12 + \
                         (max_dt.month - min_dt.month)
                maximum = months / delta[0]

                if min_dt.month < 12 - delta[0]:
                    min_dt2 = min_dt.replace(month=min_dt.month + delta[0])
                else:
                    min_dt2 = min_dt.replace(year=min_dt.year + 1,
                                             month=12 - min_dt.month +
                                             delta[0])
                if max_dt.month < 12 - delta[0]:
                    max_dt2 = max_dt.replace(month=max_dt.month + delta[0])
                else:
                    max_dt2 = max_dt.replace(year=max_dt.year + 1,
                                             month=12 - min_dt.month +
                                             delta[0])

                date_format = ''.join(self.DATE_FORMATS[0:2])

                for k, (i, u) in [(k, v) for k, v in self.STEP_SIZES.items()
                                  if isinstance(v, tuple) and v[1] == 'month']:
                    if delta[0] <= i:
                        min_overlap = k
                        break
                else:
                    min_overlap = '1 year'
            else:  # elif delta[1] == 'year':
                years = max_dt.year - min_dt.year
                maximum = years / delta[0]

                min_dt2 = min_dt.replace(year=min_dt.year + delta[0], )
                max_dt2 = max_dt.replace(year=max_dt.year + delta[0], )

                date_format = self.DATE_FORMATS[0]

                for k, (i, u) in [(k, v) for k, v in self.STEP_SIZES.items()
                                  if isinstance(v, tuple) and v[1] == 'year']:
                    if delta[0] <= i:
                        min_overlap = k
                        break
                else:
                    raise Exception('Timedelta larger than 100 years')

        # find max sensible time overlap
        upper_overlap_limit = range / 2
        for k, overlap in self.STEP_SIZES.items():
            if isinstance(overlap, Number):
                if upper_overlap_limit.total_seconds() <= overlap:
                    max_overlap = k
                    break
            else:
                i, u = overlap
                if u == 'month':
                    month_diff = (max_dt.year - min_dt.year) * 12 \
                                 + max(0, max_dt.month - min_dt.month)
                    if month_diff / 2 <= i:
                        max_overlap = k
                        break
                else:  # if u == 'year':
                    year_diff = max_dt.year - min_dt.year
                    if year_diff / 2 <= i:
                        max_overlap = k
                        break
        else:
            # last item in step sizes
            *_, max_overlap = self.STEP_SIZES.keys()

        self.stepsize_combobox.clear()
        dict_iter = iter(self.STEP_SIZES.keys())
        next_item = next(dict_iter)
        while next_item != min_overlap:
            next_item = next(dict_iter)
        self.stepsize_combobox.addItem(next_item)
        self.step_size = next_item
        while next_item != max_overlap:
            next_item = next(dict_iter)
            self.stepsize_combobox.addItem(next_item)

        slider.setMinimum(0)
        slider.setMaximum(int(maximum + 1))

        self._set_disabled(False)
        slider.setHistogram(time_values)
        slider.setFormatter(var.repr_val)
        slider.setScale(time_values.min(), time_values.max(),
                        data.time_delta.gcd)
        self.sliderValuesChanged(slider.minimumValue(), slider.maximumValue())

        def utc_dt(dt):
            qdt = QDateTime(dt)
            qdt.setTimeZone(QTimeZone.utc())
            return qdt

        self.date_from.setDateTimeRange(utc_dt(min_dt), utc_dt(max_dt))
        self.date_to.setDateTimeRange(utc_dt(min_dt2), utc_dt(max_dt2))
        self.date_from.setDisplayFormat(date_format)
        self.date_to.setDisplayFormat(date_format)

        def format_time(i):
            dt = QDateTime.fromMSecsSinceEpoch(i * 1000).toUTC()
            return dt.toString(date_format)

        self.slider.setFormatter(format_time)
Ejemplo n.º 7
0
 def setScale(self, minimum, maximum, time_delta):
     self.__scale_minimum = fromtimestamp(round(minimum))
     self.__scale_maximum = fromtimestamp(round(maximum))
     self.__time_delta = time_delta
Ejemplo n.º 8
0
 def time_key(i):
     return timestamp(aggreagate_time(fromtimestamp(data.time_values[i])))