Exemplo n.º 1
0
    def to_svg_group(self, width=None, height=None):
        """
        Render this chart to an SVG group element.

        This can then be placed inside an :code:`<svg>` tag to make a complete
        SVG graphic.

        See :meth:`.Chart.to_svg` for arguments.
        """
        width = width or theme.default_width
        height = height or theme.default_height

        if not self._layers:
            raise ValueError(
                'You must add at least one series to the chart before rendering.'
            )

        if isinstance(theme.margin, float):
            default_margin = width * theme.margin

            margin = Box(top=default_margin,
                         right=default_margin,
                         bottom=default_margin,
                         left=default_margin)
        elif isinstance(margin, int):
            margin = Box(margin, margin, margin, margin)
        elif not isinstance(margin, Box):
            margin = Box(*margin)

        # Root / background
        root_group = ET.Element('g')

        root_group.append(
            ET.Element('rect',
                       x=six.text_type(0),
                       y=six.text_type(0),
                       width=six.text_type(width),
                       height=six.text_type(height),
                       fill=theme.background_color))

        # Margins
        margin_group = ET.Element('g')
        margin_group.set('transform', svg.translate(margin.left, margin.top))

        margin_width = width - (margin.left + margin.right)
        margin_height = height - (margin.top + margin.bottom)

        root_group.append(margin_group)

        # Header
        header_group = ET.Element('g')

        header_margin = 0

        if self._title:
            label = ET.Element('text',
                               x=six.text_type(0),
                               y=six.text_type(0),
                               fill=theme.title_color)
            label.set('font-family', theme.title_font_family)
            label.set('font-size', six.text_type(theme.title_font_size))
            label.text = six.text_type(self._title)

            header_group.append(label)
            header_margin += theme.title_font_char_height + theme.title_gap

        # Legend
        if len(self._layers) > 1 or isinstance(self._layers[0][0],
                                               CategorySeries):
            legend_group = ET.Element('g')
            legend_group.set('transform', svg.translate(0, header_margin))

            indent = 0
            rows = 1
            palette = self._palette()

            for series, shape in self._layers:
                for item_group, item_width in shape.legend_to_svg(
                        series, palette):
                    if indent + item_width > width:
                        indent = 0
                        rows += 1

                    y = (rows - 1) * (theme.legend_font_char_height +
                                      theme.legend_gap)
                    item_group.set('transform', svg.translate(indent, y))

                    indent += item_width

                    legend_group.append(item_group)

            legend_height = rows * (theme.legend_font_char_height +
                                    theme.legend_gap)

            header_margin += legend_height
            header_group.append(legend_group)

        margin_group.append(header_group)

        # Body
        body_group = ET.Element('g')
        body_group.set('transform', svg.translate(0, header_margin))

        body_width = margin_width
        body_height = margin_height - header_margin

        margin_group.append(body_group)

        # Axes
        x_scale, x_axis = self._validate_dimension(X)
        y_scale, y_axis = self._validate_dimension(Y)

        bottom_margin = x_axis.estimate_label_margin(x_scale, 'bottom')
        left_margin = y_axis.estimate_label_margin(y_scale, 'left')

        canvas_width = body_width - left_margin
        canvas_height = body_height - bottom_margin

        axes_group = ET.Element('g')
        axes_group.set('transform', svg.translate(left_margin, 0))

        axes_group.append(
            x_axis.to_svg(canvas_width, canvas_height, x_scale, 'bottom'))
        axes_group.append(
            y_axis.to_svg(canvas_width, canvas_height, y_scale, 'left'))

        header_group.set('transform', svg.translate(left_margin, 0))

        body_group.append(axes_group)

        # Series
        series_group = ET.Element('g')

        palette = self._palette()

        for series, shape in self._layers:
            series_group.append(
                shape.to_svg(canvas_width, canvas_height, x_scale, y_scale,
                             series, palette))

        axes_group.append(series_group)

        return root_group
Exemplo n.º 2
0
    def to_svg(self, path=None, width=None, height=None):
        """
        Render the grid to an SVG.

        The :code:`width` and :code:`height` arguments refer to the size of the
        entire grid. The size of individual charts will be inferred
        automatically.

        See :meth:`.Chart.to_svg` for arguments.
        """
        if not width or not height:
            count = len(self._charts)

            columns = math.ceil(math.sqrt(count))
            rows = math.ceil(count / columns)

            width = columns * theme.default_chart_width
            height = rows * theme.default_chart_height

        root = ET.Element('svg',
            width=six.text_type(width),
            height=six.text_type(height),
            version='1.1',
            xmlns='http://www.w3.org/2000/svg'
        )

        # Root /  background
        root_group = ET.Element('g')

        root_group.append(ET.Element('rect',
            x=six.text_type(0),
            y=six.text_type(0),
            width=six.text_type(width),
            height=six.text_type(height),
            fill=theme.background_color
        ))

        root.append(root_group)

        # Charts
        grid_group = ET.Element('g')

        chart_count = len(self._charts)
        grid_width = math.ceil(math.sqrt(chart_count))
        grid_height = math.ceil(chart_count / grid_width)
        chart_width = width / grid_width
        chart_height = height / grid_height

        for i, chart in enumerate(self._charts):
            x = (i % grid_width) * chart_width
            y = math.floor(i / grid_width) * chart_height

            group = ET.Element('g')
            group.set('transform', svg.translate(x, y))

            chart = chart.to_svg_group(chart_width, chart_height)
            group.append(chart)

            grid_group.append(group)

        root_group.append(grid_group)

        svg_text = svg.stringify(root)
        close = True

        if path:
            try:
                if hasattr(path, 'write'):
                    f = path
                    close = False
                else:
                    dirpath = os.path.dirname(path)

                    if dirpath and not os.path.exists(dirpath):
                        os.makedirs(dirpath)

                    f = open(path, 'w')

                f.write(svg.HEADER)
                f.write(svg_text)
            finally:
                if close and f is not None:
                    f.close()
        else:
            return IPythonSVG(svg_text)
