示例#1
0
 def __init__(self,
              title=None,
              title_level=3,
              title_wrap=False,
              width=None,
              height=None,
              inherit_cfg=True,
              styles=None,
              classes=(),
              anchor=None,
              **kwargs):
     self._settings = Cfg(
         title=title,
         title_level=title_level,
         title_wrap=title_wrap,
         cascading_cfg=Cfg(**kwargs).override(styles or Cfg()),
         default_cfg=Cfg(),
         inherit_cfg=inherit_cfg,
         width=width,
         height=height,
         classes=["pybloqs"] +
         ([classes] if isinstance(classes, str) else list(classes)))
     # Anchor should not be inherited, so keep outside of Cfg
     self._anchor = anchor
     self._id = uuid.uuid4().hex
示例#2
0
    def _parse_args(args, allowed_cfg_types=(Cfg, )):
        """
        Parse the supplied argument list into a configuration object.

        :param args: Argument list.
        :param allowed_cfg_types: The listed configuration object types will be allowed.
        :return: Tuple of (chart configuration object, plot configuration object OR None)
        """
        plot_cfg = None
        configs = Cfg()
        for arg in args:
            # Construct an instance in case the config object is passed in as a type
            if isinstance(arg, type):
                arg = arg()

            if isinstance(arg, _PlotOpts):
                if plot_cfg:
                    plot_cfg = plot_cfg.inherit(arg)
                else:
                    plot_cfg = arg
            elif isinstance(arg, allowed_cfg_types):
                configs = configs.inherit(arg)
            else:
                raise ValueError(
                    "%s is not recognized as a plot or chart configuration object"
                    % arg)
        return configs, plot_cfg
示例#3
0
    def render_html(self,
                    pretty=True,
                    static_output=False,
                    header_block=None,
                    footer_block=None,
                    pdf_page_size="A4"):
        """Returns html output of the block
        :param pretty: Toggles pretty printing of the resulting HTML. Not applicable for non-HTML output.
        :return html-code of the block
        """
        # Render the contents
        html = root("html", doctype="html")
        head = append_to(html, "head")
        head = append_to(head, "meta", charset='utf-8')
        body = append_to(html, "body")

        # Make sure that the main style sheet is always included
        resource_deps = DependencyTracker(default_css_main)
        if header_block is not None:
            header_block._write_block(body,
                                      Cfg(),
                                      id_generator(),
                                      resource_deps=resource_deps,
                                      static_output=static_output)

        self._write_block(body,
                          Cfg(),
                          id_generator(),
                          resource_deps=resource_deps,
                          static_output=static_output)

        if footer_block is not None:
            footer_block._write_block(body,
                                      Cfg(),
                                      id_generator(),
                                      resource_deps=resource_deps,
                                      static_output=static_output)

        script_inflate.write(head)
        script_block_core.write(head)

        if static_output:
            # Add the load wait poller if there are any JS resources
            js_elem(body, "var loadWaitPoller=runWaitPoller();")

        # Write out resources
        for res in resource_deps:
            res.write(head)

        # Render the whole document (the parent of the html tag)
        content = render(html.parent, pretty=pretty)
        return content
示例#4
0
    def _set_chart_defaults(chart_cfg, chart_cls):
        if chart_cls == "StockChart":
            chart_cfg = chart_cfg.inherit_many(
                Chart(zoom_type="x"),
                PlotOptions(Series(States(Hover(enabled=False, halo=False)))))
        else:
            chart_cfg = chart_cfg.inherit_many(Chart(zoom_type="xy"))

        # Stockcharts forces the Y Axis to be on the right side by default and it
        # does not honor overrides set globally in JS. Fix it here.
        if "y_axis" not in chart_cfg:
            return chart_cfg.inherit(YAxis(opposite=False))
        else:
            base_cfg = Cfg(opposite=False)

            # In case we have a single y axis, just set the defaults on it
            if isinstance(chart_cfg.y_axis, Cfg):
                chart_cfg.y_axis = chart_cfg.y_axis.inherit(base_cfg)
            else:
                y_axes = chart_cfg.y_axis

                # Set the default on all y axes
                for i in range(len(y_axes)):
                    y_axes[i] = y_axes[i].inherit(base_cfg)

            return chart_cfg
