Ejemplo n.º 1
0
    def rebuild(self):
        """
        Rebuilds the item based on the current points.
        """
        scene = self.scene()
        if not scene:
            return

        self._subpaths = []

        grid = scene.gridRect()
        typ = self.chartType()

        hruler = scene.horizontalRuler()
        vruler = scene.verticalRuler()

        path = QPainterPath()
        area = QPainterPath()

        self._buildData.clear()
        self._buildData['path_area'] = area

        self.setPos(0, 0)

        # draw a line item
        if typ == XChartScene.Type.Line:
            first = True
            pos = None
            home = None
            self._ellipses = []

            points = self.points()
            if (self.orientation() == Qt.Horizontal):
                points.sort(hruler.compareValues, key=lambda x: x[0])
            else:
                points.sort(vruler.compareValues, key=lambda y: y[1])
                points.reverse()

            for x, y in self.points():
                pos = scene.mapFromChart(x, y)
                if first:
                    home = QPointF(pos.x(), grid.bottom())
                    area.moveTo(home)
                    area.lineTo(pos)
                    path.moveTo(pos)

                    self._ellipses.append(pos)

                    first = False
                else:
                    path.lineTo(pos)
                    area.lineTo(pos)

                    self._ellipses.append(pos)

            if pos and home:
                area.lineTo(pos.x(), grid.bottom())
                area.lineTo(home)

        # draw a bar item
        elif typ == XChartScene.Type.Bar:
            barsize = self.barSize()
            horiz = self.orientation() == Qt.Horizontal

            for x, y in self.points():
                pos = scene.mapFromChart(x, y)
                subpath = QPainterPath()
                if horiz:
                    r = min(grid.bottom() - pos.y(), 8)

                    subpath.moveTo(pos.x() - barsize / 2.0, grid.bottom())
                    subpath.lineTo(pos.x() - barsize / 2.0, pos.y() + r)
                    subpath.quadTo(pos.x() - barsize / 2.0, pos.y(),
                                   pos.x() - barsize / 2.0 + r, pos.y())

                    subpath.lineTo(pos.x() + barsize / 2.0 - r, pos.y())
                    subpath.quadTo(pos.x() + barsize / 2.0, pos.y(),
                                   pos.x() + barsize / 2.0,
                                   pos.y() + r)

                    subpath.lineTo(pos.x() + barsize / 2.0, grid.bottom())
                    subpath.lineTo(pos.x() - barsize / 2.0, grid.bottom())
                else:
                    subpath.moveTo(grid.left(), pos.y() - barsize / 2.0)
                    subpath.lineTo(pos.x(), pos.y() - barsize / 2.0)
                    subpath.lineTo(pos.x(), pos.y() + barsize / 2.0)
                    subpath.lineTo(grid.left(), pos.y() + barsize / 2.0)
                    subpath.lineTo(grid.left(), pos.y() - barsize / 2.0)

                path.addPath(subpath)
                self._subpaths.append((x, y, subpath))

        # draw a pie chart
        elif typ == XChartScene.Type.Pie:
            if self.orientation() == Qt.Horizontal:
                key_index = 0
                value_index = 1
                value_ruler = self.verticalRuler()
            else:
                key_index = 1
                value_index = 0
                value_ruler = self.horizontalRuler()

            pie_values = {}

            for point in self.points():
                key = point[key_index]
                value = point[value_index]

                pie_values.setdefault(key, [])
                pie_values[key].append(value)

            for key, values in pie_values.items():
                pie_values[key] = value_ruler.calcTotal(values)

            total = max(1, value_ruler.calcTotal(pie_values.values()))

            # calculate drawing parameters
            center = self.pieCenter()
            radius = self.radius()
            diameter = radius * 2
            angle = 0
            bound = QRectF(-radius, -radius, diameter, diameter)

            for key, value in sorted(pie_values.items(), key=lambda x: x[1]):
                # calculate the percentage
                perc = float(value) / total

                # calculate the angle as the perc * 360
                item_angle = perc * 360
                self.setPos(center)

                sub_path = QPainterPath()
                sub_path.arcTo(bound, angle, item_angle)
                sub_path.lineTo(0, 0)

                path.addPath(sub_path)
                self._subpaths.append((key, value, sub_path))

                angle += item_angle

        self.setPath(path)
        self._dirty = False
