Example #1
0
def test_Quadratic():
    glyph = Quadratic()
    assert glyph.x0 == "x0"
    assert glyph.y0 == "y0"
    assert glyph.x1 == "x1"
    assert glyph.y1 == "y1"
    assert glyph.cx == "cx"
    assert glyph.cy == "cy"
    yield check_line, glyph
    yield check_props, glyph, ["x0", "y0", "x1", "y1", "cx", "cy"], LINE
Example #2
0
def test_Quadratic() -> None:
    glyph = Quadratic()
    assert glyph.x0 == field("x0")
    assert glyph.y0 == field("y0")
    assert glyph.x1 == field("x1")
    assert glyph.y1 == field("y1")
    assert glyph.cx == field("cx")
    assert glyph.cy == field("cy")
    check_line_properties(glyph)
    check_properties_existence(glyph, [
        "x0",
        "y0",
        "x1",
        "y1",
        "cx",
        "cy",
    ], LINE, GLYPH)
Example #3
0
def test_Quadratic():
    glyph = Quadratic()
    assert glyph.x0 is None
    assert glyph.y0 is None
    assert glyph.x1 is None
    assert glyph.y1 is None
    assert glyph.cx is None
    assert glyph.cy is None
    check_line_properties(glyph)
    check_properties_existence(glyph, [
        "x0",
        "y0",
        "x1",
        "y1",
        "cx",
        "cy",
    ], LINE, GLYPH)
Example #4
0
def test_Quadratic():
    glyph = Quadratic()
    assert glyph.x0 is None
    assert glyph.y0 is None
    assert glyph.x1 is None
    assert glyph.y1 is None
    assert glyph.cx is None
    assert glyph.cy is None
    yield check_line, glyph
    yield (check_props, glyph, [
        "x0",
        "y0",
        "x1",
        "y1",
        "cx",
        "cy",
    ], LINE)
Example #5
0
ydr = DataRange1d()

plot = Plot(title=None,
            x_range=xdr,
            y_range=ydr,
            plot_width=300,
            plot_height=300,
            h_symmetry=False,
            v_symmetry=False,
            min_border=0,
            toolbar_location=None)

glyph = Quadratic(x0="x",
                  y0="y",
                  x1="xp02",
                  y1="y",
                  cx="xp01",
                  cy="yp01",
                  line_color="#4DAF4A",
                  line_width=3)
plot.add_glyph(source, glyph)

xaxis = LinearAxis()
plot.add_layout(xaxis, 'below')

yaxis = LinearAxis()
plot.add_layout(yaxis, 'left')

plot.add_layout(Grid(dimension=0, ticker=xaxis.ticker))
plot.add_layout(Grid(dimension=1, ticker=yaxis.ticker))

