コード例 #1
0
class HorizonBuilder(LineBuilder):
    """Produces glyph renderers representing a horizon chart from many input types.

    The builder handles ingesting the data, deriving settings when not provided,
    building the renderers, then setting ranges, and modifying the chart as needed.

    """

    # class configuration
    glyph = HorizonGlyph
    default_attributes = {
        'color': ColorAttr(sort=False),
        'series': IdAttr(sort=False)
    }

    # primary input properties
    pos_color = Color("#006400",
                      help="""
    The color of the positive folds. (default: "#006400")
    """)

    neg_color = Color("#6495ed",
                      help="""
    The color of the negative folds. (default: "#6495ed")
    """)

    num_folds = Int(3,
                    help="""
    The number of folds stacked on top of each other. (default: 3)
    """)

    flip_neg = Bool(default=True,
                    help="""When True, the negative values will be
    plotted as their absolute value, then their individual axes is flipped. If False,
    then the negative values will still be taken as their absolute value, but the base
    of their shape will start from the same origin as the positive values.
    """)

    # derived properties
    series_count = Int(help="""Count of the unique series names.""")
    bins = List(Float,
                help="""The binedges calculated from the number of folds,
    and the maximum value of the entire source data.""")
    series_column = String(
        help="""The column that contains the series names.""")
    fold_height = Float(help="""The size of the bin.""")

    def setup(self):
        super(HorizonBuilder, self).setup()

        # collect series names and columns selected to color by
        if self.attributes['series'].columns is None:
            self.series_column = self.attributes['color'].columns[0]
        else:
            self.series_column = self.attributes['series'].columns[0]

        if len(self.series_names) == 0:
            self.set_series(self.series_column)

        self.series_count = len(self.series_names)

    def process_data(self):
        super(HorizonBuilder, self).process_data()

        # calculate group attributes, useful for each horizon glyph
        self.fold_height = max(self.y.max, abs(self.y.min)) / self.num_folds
        self.bins = [
            bin_id * self.fold_height for bin_id in range(self.num_folds + 1)
        ]

        # manually set attributes to have constant color
        ds = ColumnDataSource(self._data.df)
        self.attributes['series'].setup(data=ds, columns=self.series_column)
        self.attributes['color'].setup(data=ds, columns=self.pos_color)

    def set_ranges(self):
        super(HorizonBuilder, self).set_ranges()
        self.x_range = DataRange1d(range_padding=0)
        self.y_range.start = 0
        self.y_range.end = self.y.max
コード例 #2
0
class HistogramBuilder(BarBuilder):
    """Generates one to many histograms with unique attributes.

    The HistogramBuilder is responsible for producing a chart
    containing one to many histograms from table-like inputs.

    """

    bins = Either(List(Float), Int, default=None, help="""
    If bins is an int, it defines the number of equal-width bins in the
    given range. If bins is a sequence, it defines the
    bin edges, including the rightmost edge, allowing for non-uniform
    bin widths.

    (default: None, use Freedman-Diaconis rule)
    """)

    density = Bool(False, help="""
    Whether to normalize the histogram.

    If True, the result is the value of the probability *density* function
    at the bin, normalized such that the *integral* over the range is 1. If
    False, the result will contain the number of samples in each bin.

    For more info check :class:`~bkcharts.glyphs.HistogramGlyph`
    documentation.

    (default: False)
    """)

    glyph = HistogramGlyph

    def setup(self):
        super(HistogramBuilder, self).setup()

        # when we create multiple histograms, we set the alpha to support overlap
        if self.attributes['color'].columns is not None:
            self.fill_alpha = 0.6

    def get_extra_args(self):
        """Build kwargs that are unique to the histogram builder."""
        return dict(bins=self.bins, density=self.density)

    def _apply_inferred_index(self):
        # ignore this for now, unless histogram later adds handling of indexed data
        pass

    def set_ranges(self):
        """Push the Bar data into the ColumnDataSource and calculate
        the proper ranges.
        """

        x_max = max([comp_glyph.x_max for comp_glyph in self.comp_glyphs])
        x_min = min([comp_glyph.x_min for comp_glyph in self.comp_glyphs])
        y_max = max([comp_glyph.y_max for comp_glyph in self.comp_glyphs])
        y_min = min([comp_glyph.y_min for comp_glyph in self.comp_glyphs])

        x_buffer = ((x_max + x_min)/2.0)*0.05

        self.x_range = Range1d(start=x_min - x_buffer, end=x_max + x_buffer)

        self.y_range = Range1d(start=y_min, end=y_max * 1.1)