Ejemplo n.º 2
0
    def calculateDatasets(self, scene, axes, datasets):
        """
        Builds the datasets for this renderer.  Each renderer will need to
        subclass and implemenent this method, otherwise, no data will be
        shown in the chart.
        
        :param      scene | <XChartScene>
                    axes | [<
                    datasets | [<XChartDataset>, ..]
        """
        items = self.calculateDatasetItems(scene, datasets)
        if not items:
            scene.clear()
            return

        xaxis = scene.chart().horizontalAxis()
        yaxis = scene.chart().verticalAxis()
        data_axis = None
        all_values = []

        # determine if we're mapping data aginst the sets themselves, in
        # which case, create a pie chart of the dataset vs. its
        if isinstance(xaxis, XDatasetAxis):
            per_dataset = False
            data_axis = yaxis
            total = 1

        elif isinstance(yaxis, XDatasetAxis):
            per_dataset = False
            total = 1
            data_axis = xaxis

        else:
            per_dataset = True
            total = len(items)

        if not per_dataset:
            all_values = [dataset.sum(data_axis) \
                          for dataset in datasets]

        # generate the build information
        rect = self.buildData('grid_rect')
        rect.setX(rect.x() + 10)
        rect.setY(rect.y() + 10)
        rect.setWidth(rect.width() - 20)
        rect.setHeight(rect.height() - 20)

        if rect.width() > rect.height():
            radius = min(rect.width() / 2.0, rect.height() / 2.0)
            x = rect.left()
            y = rect.top() + radius
            deltax = min(radius * 2, rect.width() / float(total + 1))
            deltay = 0
        else:
            radius = min(rect.height() / 2.0, rect.width() / 2.0)
            x = rect.left() + radius
            y = rect.top()
            deltax = 0
            deltay = min(radius * 2, rect.height() / float(total + 1))

        # initialize the first pie chart
        angle = 0
        cx = x + deltax
        cy = y + deltay

        x += deltax
        y += deltay

        self.setBuildData('center', QPointF(cx, cy))
        self.setBuildData('radius', radius)

        for dataset in datasets:
            item = items.get(dataset)
            if not item:
                continue

            item.setBuildData('center', QPointF(cx, cy))
            item.setBuildData('radius', radius)

            subpaths = []
            bound = QRectF(cx - radius, cy - radius, radius * 2, radius * 2)
            path = QPainterPath()
            if per_dataset:
                data_values = dataset.values(yaxis.name())
                andle = 0
                for value in dataset.values():
                    perc = yaxis.percentOfTotal(value.get(yaxis.name()),
                                                data_values)

                    # calculate the angle as the perc
                    item_angle = perc * 360

                    subpath = QPainterPath()
                    subpath.moveTo(cx, cy)
                    subpath.arcTo(bound, angle, item_angle)
                    subpath.lineTo(cx, cy)

                    path.addPath(subpath)
                    subpaths.append((value.get(xaxis.name()), subpath))

                    angle += item_angle

                cx = x + deltax
                cy = y + deltay

                x += deltax
                y += deltay
            else:
                value = dataset.sum(data_axis)
                perc = data_axis.percentOfTotal(value, all_values)

                # calculate the angle as the perc
                item_angle = perc * 360

                subpath = QPainterPath()
                subpath.moveTo(cx, cy)
                subpath.arcTo(bound, angle, item_angle)
                subpath.lineTo(cx, cy)

                path.addPath(subpath)
                subpaths.append((value, subpath))

                angle += item_angle

            item.setPath(path)
            item.setBuildData('subpaths', subpaths)