doc = Document()
Example #6
0
    def draw(self):
        from bokeh.plotting import figure
        if self._data['time_set'].instantaneous:
            min_time = min(self._data['time_set'])
            max_time = max(self._data['time_set'])
        else:
            min_time = min(k[0] for k in self._data['time_set'])
            max_time = max(k[1] for k in self._data['time_set'])

        # get nodes
        nodes = sorted([str(n) for n in self._data['node_set']])
        # map them to numbers
        ln = dict(enumerate(nodes))
        nl = {n: i for i, n in enumerate(nodes)}
        pallete = self._make_pallete(len(self._data['temporal_linkset']))

        # width height
        w, h = (max_time - min_time) * 70, len(nodes) * 50
        division = (1 if self._data['temporal_nodeset'].discrete else 0.1)
        division = self.map_time(min_time + division) - self.map_time(min_time)
        min_time, max_time = self.map_time(min_time), self.map_time(max_time)

        # plot nodes
        node_points, time_points = [], []
        if self._data['temporal_nodeset'].instantaneous:
            for (u, ts) in self._data['temporal_nodeset']:
                ts = self.map_time(ts)
                if ts >= min_time and ts <= max_time:
                    # add circular points
                    node_points.append(nl[str(u)])
                    time_points.append(ts)
        else:
            for k in self._data['temporal_nodeset']:
                for ts in np.arange(max(self.map_time(k[1]), min_time),
                                    min(self.map_time(k[2]), max_time),
                                    division):
                    node_points.append(nl[str(k[0])])
                    time_points.append(ts)

        # plot links
        height = 0.5
        data, nan, l, b = self._data['temporal_linkset'], float('nan'), [], []
        if len(data):
            for ls, color in zip(data, pallete):
                lp_x, lp_y = [], []
                x0, y0, x1, y1, cx, cy = [], [], [], [], [], []
                if ls.instantaneous:
                    for (u, v, ts) in ls:
                        u, v = str(u), str(v)
                        ts = self.map_time(ts)
                        yu, yv = sorted((nl[u], nl[v]))
                        cr = curving(yu, yv) * division * 0.7
                        xm = ts + cr
                        ym = (yu + yv) * height
                        if cr > 0.:
                            x0.append(ts)
                            x1.append(ts)
                            y0.append(yu)
                            y1.append(yv)
                            cx.append(xm)
                            cy.append(ym)
                        else:
                            lp_x += [ts, ts, nan]
                            lp_y += [yu, yv, nan]

                else:
                    for k in ls:
                        u, v = str(k[0]), str(k[1])
                        ts, tf = k[2:4]
                        ts = self.map_time(ts)
                        tf = self.map_time(tf)
                        yu, yv = sorted((nl[u], nl[v]))
                        cr = curving(yu, yv) * division * 0.7
                        xm = ts + cr
                        ym = (yu + yv) * height
                        if cr > 0.:
                            x0.append(ts)
                            x1.append(ts)
                            y0.append(yu)
                            y1.append(yv)
                            cx.append(xm)
                            cy.append(ym)
                            if yu + yv == 2 * ym:
                                t = 0.5
                            else:
                                t = (sqrt(
                                    (yu - ym) *
                                    (ym - yv)) + yu - ym) / (yu - 2 * ym + yv)
                            assert 0 <= t <= 1
                            xm = (
                                (1 - t)**2 + t**2) + 2 * t * (1 - t) * (xm + 1)
                        else:
                            lp_x += [ts, ts, nan]
                            lp_y += [yu, yv, nan]
                        lp_x += [xm, tf, nan]
                        lp_y += [ym, ym, nan]
                l.append(((lp_x, lp_y), color))
                b.append(((x0, y0, x1, y1, cx, cy), color))

        aspect_scale = w / float(h)
        if self.date_map is None:
            self.p = figure(aspect_scale=aspect_scale)
            if self._data['time_set'].instantaneous:
                self.p.xaxis.ticker = list(self._data['time_set'])
            elif self._data['time_set'].discrete:
                self.p.xaxis.ticker = [
                    t for ts, tf in self._data['time_set']
                    for t in range(ts, tf + 1)
                ]
        else:
            assert callable(self.date_map) or isinstance(self.date_map, dict)
            self.p = figure(aspect_scale=aspect_scale, x_axis_type="datetime")
        if self.y_axis_label is not None:
            self.p.yaxis.axis_label = str(self.y_axis_label)
        self.p.xaxis.axis_label = (str(self.x_axis_label) if self.x_axis_label
                                   is not None else 'time')
        self.p.yaxis.ticker = list(range(len(nodes)))
        self.p.yaxis.major_label_overrides = ln

        from bokeh.models import ColumnDataSource
        from bokeh.models.glyphs import Quadratic

        self.p.circle(time_points, node_points, size=8, color="black")
        for ((lp_x, lp_y), c) in l:
            self.p.line(lp_x, lp_y, line_width=2, color='black')

        for ((x0, y0, x1, y1, cx, cy), c) in b:
            data = dict(x0=x0, y0=y0, x1=x1, y1=y1, cx=cx, cy=cy)
            self.p.add_glyph(
                ColumnDataSource(data),
                Quadratic(x0='x0',
                          y0='y0',
                          x1='x1',
                          y1='y1',
                          cx='cx',
                          cy='cy',
                          line_color=c,
                          line_width=2))