コード例 #3
0
ファイル: stats.py プロジェクト: rodrigopimenta10/RSR_Parsing
class BinnedStat(Stat):
    """ Base class for shared functionality accross bins and aggregates
    dimensions for plotting.

    """
    bin_stat = Instance(BinStats,
                        help="""
        A mapping between each dimension and associated binning calculations.
        """)

    bins = List(Instance(Bin),
                help="""
        A list of the `Bin` instances that were produced as result of the inputs.
        Iterating over `Bins` will iterate over this list. Each `Bin` can be inspected
        for metadata about the bin and the values associated with it.
        """)

    stat = Instance(Stat,
                    default=Count(),
                    help="""
        The statistical operation to be used on the values in each bin.
        """)

    bin_column = String()
    centers_column = String()

    aggregate = Bool(default=True)

    bin_values = Bool(default=False)

    bin_width = Float()

    def __init__(self,
                 values=None,
                 column=None,
                 bins=None,
                 stat='count',
                 source=None,
                 **properties):

        if isinstance(stat, str):
            stat = stats[stat]()

        properties['column'] = column or 'vals'
        properties['stat'] = stat
        properties['values'] = values
        properties['source'] = source
        self._bins = bins
        super(BinnedStat, self).__init__(**properties)

    def _get_stat(self):
        stat_kwargs = {}

        if self.source is not None:
            stat_kwargs['source'] = self.source
            stat_kwargs['column'] = self.column

        elif self.values is not None:
            stat_kwargs['values'] = self.values

        stat_kwargs['bins'] = self._bins

        return BinStats(**stat_kwargs)

    def update(self):
        self.bin_stat = self._get_stat()
        self.bin_stat.update()
コード例 #4
0
ファイル: glyphs.py プロジェクト: yihongfa/bokeh
class HorizonGlyph(AreaGlyph):
    num_folds = Int(default=3,
                    help="""The count of times the data is overlapped.""")

    series = Int(default=0,
                 help="""The id of the series as the order it will appear,
    starting from 0.""")

    series_count = Int()

    fold_height = Float(help="""The height of one fold.""")

    bins = List(Float,
                help="""The binedges calculated from the number of folds,
    and the maximum value of the entire source data.""")

    graph_ratio = Float(
        help="""Scales heights of each series based on number of folds
    and the number of total series being plotted.
    """)

    pos_color = Color("#006400",
                      help="""The color used for positive values.""")
    neg_color = Color("#6495ed",
                      help="""The color used for negative values.""")

    flip_neg = Bool(default=True,
                    help="""When True, the negative values will be
    plotted as their absolute value, then their individual axes is flipped. If False,
    then the negative values will still be taken as their absolute value, but the base
    of their shape will start from the same origin as the positive values.
    """)

    def __init__(self, bins=None, **kwargs):

        # fill alpha depends on how many folds will be layered
        kwargs['fill_alpha'] = 1.0 / kwargs['num_folds']

        if bins is not None:
            kwargs['bins'] = bins

            # each series is shifted up to a synthetic y-axis
            kwargs['base'] = kwargs['series'] * max(
                bins) / kwargs['series_count']
            kwargs['graph_ratio'] = float(kwargs['num_folds']) / float(
                kwargs['series_count'])

        super(HorizonGlyph, self).__init__(**kwargs)

    def build_source(self):
        data = {}

        # Build columns for the positive values
        pos_y = self.y.copy()
        pos_y[pos_y < 0] = 0
        xs, ys = self._build_dims(self.x, pos_y)

        # list of positive colors and alphas
        colors = [self.pos_color] * len(ys)
        alphas = [(bin_idx * self.fill_alpha)
                  for bin_idx in range(0, len(self.bins))]

        # If we have negative values at all, add the values for those as well
        if self.y.min() < 0:
            neg_y = self.y.copy()
            neg_y[neg_y > 0] = 0
            neg_y = abs(neg_y)
            neg_xs, neg_ys = self._build_dims(self.x, neg_y, self.flip_neg)

            xs += neg_xs
            ys += neg_ys
            colors += ([self.neg_color] * len(neg_ys))
            alphas += alphas

        # create clipped representation of each band
        data['x_values'] = xs
        data['y_values'] = ys
        data['fill_color'] = colors
        data['fill_alpha'] = colors
        data['line_color'] = colors

        return data

    def _build_dims(self, x, y, flip=False):
        """ Creates values needed to plot each fold of the horizon glyph.

        Bins the data based on the binning passed into the glyph, then copies and clips
        the values for each bin.

        Args:
            x (`pandas.Series`): array of x values
            y (`pandas.Series`): array of y values
            flip (bool): whether to flip values, used when handling negative values

        Returns:
            tuple(list(`numpy.ndarray`), list(`numpy.ndarray`)): returns a list of
                arrays for the x values and list of arrays for the y values. The data
                has been folded and transformed so the patches glyph presents the data
                in a way that looks like an area chart.
        """

        # assign bins to each y value
        bin_idx = pd.cut(y, bins=self.bins, labels=False, include_lowest=True)

        xs, ys = [], []
        for idx, bin in enumerate(self.bins[0:-1]):

            # subtract off values associated with lower bins, to get into this bin
            temp_vals = y.copy() - (idx * self.fold_height)

            # clip the values between the fold range and zero
            temp_vals[bin_idx > idx] = self.fold_height * self.graph_ratio
            temp_vals[bin_idx < idx] = 0
            temp_vals[bin_idx ==
                      idx] = self.graph_ratio * temp_vals[bin_idx == idx]

            # if flipping, we must start the values from the top of each fold's range
            if flip:
                temp_vals = (self.fold_height * self.graph_ratio) - temp_vals
                base = self.base + (self.fold_height * self.graph_ratio)
            else:
                base = self.base

            # shift values up based on index of series
            temp_vals += self.base
            val_idx = temp_vals > 0
            if pd.Series.any(val_idx):
                ys.append(temp_vals)
                xs.append(x)

        # transform clipped data so it always starts and ends at its base value
        if len(ys) > 0:
            xs, ys = map(
                list,
                zip(*[
                    generate_patch_base(x, y, base=base)
                    for x, y in zip(xs, ys)
                ]))

        return xs, ys

    def build_renderers(self):
        # parse all series. We exclude the first attr as it's the x values
        # added for the index
        glyph = Patches(xs='x_values',
                        ys='y_values',
                        fill_alpha=self.fill_alpha,
                        fill_color='fill_color',
                        line_color='line_color')
        renderer = GlyphRenderer(data_source=self.source, glyph=glyph)
        yield renderer
