diff --git a/python/graph_item.py b/python/graph_item.py index 64babb74203b536e60ed0f8c33ebc3061464ccc0..7e8e0922e9281a6114257f4597e94b934ea54998 100644 --- a/python/graph_item.py +++ b/python/graph_item.py @@ -44,7 +44,7 @@ class GraphItem(): if right_edge > x: x = right_edge for view in self.views: - right_edge = view.shape().boundingRect().right() + right_edge = view.x() + view.shape().boundingRect().right() if right_edge > x: x = right_edge return x diff --git a/python/mp_code_io_manager.py b/python/mp_code_io_manager.py index ce6759c9c9f8bd73fd4a953dfffe6a8e1ea27155..fa2607aafbc4c03b224c0e4d580572704ea7612a 100644 --- a/python/mp_code_io_manager.py +++ b/python/mp_code_io_manager.py @@ -97,13 +97,13 @@ def read_generated_json(generated_json_text): pass # item 1 or 2: dict containing SAY key or view_object dict - for say_or_report_json in generated_json["GLOBAL"][1:]: - if "SAY" in say_or_report_json: + for say_or_generated_json_view in generated_json["GLOBAL"][1:]: + if "SAY" in say_or_generated_json_view: # SAY item - generated_global_views["SAY"] = say_or_report_json + generated_global_views["SAY"] = say_or_generated_json_view else: # view_object dict - generated_global_views.update(say_or_report_json) + generated_global_views.update(say_or_generated_json_view) # build graph item from the global view graph_index = 0 # sorts to top @@ -184,12 +184,10 @@ def read_generated_json(generated_json_text): elif isinstance(type_specific_element, dict) \ and len(type_specific_element) == 1 \ and "VIEWS" in type_specific_element: - if type_specific_element["VIEWS"]: - generated_views = type_specific_element["VIEWS"][0] - json_views = make_json_views(generated_views) - else: - # empty VIEWS dict - pass + generated_json_views = dict() + for generated_json_view in type_specific_element["VIEWS"]: + generated_json_views.update(generated_json_view) + json_views = make_json_views(generated_json_views) else: print("Unexpected input:", type_specific_element) diff --git a/python/views/bar_chart.py b/python/views/bar_chart.py new file mode 100644 index 0000000000000000000000000000000000000000..6139512fdc43c1b4db48ab79d3ce4e1e3ed11fdd --- /dev/null +++ b/python/views/bar_chart.py @@ -0,0 +1,127 @@ +from PyQt5.QtCore import QPoint, QRectF, Qt +from PyQt5.QtGui import QPainterPath +from PyQt5.QtGui import QFontMetrics +from PyQt5.QtGui import QFont +from PyQt5.QtWidgets import QGraphicsItem +from next_graphics_index import next_graphics_index + +MAX_BAR_H = 100 + +def _text_width(text): + fm = QFontMetrics(QFont()) # use default font since we do not set it + return fm.horizontalAdvance(text) + +class BarChart(QGraphicsItem): + Type = next_graphics_index() + + def __init__(self, json_data, default_x, default_y): + super(BarChart, self).__init__() + + # graphicsItem mode + self.setFlag(QGraphicsItem.ItemIsMovable) + self.setFlag(QGraphicsItem.ItemIsSelectable) + self.setZValue(2) + + # json_data + self._json_data = json_data # keep for export + + # x,y + if json_data["x"] == 0 and json_data["y"] == 0: + self.setPos(QPoint(default_x, default_y)) + else: + self.setPos(QPoint(json_data["x"], json_data["y"])) + + # graph data + data = json_data["data"] + + # title, headers + self.title = data["title"] + self.headers = data["tabs"] + self.bar_header = self.headers[0] + self.value_header = self.headers[1] + + # header width + self.value_header_width = _text_width(self.value_header) + 4 + self.bar_header_width = _text_width(self.bar_header) + 4 + self.header_width = max([self.value_header_width, + self.bar_header_width]) + + # bar names, values, normalized heights, width, max height + bars = data["rows"] + self.bar_names = list() + self.bar_values = list() + self.bar_width = 0 + for bar in bars: + bar_name, bar_value = bar + self.bar_names.append(bar_name) + self.bar_values.append(bar_value) + w = _text_width(bar_name) + if w > self.bar_width: + self.bar_width = w + if self.bar_values: + self.bar_heights = list() + max_height = max(self.bar_values) + for bar_value in self.bar_values: + self.bar_heights.append(int(bar_value * MAX_BAR_H / max_height)) + + # bar chart width, height + self.bar_chart_w = self.header_width + len(bars) * self.bar_width + self.bar_chart_h = 60 + MAX_BAR_H + + # rectangle for mouse sense + self.bounding_path = QPainterPath() + self.bounding_path.addRect(QRectF(0, 0, + self.bar_chart_w, self.bar_chart_h)) + + def json_data(self): + self._json_data["x"] = self.x() + self._json_data["y"] = self.y() + return self._json_data + + def type(self): + return BarChart.Type + + # draw inside this rectangle + def boundingRect(self): + return self.bounding_path.boundingRect().adjusted(-1, -1, 1, 1) + + # mouse hovers when inside this rectangle + def shape(self): + return self.bounding_path + + def paint(self, painter, _option, _widget): + + # title + painter.drawText(QRectF(0, 5, self.bar_chart_w, 20), Qt.AlignCenter, + self.title) + + # headers + painter.drawText(QRectF(0, self.bar_chart_h - 20, + self.value_header_width, 20), + Qt.AlignCenter, self.bar_header) + painter.drawText(QRectF(0, self.bar_chart_h - 40, + self.value_header_width, 20), + Qt.AlignCenter, self.value_header) + + # bar names + for i in range(len(self.bar_names)): + painter.drawText(QRectF(self.header_width + self.bar_width * i, + self.bar_chart_h - 20, + self.bar_width, + 20), + Qt.AlignCenter, self.bar_names[i]) + + # bar value labels + for i in range(len(self.bar_values)): + painter.drawText(QRectF(self.header_width + self.bar_width * i, + self.bar_chart_h - 40, + self.bar_width, + 20), + Qt.AlignCenter, "%s"%self.bar_values[i]) + + # bars + for i in range(len(self.bar_heights)): + x = self.header_width + self.bar_width * i + y = MAX_BAR_H - self.bar_heights[i] + 40 + painter.drawRect(x, y, self.bar_width, self.bar_heights[i]) + diff --git a/python/views/make_views.py b/python/views/make_views.py index 6023fb14426f54283c27cd8d0ce2c6e0142d4c6f..1907dc653dce395aee70ca843b0acbfcebbffa2c 100644 --- a/python/views/make_views.py +++ b/python/views/make_views.py @@ -9,8 +9,9 @@ from views.report import Report from views.table import Table from views.activity_diagram import ActivityDiagram from views.graph import Graph +from views.bar_chart import BarChart -VIEW_TYPES = {"REPORT", "TABLE", "AD", "GRAPH"} +VIEW_TYPES = {"REPORT", "TABLE", "AD", "GRAPH", "BAR_CHART"} def make_json_views(generated_views): """Convert trace-generator view data structures into structures with x,y positioning.""" @@ -42,6 +43,8 @@ def make_view(json_view, default_x, default_y): view = ActivityDiagram(json_view, default_x, default_y) elif json_view["type"] == "GRAPH": view = Graph(json_view, default_x, default_y) + elif json_view["type"] == "BAR_CHART": + view = BarChart(json_view, default_x, default_y) else: print("Unrecognized view type: %s"%view_type, json_view["type"])