Exemplo n.º 3
0
    def to_svg_group(self, width=None, height=None):
        """
        Render this chart to an SVG group element.

        This can then be placed inside an :code:`<svg>` tag to make a complete
        SVG graphic.

        See :meth:`.Chart.to_svg` for arguments.
        """
        width = width or theme.default_width
        height = height or theme.default_height

        if not self._layers:
            raise ValueError('You must add at least one series to the chart before rendering.')

        if isinstance(theme.margin, float):
            default_margin = width * theme.margin

            margin = Box(
                top=default_margin,
                right=default_margin,
                bottom=default_margin,
                left=default_margin
            )
        elif isinstance(margin, int):
            margin = Box(margin, margin, margin, margin)
        elif not isinstance(margin, Box):
            margin = Box(*margin)

        # Root / background
        root_group = ET.Element('g')

        root_group.append(ET.Element('rect',
            x=six.text_type(0),
            y=six.text_type(0),
            width=six.text_type(width),
            height=six.text_type(height),
            fill=theme.background_color
        ))

        # Margins
        margin_group = ET.Element('g')
        margin_group.set('transform', svg.translate(margin.left, margin.top))

        margin_width = width - (margin.left + margin.right)
        margin_height = height - (margin.top + margin.bottom)

        root_group.append(margin_group)

        # Header
        header_group = ET.Element('g')

        header_margin = 0

        if self._title:
            label = ET.Element('text',
                x=six.text_type(0),
                y=six.text_type(0),
                fill=theme.title_color
            )
            label.set('font-family', theme.title_font_family)
            label.set('font-size', six.text_type(theme.title_font_size))
            label.text = six.text_type(self._title)

            header_group.append(label)
            header_margin += theme.title_font_char_height + theme.title_gap

        if not self._legend:
            if len(self._layers) > 1:
                self._legend = Legend()

        if self._legend:
            legend_group, legend_height = self._legend.to_svg(margin_width, self._layers)
            legend_group.set('transform', svg.translate(0, header_margin))

            header_margin += legend_height
            header_group.append(legend_group)

        margin_group.append(header_group)

        # Body
        body_group = ET.Element('g')
        body_group.set('transform', svg.translate(0, header_margin))

        body_width = margin_width
        body_height = margin_height - header_margin

        margin_group.append(body_group)

        # Axes
        x_scale, x_axis = self._validate_dimension(X)
        y_scale, y_axis = self._validate_dimension(Y)

        bottom_margin = x_axis.estimate_label_margin(x_scale, 'bottom')
        left_margin = y_axis.estimate_label_margin(y_scale, 'left')

        canvas_width = body_width - left_margin
        canvas_height = body_height - bottom_margin

        axes_group = ET.Element('g')
        axes_group.set('transform', svg.translate(left_margin, 0))

        axes_group.append(x_axis.to_svg(canvas_width, canvas_height, x_scale, 'bottom'))
        axes_group.append(y_axis.to_svg(canvas_width, canvas_height, y_scale, 'left'))

        header_group.set('transform', svg.translate(left_margin, 0))

        body_group.append(axes_group)

        # Series
        series_group = ET.Element('g')

        for series in self._layers:
            series_group.append(series.to_svg(canvas_width, canvas_height, x_scale, y_scale))

        axes_group.append(series_group)

        return root_group