Example #7
0
    def add_path(self,
                 source_label,
                 links=None,
                 edge_type='curved',
                 tooltips=None,
                 legend=None,
                 **kwargs):
        """
        Connect all points in the datasource in a path (to show order).
        `self.prepare_plot` must have been called previous to this.
        
        Parameters:
        
        source_label (str): string corresponding to a label previously 
            called in `self.add_source`
        order_col: the column of a data source specifying the order of the records
        tooltips: string or list of tuples (passed to Bokeh HoverTool)
        legend (str): name to assign to this layer in the plot legend
        kwargs: options passed to the objected for `bokeh_model`
        
        This method allows two special kwargs: 'color' and 'alpha'. When 
            used with a bokeh model that has 'fill_color' and 'line_color' 
            and 'fill_alpha' and 'line_alpha' properties, calling the special 
            kwarg will use the same value for both.
        
        """

        self._validate_workflow('add_path')

        source = self.sources[source_label].copy()

        suffix = '_transform' if type(self.plot) != GMapPlot else ''
        x_point_label = 'x_coord_point{}'.format(suffix)
        y_point_label = 'y_coord_point{}'.format(suffix)

        if all(isinstance(x, (int, float)) for x in source[links].tolist()):
            x1 = source.sort_values(links)[x_point_label].values
            y1 = source.sort_values(links)[y_point_label].values
            x2 = x1[1:]
            y2 = y1[1:]
            x1 = x1[:-1]
            y1 = y1[:-1]
            x3 = (x1 + x2) / 2
            y3 = (y1 + y2) / 2
            xc = x3 + abs(y3 - y2)
            yc = y3 + abs(x3 - x2)

            new_source = {
                'x1': x1,
                'x2': x2,
                'xc': xc,
                'y1': y1,
                'y2': y2,
                'yc': yc
            }

            for c in source.columns:
                if (c not in self.omit_columns) and c not in new_source:
                    new_source[c] = source[c].values[:-1]
        elif all(
                isinstance(x, (list, tuple, set))
                for x in source[links].tolist()):
            if 'uid' not in source.columns:
                raise ValueError(
                    'Source must contain column `uid` when links is a list of iterables.'
                )

            nodes = source['uid'].tolist()
            edges = source[links].tolist()
            node_x = source.set_index('uid')[x_point_label].to_dict()
            node_y = source.set_index('uid')[y_point_label].to_dict()

            a_vals, x1, x2, y1, y2 = zip(*[(a, node_x[a], node_x[b], node_y[a],
                                            node_y[b])
                                           for a, bs in zip(nodes, edges)
                                           for b in bs])
            x1, x2, y1, y2 = array(x1), array(x2), array(y1), array(y2)
            x3 = (x1 + x2) / 2
            y3 = (y1 + y2) / 2
            xc = x3 + abs(y3 - y2)
            yc = y3 + abs(x3 - x2)

            new_source = {
                'x1': x1,
                'x2': x2,
                'xc': xc,
                'y1': y1,
                'y2': y2,
                'yc': yc
            }

            for c in source.columns:
                if (c not in self.omit_columns) and c not in new_source:
                    col_dict = source.set_index('uid', drop=False)[c].to_dict()
                    new_source[c] = [col_dict[v] for v in a_vals]
        else:
            raise ValueError(
                'Values of `links` field must be numeric or a list, set, or tuple of values from the `uid` field.'
            )

        if 'color' in kwargs.keys():
            color = kwargs.pop('color')
            for v in Quadratic.dataspecs():
                if 'color' in v:
                    kwargs[v] = color

        if 'alpha' in kwargs.keys():
            alpha = kwargs.pop('alpha')
            for v in Quadratic.dataspecs():
                if 'alpha' in v:
                    kwargs[v] = alpha

        if edge_type == 'curved':
            model_object = Quadratic(x0='x1',
                                     y0='y1',
                                     x1="x2",
                                     y1="y2",
                                     cx="xc",
                                     cy="yc",
                                     name=source_label,
                                     **kwargs)
        elif edge_type == 'straight':
            model_object = Segment(x0='x1',
                                   y0='y1',
                                   x1="x2",
                                   y1="y2",
                                   name=source_label,
                                   **kwargs)
        else:
            raise ValueError(
                'Keyword `edge_type` must be either "curved" or "straight".')

        source = ColumnDataSource(new_source, name=source_label)
        rend = self.plot.add_glyph(source, model_object)

        if legend is not None:
            li = LegendItem(label=legend, renderers=[rend])
            self.legend.items.append(li)

        if tooltips is not None:
            self.plot.add_tools(HoverTool(tooltips=tooltips, renderers=[rend]))

        return self