コード例 #5
0
ファイル: tabulator.py プロジェクト: yuttie/panel
class DataTabulator(HTMLBox):
    """A Bokeh Model that enables easy use of Tabulator tables
    See http://tabulator.info/
    """

    configuration = Dict(String, Any)

    columns = List(Instance(TableColumn),
                   help="""
    The list of child column widgets.
    """)

    download = Bool(default=False)

    editable = Bool(default=True)

    filename = String(default="table.csv")

    follow = Bool(True)

    frozen_rows = List(Int)

    groupby = List(String)

    hidden_columns = List(String)

    layout = Enum('fit_data',
                  'fit_data_fill',
                  'fit_data_stretch',
                  'fit_data_table',
                  'fit_columns',
                  default="fit_data")

    source = Instance(ColumnDataSource)

    styles = Dict(Int, Dict(Int, List(String)))

    pagination = Nullable(String)

    page = Nullable(Int)

    page_size = Int()

    max_page = Int()

    sorters = List(Dict(String, String))

    theme = Enum(*TABULATOR_THEMES, default="simple")

    theme_url = String(default=THEME_URL)

    __css__ = [THEME_URL + 'tabulator_simple.min.css']

    __javascript__ = [JS_SRC, MOMENT_SRC]

    __js_require__ = {
        'paths': {
            'tabulator': JS_SRC[:-3]
        },
        'exports': {
            'tabulator': 'Tabulator'
        }
    }

    __js_skip__ = {'tabulator': __javascript__}