示例#5
0
    def _get_styles_string(self, styles_cfg):
        """
        Converts the styles configuration to a CSS styles string.

        :param styles_cfg: The configuration object to convert.
        :return: CSS string
        """
        sizing_cfg = Cfg()

        if self._settings.width is not None:
            sizing_cfg["width"] = self._settings.width

        if self._settings.height is not None:
            sizing_cfg["height"] = self._settings.height

        # Replace `_` with `-` and make values lowercase to get valid CSS names
        return cfg_to_css_string(styles_cfg.override(sizing_cfg))
示例#6
0
    def data(self):
        """
        Function required to support interactive IPython plotting.

        Should not be used directly.

        :return: Data to be displayed
        """
        container = root("div")
        self._write_block(container, Cfg(), id_generator())

        # Write children into the output
        output = BytesIO()

        for child in container.children:
            output.write(render(child))

        return output.getvalue()
示例#7
0
                def _set_axis(axis_name):
                    # Get a custom axis, or use/create a default one.
                    axis = subchart_cfg.setdefault(
                        axis_name, None) or axis_defaults.setdefault(
                            axis_name, Cfg())
                    if isinstance(axis, (list, tuple)):
                        if len(axis) != 1:
                            raise ValueError(
                                "There can be at most one sub-chart axis definition for each axis."
                            )

                        axis = axis[0]

                    # Get the index of this axis from the list of known axes. Optionally, add a new entry.
                    axis_coll = axes[axis_name]
                    try:
                        axis_idx = axis_coll.index(axis)
                    except ValueError:
                        axis_coll.append(axis)
                        axis_idx = len(axis_coll) - 1

                    for series_cfg in subchart_series:
                        series_cfg[axis_name] = axis_idx
示例#8
0
    def _write_contents(self, container, actual_cfg, *args, **kwargs):
        # The width of one column in percentage
        content_count = len(self._contents)

        # Skip layout if there is no content.
        if content_count > 0:
            cell_width = 100. / min(self._cols, content_count)

            row_count = int(math.ceil(content_count / float(self._cols)))

            for row_i in range(row_count):
                row_el = append_to(container, "div")
                row_el["class"] = ["pybloqs-grid-row"]

                if row_i > 0:
                    row_el["style"] = "clear:both"

                written_row_item_count = row_i * self._cols

                for col_i in range(self._cols):
                    item_count = written_row_item_count + col_i
                    if item_count >= content_count:
                        break

                    cell_el = append_to(row_el,
                                        "div",
                                        style="width:%f%%;float:left;" %
                                        cell_width)
                    cell_el["class"] = ["pybloqs-grid-cell"]

                    self._contents[item_count]._write_block(
                        cell_el, actual_cfg if self._cascade_cfg else Cfg(),
                        *args, **kwargs)

            # Clear the floating, Yarr!
            append_to(container, "div", style="clear:both")
示例#9
0
    def _builder(*args, **kwargs):
        for arg in args:
            kwargs.update(arg)

        kwargs["__id"] = hash(name)
        return Cfg({name: Cfg(kwargs).inherit_many(*def_args, **def_kwargs)})
示例#10
0
 def _wrap(cfg, name):
     cfg = cfg.override(Cfg(data=data))
     if "name" not in cfg and name is not None:
         cfg.name = name
     return [cfg]