Ejemplo n.º 3
0
 def calculateDatasets(self, scene, axes, datasets):
     """
     Builds the datasets for this renderer.  Each renderer will need to
     subclass and implemenent this method, otherwise, no data will be
     shown in the chart.
     
     :param      scene | <XChartScene>
                 axes | [<
                 datasets | [<XChartDataset>, ..]
     """
     items = self.calculateDatasetItems(scene, datasets)
     if not items:
         scene.clear()
         return
     
     xaxis = scene.chart().horizontalAxis()
     yaxis = scene.chart().verticalAxis()
     data_axis = None
     all_values = []
     
     # determine if we're mapping data aginst the sets themselves, in
     # which case, create a pie chart of the dataset vs. its 
     if isinstance(xaxis, XDatasetAxis):
         per_dataset = False
         data_axis = yaxis
         total = 1
     
     elif isinstance(yaxis, XDatasetAxis):
         per_dataset = False
         total = 1
         data_axis = xaxis
     
     else:
         per_dataset = True
         total = len(items)
     
     if not per_dataset:
         all_values = [dataset.sum(data_axis) \
                       for dataset in datasets]
     
     # generate the build information
     rect = self.buildData('grid_rect')
     rect.setX(rect.x() + 10)
     rect.setY(rect.y() + 10)
     rect.setWidth(rect.width() - 20)
     rect.setHeight(rect.height() - 20)
     
     if rect.width() > rect.height():
         radius = min(rect.width() / 2.0, rect.height() / 2.0)
         x = rect.left()
         y = rect.top() + radius
         deltax = min(radius * 2, rect.width() / float(total + 1))
         deltay = 0
     else:
         radius = min(rect.height() / 2.0, rect.width() / 2.0)
         x = rect.left() + radius
         y = rect.top()
         deltax = 0
         deltay = min(radius * 2, rect.height() / float(total + 1))
     
     # initialize the first pie chart
     angle = 0
     cx = x + deltax
     cy = y + deltay
     
     x += deltax
     y += deltay
     
     self.setBuildData('center', QPointF(cx, cy))
     self.setBuildData('radius', radius)
     
     for dataset in datasets:
         item = items.get(dataset)
         if not item:
             continue
         
         item.setBuildData('center', QPointF(cx, cy))
         item.setBuildData('radius', radius)
         
         subpaths = []
         bound = QRectF(cx-radius, cy-radius, radius * 2, radius * 2)
         path = QPainterPath()
         if per_dataset:
             data_values = dataset.values(yaxis.name())
             andle = 0
             for value in dataset.values():
                 perc = yaxis.percentOfTotal(value.get(yaxis.name()),
                                             data_values)
                 
                 # calculate the angle as the perc
                 item_angle = perc * 360
                 
                 subpath = QPainterPath()
                 subpath.moveTo(cx, cy)
                 subpath.arcTo(bound, angle, item_angle)
                 subpath.lineTo(cx, cy)
                 
                 path.addPath(subpath)
                 subpaths.append((value.get(xaxis.name()), subpath))
                 
                 angle += item_angle
                 
             cx = x + deltax
             cy = y + deltay
             
             x += deltax
             y += deltay
         else:
             value = dataset.sum(data_axis)
             perc = data_axis.percentOfTotal(value, all_values)
             
             # calculate the angle as the perc
             item_angle = perc * 360
             
             subpath = QPainterPath()
             subpath.moveTo(cx, cy)
             subpath.arcTo(bound, angle, item_angle)
             subpath.lineTo(cx, cy)
             
             path.addPath(subpath)
             subpaths.append((value, subpath))
             
             angle += item_angle
             
         item.setPath(path)
         item.setBuildData('subpaths', subpaths)