コード例 #6
0
class BarBuilder(Builder):
    """This is the Bar builder and it is in charge of plotting
    Bar chart (grouped and stacked) in an easy and intuitive way.
    Essentially, it utilizes a standardized way to ingest the data,
    make the proper calculations and generate renderers. The renderers
    reference the transformed data, which represent the groups of data
    that were derived from the inputs. We additionally make calculations
    for the ranges.
    The x_range is categorical, and is made either from the label argument
    or from the `pandas.DataFrame.index`. The y_range can be supplied as the
    parameter continuous_range, or will be calculated as a linear range
    (Range1d) based on the supplied values.
    The bar builder is and can be further used as a base class for other
    builders that might also be performing some aggregation across
    derived groups of data.
    """

    # ToDo: add label back as a discrete dimension
    values = Dimension('values')

    dimensions = ['values']
    # req_dimensions = [['values']]

    default_attributes = {'label': CatAttr(),
                          'color': ColorAttr(),
                          'line_color': ColorAttr(default='white'),
                          'stack': CatAttr(),
                          'group': CatAttr()}

    agg = Enum(Aggregation, default='sum')

    max_height = Float(1.0)
    min_height = Float(0.0)
    bar_width = Float(default=0.8)
    fill_alpha = Float(default=0.8)

    glyph = BarGlyph
    comp_glyph_types = Override(default=[BarGlyph])
    label_attributes = ['stack', 'group']

    label_only = Bool(False)
    values_only = Bool(False)

    _perform_stack = False
    _perform_group = False

    def setup(self):

        if self.attributes['color'].columns is None:
            if self.attributes['stack'].columns is not None:
                self.attributes['color'].setup(columns=self.attributes['stack'].columns)

            if self.attributes['group'].columns is not None:
                self.attributes['color'].setup(columns=self.attributes['group'].columns)

        if self.attributes['stack'].columns is not None:
            self._perform_stack = True

        if self.attributes['group'].columns is not None:
            self._perform_group = True

        # ToDo: perform aggregation validation
        # Not given values kw, so using only categorical data
        if self.values.dtype.name == 'object' and len(self.attribute_columns) == 0:
            # agg must be count
            self.agg = 'count'
            self.attributes['label'].set_columns(self.values.selection)
        else:
            pass

        self._apply_inferred_index()

        if self.xlabel is None:
            if self.attributes['label'].columns is not None:
                self.xlabel = str(
                    ', '.join(self.attributes['label'].columns).title()).title()
            else:
                self.xlabel = self.values.selection

        if self.ylabel is None:
            if not self.label_only:
                self.ylabel = '%s( %s )' % (
                self.agg.title(), str(self.values.selection).title())
            else:
                self.ylabel = '%s( %s )' % (
                self.agg.title(), ', '.join(self.attributes['label'].columns).title())

    def _apply_inferred_index(self):
        """Configure chart when labels are provided as index instead of as kwarg."""

        # try to infer grouping vs stacking labels
        if (self.attributes['label'].columns is None and
                    self.values.selection is not None):

            if self.attributes['stack'].columns is not None:
                special_column = 'unity'
            else:
                special_column = 'index'

            self._data['label'] = special_column
            self.attributes['label'].setup(data=ColumnDataSource(self._data.df),
                                           columns=special_column)

            self.xlabel = ''

    def set_ranges(self):
        """Push the Bar data into the ColumnDataSource and calculate
        the proper ranges.
        """
        x_items = self.attributes['label'].items
        if x_items is None:
            x_items = ''
        x_labels = []

        # Items are identified by tuples. If the tuple has a single value,
        # we unpack it
        for item in x_items:
            item = self._get_label(item)

            x_labels.append(str(item))

        self.x_range = FactorRange(factors=x_labels)

        y_shift = abs(0.1 * ((self.min_height + self.max_height) / 2))

        if self.min_height < 0:
            start = self.min_height - y_shift
        else:
            start = 0.0

        if self.max_height > 0:
            end = self.max_height + y_shift
        else:
            end = 0.0

        self.y_range = Range1d(start=start, end=end)

    def get_extra_args(self):
        if self.__class__ is not BarBuilder:
            attrs = self.properties(with_bases=False)
            return {attr: getattr(self, attr) for attr in attrs}
        else:
            return {}