示例#11
0
    def __init__(self, data, *args, **kwargs):
        """
        Create a chart or composite chart from the supplied data.

        :param data: List, tuple, pandas.Series/DataFrame to use as chart data.
                     In case `data` is a list of Plot objects, a composite chart will be constructed.
        :param chart_cls: The chart class to use. Available values are "Chart" or "StockChart".
                          StockCharts have extra features like a navigator pane and special handling
                          for timestamps. A sensible default will be chosen based on the data by default.
        :param flatten: When set to True, the data will be flattened and categories will be
                        extracted from labelled data automatically.
                        Useful when creating plots where both axes need category labels (e.g. heatmaps).
        :param args: Chart level configuration. Axes definitions will be applied to subplots
                     that do not have custom axes. Plots option sets supplied here will
                     be used by default for any subplots that do not specify their own.
        :param kwargs: Optional styling arguments. The `style` keyword argument has special
                       meaning in that it allows styling to be grouped as one argument.
                       It is also useful in case a styling parameter name clashes with a standard
                       block parameter.
        """
        chart_cls = kwargs.pop("chart_cls", self._choose_chart_class(data))
        flatten = kwargs.pop("flatten", False)
        switch_zy = kwargs.pop("switch_zy", False)

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

        chart_cfg, plot_cfg = self._parse_args(args)

        # In case we got a list/tuple of Plots, create a composite chart.
        if isinstance(data,
                      (list, tuple)) and isinstance(data[0], (Plot, NDFrame)):
            # Parse out any axis defaults
            axis_defaults = {}
            for ax_name in ["x_axis", "y_axis"]:
                axis_cfg = chart_cfg.pop(ax_name, None)
                if axis_cfg is not None:
                    axis_defaults[ax_name] = axis_cfg

            axes = Cfg(x_axis=[], y_axis=[])

            chart_series = []

            for plot_data in data:
                # Convert data to a plot in case the it was not an actual plot instance
                # (but a pandas object for example).
                if not isinstance(plot_data, Plot):
                    plot_data = Plot(plot_data)
                    # If no chart class was defined yet, choose one based on the data.
                if chart_cls is None:
                    chart_cls = plot_data._chart_cls

                # Extract the chart configuration.
                subchart_cfg = plot_data._chart_cfg

                # Extract the series from the subchart config
                subchart_series = subchart_cfg.series

                # Check for axis definitions.
                def _set_axis(axis_name):
                    # Get a custom axis, or use/create a default one.
                    axis = subchart_cfg.setdefault(
                        axis_name, None) or axis_defaults.setdefault(
                            axis_name, Cfg())
                    if isinstance(axis, (list, tuple)):
                        if len(axis) != 1:
                            raise ValueError(
                                "There can be at most one sub-chart axis definition for each axis."
                            )

                        axis = axis[0]

                    # Get the index of this axis from the list of known axes. Optionally, add a new entry.
                    axis_coll = axes[axis_name]
                    try:
                        axis_idx = axis_coll.index(axis)
                    except ValueError:
                        axis_coll.append(axis)
                        axis_idx = len(axis_coll) - 1

                    for series_cfg in subchart_series:
                        series_cfg[axis_name] = axis_idx

                _set_axis("x_axis")
                _set_axis("y_axis")

                # Add the subplot series to the figure series.
                chart_series.extend(subchart_series)

            chart_cfg = chart_cfg.override(axes)
            chart_cfg.series = chart_series
        else:
            if flatten:
                data, chart_cfg = self._flatten_data(data,
                                                     chart_cfg,
                                                     switch_zy=switch_zy)

            chart_cfg.series = self._construct_plot_series(data, plot_cfg)

        chart_cfg = self._set_chart_defaults(chart_cfg, chart_cls)

        self._chart_cfg = chart_cfg
        self._chart_cls = chart_cls
