def __init__(self, pydisplay, event_handler): super().__init__(pydisplay, event_handler, "Buttons", (400, 300), Colors.BLACK) self.button = Drawables.Button(50, 50, 100, 50, "Hello", 25, Colors.WHITE, Colors.BLUE, callback=self.button_callback) self.textBox = Drawables.Text(50, 110, "textbox here", 15, Colors.RED, Drawables.Text.ALIGN_X_CENTER, Drawables.Text.ALIGN_Y_CENTER, rotate=90) self.textBox2 = Drawables.Text(200, 100, "textbox here", 15, Colors.WHITE, Drawables.Text.ALIGN_X_RIGHT, Drawables.Text.ALIGN_Y_TOP) self._drawables.append(self.button) self._drawables.append(self.textBox) self._drawables.append(self.textBox2) self._event_handler.register_event(object, Events.EventTypes.BUTTON_HOLD, self.button_27_callback)
def set_y_label(self, text, distance_from_left_of_graph=5, font_size=15, fg_color=None): """ Set the y label (this will be rotated and centered on the left of the chart) :param text: Text to display :param distance_from_left_of_graph: Distance top of text (upward direction of letters) is from left of graph :param font_size: Font size :param fg_color: Font color :return: None """ x = self.x + distance_from_left_of_graph y = self.y + self._plot["offset_y"] + self._plot["height"] / 2 fg_color = self._plot["fg_color"] if fg_color is None else fg_color self._drawables["y_label"] = Drawables.Text( x=x, y=y, text=text, font_size=font_size, fg_color=fg_color, align_x=Drawables.Text.ALIGN_X_LEFT, align_y=Drawables.Text.ALIGN_Y_CENTER, rotate=90)
def set_title(self, text, distance_from_top_of_graph=5, font_size=20, fg_color=None): """ Set the title of the graph. :param text: The text to display :param distance_from_top_of_graph: Distance top of text is from the top of graph :param font_size: Font size :param fg_color: Font color :return: None """ fg_color = self._plot["fg_color"] if fg_color is None else fg_color self._drawables["title"] = Drawables.Text( x=self.width / 2, y=self.y + distance_from_top_of_graph, text=text, font_size=font_size, fg_color=fg_color, align_x=Drawables.Text.ALIGN_X_CENTER, align_y=Drawables.Text.ALIGN_Y_TOP)
def set_x_label(self, text, distance_from_bottom_of_graph=5, font_size=15, fg_color=None): """ Set the x label (this will be centered at the bottom of the chart) :param text: Text to display :param distance_from_bottom_of_graph: Distance bottom of text is from bottom of graph :param font_size: Font size :param fg_color: Font color :return: None """ x = self.x + self._plot["offset_x"] + self._plot["width"] / 2 y = self.y + self.height - distance_from_bottom_of_graph fg_color = self._plot["fg_color"] if fg_color is None else fg_color self._drawables["x_label"] = Drawables.Text( x=x, y=y, text=text, font_size=font_size, fg_color=fg_color, align_x=Drawables.Text.ALIGN_X_CENTER, align_y=Drawables.Text.ALIGN_Y_BOTTOM)
def set_bounds(self, x_min=None, x_max=None, x_interval=None, y_min=None, y_max=None, y_interval=None): """ Set bounds for the two axes and the tick interval. This does a lot of the calculations and creates the Drawables that are needed for the plot (axes, ticks, tick labels). Call this method again when any of the bounds change. :param x_min: Minimum x value :param x_max: Maximum x value (must be greater than x_min) :param x_interval: Amount between tick marks on x axis (must be greater than 0) :param y_min: Minimum y value :param y_max: Maximum y value (must be greater than y_min) :param y_interval: Amount between tick marks on y axis (must be greater than 0) :return: None """ if x_min is None: x_min = self._axis["x_min"] if x_max is None: x_max = self._axis["x_max"] if x_interval is None: x_interval = self._axis["x_interval"] if y_min is None: y_min = self._axis["y_min"] if y_max is None: y_max = self._axis["y_max"] if y_interval is None: y_interval = self._axis["y_interval"] # Make sure the inputs are reasonable assert x_max > x_min and x_interval > 0, (x_min, x_max, x_interval) assert y_max > y_min and y_interval > 0, (y_min, y_max, y_interval) # Store the variables self._axis["x_min"] = x_min self._axis["x_max"] = x_max self._axis["x_interval"] = x_interval self._axis["y_min"] = y_min self._axis["y_max"] = y_max self._axis["y_interval"] = y_interval # Some local variables plot_x = self.x + self._plot["offset_x"] plot_y = self.y + self._plot["offset_y"] width = self._plot["width"] height = self._plot["height"] # Reset the drawables self._drawables["x_ticks"] = [] self._drawables["x_numbers"] = [] self._drawables["y_ticks"] = [] self._drawables["y_numbers"] = [] # Figure out the axes self._axis_value_calculate() self._drawables["x_axis"] = Drawables.Line(plot_x, self._axis["x_axis_y"], width, 0, self._plot["fg_color"]) self._drawables["y_axis"] = Drawables.Line(self._axis["y_axis_x"], plot_y, 0, height, self._plot["fg_color"]) self.update_distance_between_ticks() # Figure out x tick marks x_ticks_x, x_ticks_values = self.tick_marks(x_min, x_max, x_interval, 0) for tick_x, tick_value in zip(x_ticks_x, x_ticks_values): self._drawables["x_ticks"].append( Drawables.Line(tick_x, plot_y + height - 4, 0, 4, self._plot["fg_color"])) self._drawables["x_numbers"].append( Drawables.Text(x=tick_x, y=plot_y + height + 2, text=str(tick_value), font_size=12, fg_color=self._plot["fg_color"], align_x=Drawables.Text.ALIGN_X_CENTER, align_y=Drawables.Text.ALIGN_Y_TOP)) # Figure out y tick marks y_ticks_y, y_ticks_values = self.tick_marks(y_min, y_max, y_interval, 1) for tick_y, tick_value in zip(y_ticks_y, y_ticks_values): self._drawables["y_ticks"].append( Drawables.Line(plot_x, tick_y, 4, 0, self._plot["fg_color"])) self._drawables["y_numbers"].append( Drawables.Text(x=plot_x - 2, y=tick_y, text=str(tick_value), font_size=12, fg_color=self._plot["fg_color"], align_x=Drawables.Text.ALIGN_X_RIGHT, align_y=Drawables.Text.ALIGN_Y_CENTER))
def add_datum(self, values): """ Add new datum. This will automatically add the datum to the chart and draw a new row for this. After the data point is added, the chart is resorted as desired (set the sorting scheme using add_sorting_scheme; default is FIFO so new data appears at the bottom). :param values: A dictionary of values (must have the same keys as the names of the columns and must have a key/value pair for every column. :return: None """ assert isinstance(values, dict) and values.keys() == self.datasets.keys() # Mark that you can't add more datasets self._can_add_more_datasets = False # Extend old vertical lines for vertical in self._drawables["vertical"]: vertical.height += self._cell_heights # Add extra horizontal line horizontal_y = self.y + (max( [len(dataset["data"]) for dataset in self.datasets.values()]) + 2) * self._cell_heights horizontal_width = sum( [dataset["cell_width"] for dataset in self.datasets.values()]) self._drawables["horizontal"].append( Drawables.Line(self.x, horizontal_y, horizontal_width, 0, color=self._fg_color)) # Add text for the new row's data column_x = self.x for i, (dataset_name, value) in enumerate(values.items()): dataset = self.datasets[dataset_name] x_values = { Drawables.Text.ALIGN_X_LEFT: column_x + dataset["pad"], Drawables.Text.ALIGN_X_CENTER: column_x + dataset["cell_width"] / 2, Drawables.Text.ALIGN_X_RIGHT: column_x + dataset["cell_width"] - dataset["pad"] } y_value = self.y + (len(dataset["data"]) + 1.5) * self._cell_heights dataset["data"].append(value) dataset["insertion_order"].append( max(dataset["insertion_order"]) + 1) data_text = Drawables.Text(x_values[dataset["data_align_x"]], y_value, dataset["formatting"].format(value), dataset["data_font_size"], fg_color=dataset["font_color"], align_x=dataset["data_align_x"], align_y=Drawables.Text.ALIGN_Y_CENTER) self._drawables["data"][dataset_name].append(data_text) column_x += dataset["cell_width"] # Since new datapoint, sort if not FIFO if self._sorting_scheme != Sorting.FIFO: self._sort()
def add_dataset(self, name, data, font_color=Colors.WHITE, formatting="{}", cell_width=100, header_align_x=Drawables.Text.ALIGN_X_CENTER, data_align_x=Drawables.Text.ALIGN_X_LEFT): """ Add a new dataset (or column) to the chart. Note that this funciton cannot be called after the add_datum function has been called. :param name: Name of the column (will show up as a header and must be unique) :param data: A list of data points for this column (all columns must have the same number of datapoints. :param font_color: Color of the font of the text in this column :param formatting: If you wat custom formatting; for example, if you want percent signs, you can pass in "{}%" :param cell_width: Width of the cells in this column :param header_align_x: How should the header be aligned (pick from Drawables.Text x align options) :param data_align_x: How should the data values be aligned (pick from Drawables.Text x align options) :return: None """ assert isinstance(name, str) and name not in self.datasets assert isinstance(data, list) assert Colors.is_color(font_color) assert isinstance(formatting, str) and re.match( r"^[^{]*{[^{]*}[^{]*$", formatting) assert header_align_x in (Drawables.Text.ALIGN_X_LEFT, Drawables.Text.ALIGN_X_CENTER, Drawables.Text.ALIGN_X_RIGHT) assert data_align_x in (Drawables.Text.ALIGN_X_LEFT, Drawables.Text.ALIGN_X_CENTER, Drawables.Text.ALIGN_X_RIGHT) assert sum( [dataset["cell_width"] for dataset in self.datasets.values()]) + cell_width <= self.width assert all([ len(data) == len(dataset["data"]) for dataset in self.datasets.values() ]) assert self._can_add_more_datasets # To pad left and right if alignments are selected to be to left and right pad = 4 data_font_size = 12 # Account for new vertical line vertical_line_height = (len(data) + 1) * self._cell_heights if len(self._drawables["vertical"]) == 0: self._drawables["vertical"].append( Drawables.Line(self.x, self.y, 0, vertical_line_height, color=self._fg_color)) column_x = self.x + sum( [dataset["cell_width"] for dataset in self.datasets.values()]) self._drawables["vertical"].append( Drawables.Line(column_x + cell_width, self.y, 0, vertical_line_height, color=self._fg_color)) # Deal with all horizontal lines if len(self._drawables["horizontal"]) == 0: for i in range(len(data) + 2): horizontal = Drawables.Line(self.x, self.y + i * self._cell_heights, column_x + cell_width, 0, color=self._fg_color) self._drawables["horizontal"].append(horizontal) else: for horizontal in self._drawables["horizontal"]: horizontal.width = column_x + cell_width # Deal with headers x_values = { Drawables.Text.ALIGN_X_LEFT: column_x + pad, Drawables.Text.ALIGN_X_CENTER: column_x + cell_width / 2, Drawables.Text.ALIGN_X_RIGHT: column_x + cell_width - pad } self._drawables["headers"].append( Drawables.Text(x_values[header_align_x], self.y + self._cell_heights / 2, name, font_size=15, fg_color=font_color, align_x=header_align_x, align_y=Drawables.Text.ALIGN_Y_CENTER)) # Deal with data data_drawables = [] for i, datum in enumerate(data): data_drawables.append( Drawables.Text(x_values[data_align_x], self.y + (i + 1.5) * self._cell_heights, formatting.format(datum), font_size=data_font_size, fg_color=font_color, align_x=data_align_x, align_y=Drawables.Text.ALIGN_Y_CENTER)) self._drawables["data"][name] = data_drawables # Store the input values self.datasets[name] = { "data": data, "insertion_order": range(len(data)), "font_color": font_color, "formatting": formatting, "cell_width": cell_width, "data_font_size": data_font_size, "pad": pad, "header_align_x": header_align_x, "data_align_x": data_align_x } self._sort()