コード例 #7
0
ファイル: glyphs.py プロジェクト: yihongfa/bokeh
class AreaGlyph(LineGlyph):

    # ToDo: should these be added to composite glyph?
    stack = Bool(default=False)
    dodge = Bool(default=False)

    base = Float(default=0.0, help="""Lower bound of area.""")

    def __init__(self, **kwargs):
        line_color = kwargs.get('line_color', None)
        fill_color = kwargs.get('fill_color', None)
        color = kwargs.get('color', None)

        if color is not None:
            # apply color to line and fill
            kwargs['fill_color'] = color
            kwargs['line_color'] = color
        elif line_color is not None and fill_color is None:
            # apply line color to fill color by default
            kwargs['fill_color'] = line_color

        super(AreaGlyph, self).__init__(**kwargs)
        self.setup()

    def build_source(self):
        data = super(AreaGlyph, self).build_source()

        x0, y0 = generate_patch_base(data['x_values'], data['y_values'])

        data['x_values'] = [x0]
        data['y_values'] = [y0]

        return data

    def build_renderers(self):

        # parse all series. We exclude the first attr as it's the x values
        # added for the index
        glyph = Patches(xs='x_values',
                        ys='y_values',
                        fill_alpha=self.fill_alpha,
                        fill_color=self.fill_color,
                        line_color=self.line_color)
        renderer = GlyphRenderer(data_source=self.source, glyph=glyph)
        yield renderer

    def __stack__(self, glyphs):

        # ToDo: need to handle case of non-aligned indices, see pandas concat
        # ToDo: need to address how to aggregate on an index when required
        if self.stack:

            # build a list of series
            areas = []
            for glyph in glyphs:
                areas.append(
                    pd.Series(glyph.source.data['y_values'][0],
                              index=glyph.source.data['x_values'][0]))

            # concat the list of indexed y values into dataframe
            df = pd.concat(areas, axis=1)

            # calculate stacked values along the rows
            stacked_df = df.cumsum(axis=1)

            # lower bounds of each area series are diff between stacked and orig values
            lower_bounds = stacked_df - df

            # reverse the df so the patch is drawn in correct order
            lower_bounds = lower_bounds.iloc[::-1]

            # concat the upper and lower bounds together
            stacked_df = pd.concat([stacked_df, lower_bounds])

            # update the data in the glyphs
            for i, glyph in enumerate(glyphs):
                glyph.source.data['x_values'] = [stacked_df.index.values]
                glyph.source.data['y_values'] = [stacked_df.ix[:, i].values]

    def get_nested_extent(self, col, func):
        return [getattr(arr, func)() for arr in self.source.data[col]]

    @property
    def x_max(self):
        return max(self.get_nested_extent('x_values', 'max'))

    @property
    def x_min(self):
        return min(self.get_nested_extent('x_values', 'min'))

    @property
    def y_max(self):
        return max(self.get_nested_extent('y_values', 'max'))

    @property
    def y_min(self):
        return min(self.get_nested_extent('y_values', 'min'))
コード例 #8
0
ファイル: datetime_picker.py プロジェクト: syamajala/panel
class DatetimePicker(InputWidget):
    ''' Calendar-based date picker widget.

    '''

    value = String(help="""
    The initial or picked date.
    """)

    min_date = Nullable(Either(Date, Datetime),
                        help="""
    Optional earliest allowable date.
    """)

    max_date = Nullable(Either(Date, Datetime),
                        help="""
    Optional latest allowable date.
    """)

    disabled_dates = List(Either(Date, Datetime, Tuple(Date, Date),
                                 Tuple(Datetime, Datetime)),
                          default=[],
                          help="""
    A list of dates of ``(start, end)`` date ranges to make unavailable for
    selection. All other dates will be avalable.

    .. note::
        Only one of ``disabled_dates`` and ``enabled_dates`` should be specified.
    """)

    enabled_dates = List(Either(Date, Datetime, Tuple(Date, Date),
                                Tuple(Datetime, Datetime)),
                         default=[],
                         help="""
    A list of dates of ``(start, end)`` date ranges to make available for
    selection. All other dates will be unavailable.

    .. note::
        Only one of ``disabled_dates`` and ``enabled_dates`` should be specified.
    """)

    position = Enum(CalendarPosition,
                    default="auto",
                    help="""
    Where the calendar is rendered relative to the input when ``inline`` is False.
    """)

    inline = Bool(default=False,
                  help="""
    Whether the calendar sholud be displayed inline.
    """)

    enable_time = Bool(default=True)

    enable_seconds = Bool(default=True)

    military_time = Bool(default=True)

    date_format = String("Y-m-d H:i:S")

    mode = String(default="single",
                  help="""
    Should either be "single" or "range".""")
