import random from typing import Union import pyqtgraph as pg from PyQt6 import QtWidgets def mergedicts(d1, d2): res = {} d1_data = list(d1.items()) d2_data = list(d2.items()) for i in range(len(d1)): # _data is a list of tuples d1_data_slice = d1_data[i] d2_data_slice = d2_data[i] # convert the tuples to dicts d1_dict = dict([d1_data_slice]) d2_dict = dict([d2_data_slice]) # merge the dicts res.update(d1_dict) res.update(d2_dict) return res class DataGraph(QtWidgets.QWidget): def __init__( self, title, data=Union[dict[list, list] | dict[list[dict[str, list]]]], generateMissing=False, label=None, ): super().__init__() lst = [] if generateMissing: x_data = data["x"] y_data = data["y"] if not isinstance(y_data, list): for key in y_data: data = {"x": x_data, "y": y_data[key]} data = self.generateMissingSemesters(data) data["y-label"] = key lst.append(data) else: data = self.generateMissingSemesters(data) lst.append(data) else: x_data = data["x"] y_data = data["y"] if not isinstance(y_data, list): for key in y_data: data = {"x": x_data, "y": y_data[key]} data["y-label"] = key lst.append(data) else: lst.append(data) x_data = lst[0]["x"] # xdict = dict(enumerate(x_data)) stringaxis_x = pg.AxisItem(orientation="bottom") stringaxis_x.setTicks([xdict.items()]) graph = pg.PlotWidget(axisItems={"bottom": stringaxis_x}) graph.addLegend() colors = ["b", "r", "c", "m", "y", "k", "w"] symbols = [ "o", "s", "t", "d", "+", "t1", "t2", "t3", "p", "h", "star", "x", "arrow_up", "arrow_down", "arrow_left", "arrow_right", ] color_index = 0 index = 0 for data in lst: symbol = symbols[random.randint(0, len(symbols) - 1)] if color_index >= len(colors): color_index = 0 # iterate over the list, use y-data and y-label to plot the graph y_data = data["y"] label = data["y-label"] if "y-label" in data else label pen = pg.mkPen(color=colors[color_index], width=2) if isinstance(y_data, list): graph.plot( list(xdict.keys()), y_data, pen=pen, symbol=symbol, name=label ) color_index += 1 index += 1 else: pass graph.setBackground("#d3d3d3") graph.setTitle(title) layout = QtWidgets.QVBoxLayout() layout.addWidget(graph) self.setLayout(layout) def generateMissingSemesters(self, data: dict[list]): # join the data into a single dict with x values as key and y values as value tmp_data = dict(zip(data["x"], data["y"], strict=False)) # split into dicts based on SoSe and WiSe SoSe_data = {k: v for k, v in tmp_data.items() if "SoSe" in k} WiSe_data = {k: v for k, v in tmp_data.items() if "WiSe" in k} SoSe_years = [int(sose.split("SoSe")[1]) for sose in SoSe_data] WiSe_years = [int(wise.split("WiSe")[1].split("/")[0]) for wise in WiSe_data] years = SoSe_years + WiSe_years years = [ year for year in range(min(list(set(years))), max(list(set(years))) + 1) ] years.sort() for year in years: SoSe_year = f"SoSe{year}" WiSe_year = f"WiSe{year}/{year + 1}" if SoSe_year not in SoSe_data.keys(): SoSe_data[SoSe_year] = 0 if WiSe_year not in WiSe_data.keys(): WiSe_data[WiSe_year] = 0 # sort WiSe_data to have same order as SoSe_data WiSe_data = dict(sorted(WiSe_data.items(), key=lambda x: x[0])) SoSe_data = dict(sorted(SoSe_data.items(), key=lambda x: x[0])) data = mergedicts(SoSe_data, WiSe_data) # split the data back into x and y data = {"x": list(data.keys()), "y": list(data.values())} return data if __name__ == "__main__": import sys app = QtWidgets.QApplication(sys.argv) data_1 = { "x": ["SoSe 10", "WiSe 10/11", "SoSe 11", "SoSe 14"], "y": { "Added": [1, 2, 3, 4], "Deleted": [4, 3, 2, 1], }, } data_2 = { "x": ["SoSe 10"], "y": [2], } graph_data = {"x": ["SoSe 24"], "y": [1]} widget = DataGraph( "ELSA Apparate pro Semester", data_2, True, "Anzahl der Apparate" ) widget.show() sys.exit(app.exec())