示例#12
0
    Creates a chart configuration group. Uniqueness is ensured by attaching an UUID
    base __id keyword.
    """
    def _builder(*args, **kwargs):
        for arg in args:
            kwargs.update(arg)

        kwargs["__id"] = hash(name)
        return Cfg({name: Cfg(kwargs).inherit_many(*def_args, **def_kwargs)})

    return _builder


# Main Chart configuration groups.
Chart = _make_chart_cfg("chart")
Colors = lambda colors: Cfg({"colors": colors}
                            )  # Colors is an array and not an option group
Credits = _make_chart_cfg("credits")
Exporting = _make_chart_cfg("exporting")
Labels = _make_chart_cfg("labels")
Legend = _make_chart_cfg("legend")
Loading = _make_chart_cfg("loading")
Pane = _make_chart_cfg("pane")
Navigation = _make_chart_cfg("navigation")
Navigator = _make_chart_cfg("navigator")
PlotOptions = _make_chart_cfg("plot_options")
RangeSelector = _make_chart_cfg("range_selector")
Scrollbar = _make_chart_cfg("scrollbar")
Subtitle = _make_chart_cfg("subtitle")
Title = _make_chart_cfg("title")
Tooltip = _make_chart_cfg("tooltip")
TooltipPct = _make_chart_cfg(
示例#13
0
    def render_html(self,
                    pretty=True,
                    static_output=False,
                    header_block=None,
                    footer_block=None):
        """Returns html output of the block
        :param pretty: Toggles pretty printing of the resulting HTML. Not applicable for non-HTML output.
        :param static_output: Passed down to _write_block. Will render static version of blocks which support this.
        :param header_block: If not None, header is inlined into a HTML body as table.
        :param footer_block: If not None, header is inlined into a HTML body as table.
        :return html-code of the block
        """
        # Render the contents
        html = root("html", doctype="html")
        head = append_to(html, "head")
        append_to(head, "meta", charset='utf-8')

        body = append_to(html, "body")

        # Make sure that the main style sheet is always included
        resource_deps = DependencyTracker(default_css_main)

        # If header or footer are passed into this function, inline them in the following structure:
        #
        # <body>
        # <table>
        #    <thead><tr><td>Header html</td></tr></thead>
        #    <tfoot><tr><td>Footer html</td></tr></tfoot>
        #    <tbody><tr><td>Body html</td></tr></tbody>
        # </table>
        # </body>
        if header_block is not None or footer_block is not None:
            content_table = append_to(body, "table")
            if header_block is not None:
                header_thead = append_to(content_table, "thead")
                header_tr = append_to(header_thead, "tr")
                header_td = append_to(header_tr, "th")
                header_block._write_block(header_td,
                                          Cfg(),
                                          id_generator(),
                                          resource_deps=resource_deps,
                                          static_output=static_output)

            if footer_block is not None:
                footer_tfoot = append_to(content_table, "tfoot", id='footer')
                footer_tr = append_to(footer_tfoot, "tr")
                footer_td = append_to(footer_tr, "td")
                footer_block._write_block(footer_td,
                                          Cfg(),
                                          id_generator(),
                                          resource_deps=resource_deps,
                                          static_output=static_output)

            body_tbody = append_to(content_table, "tbody")
            body_tr = append_to(body_tbody, "tr")
            body_td = append_to(body_tr, "td")
            self._write_block(body_td,
                              Cfg(),
                              id_generator(),
                              resource_deps=resource_deps,
                              static_output=static_output)
        else:
            self._write_block(body,
                              Cfg(),
                              id_generator(),
                              resource_deps=resource_deps,
                              static_output=static_output)

        script_inflate.write(head)
        script_block_core.write(head)

        if static_output:
            # Add the load wait poller if there are any JS resources
            js_elem(body, "var loadWaitPoller=runWaitPoller();")

        # Write out resources
        for res in resource_deps:
            res.write(head)

        # Render the whole document (the parent of the html tag)
        content = render(html.parent, pretty=pretty)
        return content
示例#14
0
 def _write_contents(self, container, actual_cfg, *args, **kwargs):
     for content in self._contents:
         content._write_block(container,
                              actual_cfg if self._cascade_cfg else Cfg(),
                              *args, **kwargs)
示例#15
0
 def _write_contents(self, container, actual_cfg, *args, **kwargs):
     for content in self._contents:
         cell = append_to(container, "div")
         content._write_block(cell,
                              actual_cfg if self._cascade_cfg else Cfg(),
                              *args, **kwargs)