コード例 #9
0
class ChordBuilder(Builder):
    """ This is the Chord builder and it is in charge of plotting
    Chord graphs in an easy and intuitive way.

    Essentially, we provide a way to ingest the data, make the proper
    calculations and push the references into a source object.
    We additionally make calculations for the ranges. And finally add
    the needed glyphs (markers) taking the references from the source.

    """

    default_attributes = {
        'color': ColorAttr(),
        'marker': MarkerAttr(),
        'stack': CatAttr()
    }

    dimensions = ['values']

    values = Dimension('values')

    arcs_data = Instance(ColumnDataSource)
    text_data = Instance(ColumnDataSource)
    connection_data = Instance(ColumnDataSource)

    origin = String()
    destination = String()
    value = Any()
    square_matrix = Bool()
    label = Seq(Any())
    matrix = Array(Array(Either(Float(), Int())))

    def set_ranges(self):
        rng = 1.1 if not self.label else 1.8
        self.x_range = Range1d(-rng, rng)
        self.y_range = Range1d(-rng, rng)

    def setup(self):

        # Process only if not a square_matrix
        if not self.square_matrix:
            source = self.values._data[self.origin]
            target = self.values._data[self.destination]
            union = source.append(target).unique()
            N = union.shape[0]
            m = pd.DataFrame(np.zeros((N, N)), columns=union, index=union)

            if not self.label:
                self.label = list(union)

            if self.value is None:
                for _, row in self.values._data.iterrows():
                    m[row[self.origin]][row[self.destination]] += 1
                self.matrix = m.get_values()

            if self.value is not None:

                if isinstance(self.value, int) or isinstance(
                        self.value, float):
                    for _, row in self.values._data.iterrows():
                        m[row[self.origin]][row[self.destination]] = self.value
                    self.matrix = m.get_values()

                elif isinstance(self.value, str):
                    for _, row in self.values._data.iterrows():
                        m[row[self.origin]][row[self.destination]] = row[
                            self.value]
                    self.matrix = m.get_values().T
        else:
            # It's already a square matrix
            self.matrix = self._data.df.get_values()

        if self.label:
            assert len(self.label) == self.matrix.shape[0]

    def process_data(self):

        weights_of_areas = (self.matrix.sum(axis=0) +
                            self.matrix.sum(axis=1)) - self.matrix.diagonal()
        areas_in_radians = (weights_of_areas / weights_of_areas.sum()) * (2 *
                                                                          pi)

        # We add a zero in the begging for the cumulative sum
        points = np.zeros((areas_in_radians.shape[0] + 1))
        points[1:] = areas_in_radians
        points = points.cumsum()

        colors = [
            color_in_equal_space(area / areas_in_radians.shape[0])
            for area in range(areas_in_radians.shape[0])
        ]

        arcs_data = pd.DataFrame({
            'start_angle': points[:-1],
            'end_angle': points[1:],
            'line_color': colors
        })

        self.arcs_data = ColumnDataSource(arcs_data)

        # Text
        if self.label:
            text_radius = 1.1
            angles = (points[:-1] + points[1:]) / 2.0

            text_positions = pd.DataFrame({
                'angles': angles,
                'text_x': np.cos(angles) * text_radius,
                'text_y': np.sin(angles) * text_radius,
                'text': list(self.label)
            })

            self.text_data = ColumnDataSource(text_positions)

        # Lines

        all_areas = []
        for i in range(areas_in_radians.shape[0]):
            all_areas.append(
                Area(weights_of_areas[i], points[:-1][i], points[1:][i]))

        all_connections = []
        for j, region1 in enumerate(self.matrix):
            # Get the connections origin region
            source = all_areas[j]
            color = colors[j]
            weight = weights_of_areas[j]

            for k, region2 in enumerate(region1):
                # Get the connection destination region
                target = all_areas[k]
                for _ in range(int(region2)):
                    p1 = source.free_points.pop()
                    p2 = target.free_points.pop()
                    # Get both regions free points and create a connection with the data
                    all_connections.append(p1 + p2 + [color, weight])

        connections_df = pd.DataFrame(all_connections, dtype=str)
        connections_df.columns = [
            "start_x", "start_y", "end_x", "end_y", "colors", "weight"
        ]
        connections_df["cx0"] = connections_df.start_x.astype("float64") / 2
        connections_df["cy0"] = connections_df.start_y.astype("float64") / 2
        connections_df["cx1"] = connections_df.end_x.astype("float64") / 2
        connections_df["cy1"] = connections_df.end_y.astype("float64") / 2
        connections_df.weight = (
            connections_df.weight.astype("float64") /
            connections_df.weight.astype("float64").sum()) * 3000

        self.connection_data = ColumnDataSource(connections_df)

    def yield_renderers(self):
        """Use the marker glyphs to display the arcs and beziers.
        Takes reference points from data loaded at the ColumnDataSource.
        """
        beziers = Bezier(x0='start_x',
                         y0='start_y',
                         x1='end_x',
                         y1='end_y',
                         cx0='cx0',
                         cy0='cy0',
                         cx1='cx1',
                         cy1='cy1',
                         line_alpha='weight',
                         line_color='colors')

        yield GlyphRenderer(data_source=self.connection_data, glyph=beziers)

        arcs = Arc(x=0,
                   y=0,
                   radius=1,
                   line_width=10,
                   start_angle='start_angle',
                   end_angle='end_angle',
                   line_color='line_color')

        yield GlyphRenderer(data_source=self.arcs_data, glyph=arcs)

        if self.label:

            text_props = {
                "text_color": "#000000",
                "text_font_size": "8pt",
                "text_align": "left",
                "text_baseline": "middle"
            }

            labels = Text(x='text_x',
                          y='text_y',
                          text='text',
                          angle='angles',
                          **text_props)

            yield GlyphRenderer(data_source=self.text_data, glyph=labels)
