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 rect = self.buildData('axis_rect') half_size = self.maximumBarSize() / 2.0 for dataset, item in items.items(): path = QPainterPath() subpaths = [] for value in dataset.values(): pos = self.pointAt(axes, value) radius = min(rect.bottom() - pos.y(), 8) subpath = QPainterPath() # create a vertical bar graph if self.orientation() == Qt.Vertical: subpath.moveTo(pos.x() - half_size, rect.bottom()) subpath.lineTo(pos.x() - half_size, pos.y() + radius) subpath.quadTo(pos.x() - half_size, pos.y(), pos.x() - half_size + radius, pos.y()) subpath.lineTo(pos.x() + half_size - radius, pos.y()) subpath.quadTo(pos.x() + half_size, pos.y(), pos.x() + half_size, pos.y() + radius) subpath.lineTo(pos.x() + half_size, rect.bottom()) subpath.lineTo(pos.x() - half_size, rect.bottom()) # create a horizontal bar graph else: subpath.moveTo(rect.left(), pos.y() - half_size) subpath.lineTo(pos.x(), pos.y() - half_size) subpath.lineTo(pos.x(), pos.y() + half_size) subpath.lineTo(rect.left(), pos.y() + half_size) subpath.lineTo(rect.left(), pos.y() - half_size) path.addPath(subpath) subpaths.append(subpath) item.setPath(path) item.setBuildData('subpaths', subpaths)
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
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