Exemplo n.º 4
0
    def to_svg(self, path=None, width=None, height=None):
        """
        Render the grid to an SVG.

        The :code:`width` and :code:`height` arguments refer to the size of the
        entire grid. The size of individual charts will be inferred
        automatically.

        See :meth:`.Chart.to_svg` for arguments.
        """
        if not width or not height:
            count = len(self._charts)

            columns = math.ceil(math.sqrt(count))
            rows = math.ceil(count / columns)

            width = columns * theme.default_chart_width
            height = rows * theme.default_chart_height

        root = ET.Element('svg',
                          width=six.text_type(width),
                          height=six.text_type(height),
                          version='1.1',
                          xmlns='http://www.w3.org/2000/svg')

        # Root /  background
        root_group = ET.Element('g')

        root_group.append(
            ET.Element('rect',
                       x=six.text_type(0),
                       y=six.text_type(0),
                       width=six.text_type(width),
                       height=six.text_type(height),
                       fill=theme.background_color))

        root.append(root_group)

        # Charts
        grid_group = ET.Element('g')

        chart_count = len(self._charts)
        grid_width = math.ceil(math.sqrt(chart_count))
        grid_height = math.ceil(chart_count / grid_width)
        chart_width = width / grid_width
        chart_height = height / grid_height

        for i, chart in enumerate(self._charts):
            x = (i % grid_width) * chart_width
            y = math.floor(i / grid_width) * chart_height

            group = ET.Element('g')
            group.set('transform', svg.translate(x, y))

            chart = chart.to_svg_group(chart_width, chart_height)
            group.append(chart)

            grid_group.append(group)

        root_group.append(grid_group)

        svg_text = svg.stringify(root)
        close = True

        if path:
            try:
                if hasattr(path, 'write'):
                    f = path
                    close = False
                else:
                    dirpath = os.path.dirname(path)

                    if dirpath and not os.path.exists(dirpath):
                        os.makedirs(dirpath)

                    f = open(path, 'w')

                f.write(svg.HEADER)
                f.write(svg_text)
            finally:
                if close and f is not None:
                    f.close()
        else:
            return IPythonSVG(svg_text)
Exemplo n.º 5
0
    def to_svg(self, width, series_list):
        """
        Render a legend series list and return it for embedding in an SVG.
        """
        legend_group = ET.Element('g')

        bubble_width = theme.legend_bubble_size + theme.legend_bubble_offset

        rows = 1
        indent = 0

        for i, series in enumerate(series_list):
            text = six.text_type(series._name or 'Series %i' % i)
            text_width = (len(text) + 4) * theme.legend_font_char_width

            if indent + text_width + bubble_width > width:
                indent = 0
                rows += 1

            y = (rows - 1) * (theme.legend_font_char_height + theme.legend_gap)

            # Group
            item_group = ET.Element('g')
            item_group.set('transform', svg.translate(indent, y))

            fill_color = getattr(series._shape, '_fill_color', None)
            stroke_color = getattr(series._shape, '_stroke_color', None)

            if callable(fill_color):
                # TODO
                fill_color = 'black'

            # Bubble
            bubble = ET.Element('rect',
                x=six.text_type(0),
                y=six.text_type(-theme.legend_font_char_height + theme.legend_bubble_offset),
                width=six.text_type(theme.legend_bubble_size),
                height=six.text_type(theme.legend_bubble_size)
            )

            if fill_color:
                bubble.set('fill', fill_color)
            elif stroke_color:
                bubble.set('fill', stroke_color)

            item_group.append(bubble)

            # Label
            label = ET.Element('text',
                x=six.text_type(bubble_width),
                y=six.text_type(0),
                fill=theme.legend_color
            )
            label.set('font-family', theme.legend_font_family)
            label.set('font-size', six.text_type(theme.legend_font_size))
            label.text = text

            item_group.append(label)

            legend_group.append(item_group)
            indent += text_width + bubble_width

        height = rows * (theme.legend_font_char_height + theme.legend_gap)

        return (legend_group, height)
Exemplo n.º 6
0
    def to_svg(self, width, series_list):
        """
        Render a legend series list and return it for embedding in an SVG.
        """
        legend_group = ET.Element('g')

        bubble_width = theme.legend_bubble_size + theme.legend_bubble_offset

        rows = 1
        indent = 0

        for i, series in enumerate(series_list):
            text = six.text_type(series._name or 'Series %i' % i)
            text_width = (len(text) + 4) * theme.legend_font_char_width

            if indent + text_width + bubble_width > width:
                indent = 0
                rows += 1

            y = (rows - 1) * (theme.legend_font_char_height + theme.legend_gap)

            # Group
            item_group = ET.Element('g')
            item_group.set('transform', svg.translate(indent, y))

            fill_color = getattr(series._shape, '_fill_color', None)
            stroke_color = getattr(series._shape, '_stroke_color', None)

            if callable(fill_color):
                # TODO
                fill_color = 'black'

            # Bubble
            bubble = ET.Element(
                'rect',
                x=six.text_type(0),
                y=six.text_type(-theme.legend_font_char_height +
                                theme.legend_bubble_offset),
                width=six.text_type(theme.legend_bubble_size),
                height=six.text_type(theme.legend_bubble_size))

            if fill_color:
                bubble.set('fill', fill_color)
            elif stroke_color:
                bubble.set('fill', stroke_color)

            item_group.append(bubble)

            # Label
            label = ET.Element('text',
                               x=six.text_type(bubble_width),
                               y=six.text_type(0),
                               fill=theme.legend_color)
            label.set('font-family', theme.legend_font_family)
            label.set('font-size', six.text_type(theme.legend_font_size))
            label.text = text

            item_group.append(label)

            legend_group.append(item_group)
            indent += text_width + bubble_width

        height = rows * (theme.legend_font_char_height + theme.legend_gap)

        return (legend_group, height)