コード例 #10
0
class Bins(Stat):
    """Bins and aggregates dimensions for plotting.

    Takes the inputs and produces a list of bins that can be iterated over and
    inspected for their metadata. The bins provide easy access to consistent labeling,
    bounds, and values.
    """

    bin_stat = Instance(BinStats,
                        help="""
        A mapping between each dimension and associated binning calculations.
        """)

    bins = List(Instance(Bin),
                help="""
        A list of the `Bin` instances that were produced as result of the inputs.
        Iterating over `Bins` will iterate over this list. Each `Bin` can be inspected
        for metadata about the bin and the values associated with it.
        """)

    stat = Instance(Stat,
                    default=Count(),
                    help="""
        The statistical operation to be used on the values in each bin.
        """)

    bin_count = Int(help="""
        An optional list of the number of bins to use for each dimension. If a single
        value is provided, then the same number of bins will be used for each.
        """)

    bin_column = String()
    centers_column = String()

    aggregate = Bool(default=True)

    bin_values = Bool(default=False)

    bin_width = Float()

    def __init__(self,
                 values=None,
                 column=None,
                 bins=None,
                 stat='count',
                 source=None,
                 **properties):

        if isinstance(stat, str):
            stat = stats[stat]()

        properties['column'] = column or 'vals'
        properties['bins'] = bins
        properties['stat'] = stat
        properties['values'] = values
        properties['source'] = source

        super(Bins, self).__init__(**properties)

    def _get_stat(self):
        stat_kwargs = {}

        if self.source is not None:
            stat_kwargs['source'] = self.source
            stat_kwargs['column'] = self.column

        elif self.values is not None:
            stat_kwargs['values'] = self.values

        stat_kwargs['bin_count'] = self.bin_count

        return BinStats(**stat_kwargs)

    def update(self):
        self.bin_stat = self._get_stat()
        self.bin_stat.update()

    def calculate(self):

        bin_str = '_bin'
        self.bin_column = self.column + bin_str
        bin_models = []

        binned, bin_bounds = pd.cut(self.bin_stat.get_data(),
                                    self.bin_stat.bin_count,
                                    retbins=True,
                                    include_lowest=True,
                                    precision=0)

        self.bin_width = np.round(bin_bounds[2] - bin_bounds[1], 1)

        if self.source is not None:
            # add bin column to data source
            self.source.add(binned.tolist(), name=self.bin_column)
            df = self.source.to_df()
        else:
            df = pd.DataFrame({
                self.column: self.values,
                self.bin_column: binned
            })

        for name, group in df.groupby(self.bin_column):
            bin_models.append(
                Bin(bin_label=name, values=group[self.column], stat=self.stat))

        self.bins = bin_models

        centers = binned.copy()
        centers = centers.astype(str)
        for bin in self.bins:
            centers[binned == bin.label] = bin.center

        self.centers_column = self.column + '_center'
        if self.source is not None:
            self.source.add(centers.tolist(), name=self.centers_column)
        else:
            df[self.centers_column] = centers

    def __getitem__(self, item):
        return self.bins[item]

    def apply(self, data):
        self.set_data(data.source)
        return self.source.to_df()

    def sort(self, ascending=True):
        if self.bins is not None:
            self.bins = list(
                sorted(self.bins, key=lambda x: x.center, reverse=~ascending))