Ejemplo n.º 4
0
 def rebuild( self ):
     """
     Rebuilds the item based on the current points.
     """
     scene       = self.scene()
     if not scene:
         return
     
     self._subpaths = []
     
     grid        = scene.gridRect()
     typ         = self.chartType()
     
     hruler      = scene.horizontalRuler()
     vruler      = scene.verticalRuler()
     
     path        = QPainterPath()
     area        = QPainterPath()
     
     self._buildData.clear()
     self._buildData['path_area'] = area
     
     self.setPos(0, 0)
     
     # draw a line item
     if typ == XChartScene.Type.Line:
         first = True
         pos   = None
         home  = None
         self._ellipses = []
         
         points = self.points()
         if ( self.orientation() == Qt.Horizontal ):
             points.sort(hruler.compareValues, key = lambda x: x[0])
         else:
             points.sort(vruler.compareValues, key = lambda y: y[1])
             points.reverse()
         
         for x, y in self.points():
             pos = scene.mapFromChart(x, y)
             if first:
                 home = QPointF(pos.x(), grid.bottom())
                 area.moveTo(home)
                 area.lineTo(pos)
                 path.moveTo(pos)
                 
                 self._ellipses.append(pos)
                 
                 first = False
             else:
                 path.lineTo(pos)
                 area.lineTo(pos)
                 
                 self._ellipses.append(pos)
         
         if pos and home:
             area.lineTo(pos.x(), grid.bottom())
             area.lineTo(home)
     
     # draw a bar item
     elif typ == XChartScene.Type.Bar:
         barsize = self.barSize()
         horiz   = self.orientation() == Qt.Horizontal
         
         for x, y in self.points():
             pos = scene.mapFromChart(x, y)
             subpath = QPainterPath()
             if horiz:
                 r = min(grid.bottom() - pos.y(), 8)
                 
                 subpath.moveTo(pos.x() - barsize / 2.0, grid.bottom())
                 subpath.lineTo(pos.x() - barsize / 2.0, pos.y() + r)
                 subpath.quadTo(pos.x() - barsize / 2.0, pos.y(),
                                pos.x() - barsize / 2.0 + r, pos.y())
                 
                 subpath.lineTo(pos.x() + barsize / 2.0 - r, pos.y())
                 subpath.quadTo(pos.x() + barsize / 2.0, pos.y(),
                                pos.x() + barsize / 2.0, pos.y() + r)
                 
                 subpath.lineTo(pos.x() + barsize / 2.0, grid.bottom())
                 subpath.lineTo(pos.x() - barsize / 2.0, grid.bottom())
             else:
                 subpath.moveTo(grid.left(), pos.y() - barsize / 2.0)
                 subpath.lineTo(pos.x(),     pos.y() - barsize / 2.0)
                 subpath.lineTo(pos.x(),     pos.y() + barsize / 2.0)
                 subpath.lineTo(grid.left(), pos.y() + barsize / 2.0)
                 subpath.lineTo(grid.left(), pos.y() - barsize / 2.0)
             
             path.addPath(subpath)
             self._subpaths.append((x, y, subpath))
     
     # draw a pie chart
     elif typ == XChartScene.Type.Pie:
         if self.orientation() == Qt.Horizontal:
             key_index   = 0
             value_index = 1
             value_ruler = self.verticalRuler()
         else:
             key_index   = 1
             value_index = 0
             value_ruler = self.horizontalRuler()
     
         pie_values = {}
         
         for point in self.points():
             key     = point[key_index]
             value   = point[value_index]
             
             pie_values.setdefault(key, [])
             pie_values[key].append(value)
     
         for key, values in pie_values.items():
             pie_values[key] = value_ruler.calcTotal(values)
         
         total = max(1, value_ruler.calcTotal(pie_values.values()))
         
         # calculate drawing parameters
         center   = self.pieCenter()
         radius   = self.radius()
         diameter = radius * 2
         angle    = 0
         bound    = QRectF(-radius, -radius, diameter, diameter)
         
         for key, value in sorted(pie_values.items(), key = lambda x: x[1]):
             # calculate the percentage
             perc  = float(value) / total
             
             # calculate the angle as the perc * 360
             item_angle = perc * 360
             self.setPos(center)
             
             sub_path = QPainterPath()
             sub_path.arcTo(bound, angle, item_angle)
             sub_path.lineTo(0, 0)
             
             path.addPath(sub_path)
             self._subpaths.append((key, value, sub_path))
             
             angle += item_angle
             
     self.setPath(path)
     self._dirty = False