コード例 #11
0
class AcePlot(HTMLBox):
    """
    A Bokeh model that wraps around a Ace editor and renders it inside
    a Bokeh plot.
    """

    __javascript_raw__ = [
        'https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.11/ace.js',
        'https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.11/ext-language_tools.js',
        'https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.11/ext-modelist.js'
    ]

    __tarball__ = {
        'tar': 'https://registry.npmjs.org/ace-builds/-/ace-builds-1.4.11.tgz',
        'src': 'package/src-min/',
        'dest': 'ajax/libs/1.4.11',
        'exclude': ['snippets']
    }

    @classproperty
    def __javascript__(cls):
        return bundled_files(cls)

    @classproperty
    def __js_skip__(cls):
        return {'ace': cls.__javascript__}

    __js_require__ = {
        'paths': {
            ('ace', ('ace/ace', 'ace/ext-language_tools')):
            '//cdnjs.cloudflare.com/ajax/libs/ace/1.4.7'
        },
        'exports': {
            'ace': 'ace'
        },
        'shim': {
            'ace/ext-language_tools': {
                'deps': ["ace/ace"]
            },
            'ace/ext-modelist': {
                'deps': ["ace/ace"]
            }
        }
    }

    code = String()

    theme = Enum(ace_themes, default='chrome')

    filename = String()

    language = String()

    annotations = List(Dict(String, Any), default=[])

    readonly = Bool(default=False)

    print_margin = Bool(default=False)

    height = Override(default=300)

    width = Override(default=300)
コード例 #12
0
class HistogramGlyph(AggregateGlyph):
    """Depicts the distribution of values using rectangles created by binning.

    The histogram represents a distribution, so will likely include other
    options for displaying it, such as KDE and cumulative density.
    """

    # derived models
    bins = Instance(BinnedStat,
                    help="""A stat used to calculate the bins. The bins stat
        includes attributes about each composite bin.""")
    bars = List(Instance(BarGlyph),
                help="""The histogram is comprised of many
        BarGlyphs that are derived from the values.""")
    density = Bool(False,
                   help="""
        Whether to normalize the histogram.

        If True, the result is the value of the probability *density* function
        at the bin, normalized such that the *integral* over the range is 1. If
        False, the result will contain the number of samples in each bin.

        For more info check :class:`~bkcharts.stats.Histogram` documentation.

        (default: False)
    """)

    def __init__(self, values, label=None, color=None, bins=None, **kwargs):
        if label is not None:
            kwargs['label'] = label
        kwargs['values'] = values

        if color is not None:
            kwargs['color'] = color

        # remove width, since this is handled automatically
        kwargs.pop('width', None)

        # keep original bins setting private since it just needs to be
        # delegated to the Histogram stat
        self._bins = bins

        super(HistogramGlyph, self).__init__(**kwargs)
        self.setup()

    def _set_sources(self):
        # No need to set sources, since composite glyphs handle this
        pass

    def build_source(self):
        # No need to build source, since composite glyphs handle this
        return None

    def build_renderers(self):
        """Yield a bar glyph for each bin."""
        # TODO(fpliger): We should expose the bin stat class so we could let
        #               users specify other bins other the Histogram Stat
        self.bins = Histogram(values=self.values,
                              bins=self._bins,
                              density=self.density)

        bars = []
        for bin in self.bins.bins:
            bars.append(
                BarGlyph(label=bin.label[0],
                         x_label=bin.center,
                         values=bin.values,
                         color=self.color,
                         fill_alpha=self.fill_alpha,
                         agg=bin.stat,
                         width=bin.width))

        # provide access to bars as children for bounds properties
        self.bars = self.children = bars

        for comp_glyph in self.bars:
            for renderer in comp_glyph.renderers:
                yield renderer

    @property
    def y_min(self):
        return 0.0
コード例 #13
0
class ExtendedColumn(Column):
    aria_hidden = Bool(False)
コード例 #14
0
class CustomRow(Box):

    __implementation__ = "customRow.ts"

    hide = Bool(False)