2 Commits

Author SHA1 Message Date
KatKatKateryna 7b99bedd8d working dashboards 2023-11-10 15:18:45 +00:00
KatKatKateryna d71fd4becf add dashboard ui 2023-11-03 16:29:27 +00:00
4 changed files with 918 additions and 281 deletions
+475 -281
View File
File diff suppressed because it is too large Load Diff
+110
View File
@@ -0,0 +1,110 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SpeckleDashboard</class>
<widget class="QDockWidget" name="SpeckleDashboard">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>575</width>
<height>651</height>
</rect>
</property>
<property name="windowTitle">
<string>Speckle Dashboard</string>
</property>
<widget class="QWidget" name="dockWidgetContents">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout" stretch="5,1">
<item>
<layout class="QFormLayout" name="formLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="1" column="0">
<widget class="QWidget" name="chart">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="1">
<layout class="QHBoxLayout" name="streamListButtons">
</layout>
</item>
<item row="2" column="0">
<widget class="QLabel" name="streamBranchLabel">
<property name="text">
<string>Model properties</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="selectionDropdown"/>
</item>
<item row="3" column="1">
<widget class="QListWidget" name="dataWidget">
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContents</enum>
</property>
<property name="resizeMode">
<enum>QListView::Fixed</enum>
</property>
<property name="viewMode">
<enum>QListView::ListMode</enum>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>
+17
View File
@@ -334,6 +334,23 @@
</layout>
</item>
<item row="14" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="open_dashboard">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Open Dashboard</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
+316
View File
@@ -0,0 +1,316 @@
import random
from qgis.PyQt import QtWidgets, uic
from qgis.PyQt import QtGui
from qgis.PyQt.QtGui import QIcon, QPixmap
from qgis.PyQt.QtWidgets import (
QCheckBox,
QListWidgetItem,
QAction,
QDockWidget,
QVBoxLayout,
QHBoxLayout,
QWidget,
QLabel,
)
from qgis.PyQt import QtCore
from qgis.PyQt.QtCore import pyqtSignal, Qt
# from qgis.PyQt import QtCore, QtWidgets #, QtWebEngineWidgets
from PyQt5 import *
from PyQt5.QtCore import QUrl
import plotly.express as px
from PyQt5.QtWebKitWidgets import QWebView
import pandas as pd
import os
FORM_CLASS, _ = uic.loadUiType(
os.path.join(os.path.join(os.path.dirname(__file__), "ui", "dashboard.ui"))
)
class SpeckleDashboard(QtWidgets.QDockWidget, FORM_CLASS):
closingPlugin = pyqtSignal()
dataStorage = None
dataNumeric: dict = {}
dataText: dict = {}
current_filter: str = ""
current_index: int = -1
selectionDropdown: QtWidgets.QComboBox
dataWidget: QtWidgets.QListWidget
chart: QWidget
browser = None
existing_web: int = 0
def __init__(self, parent=None):
"""Constructor."""
super(SpeckleDashboard, self).__init__(parent)
# Set up the user interface from Designer through FORM_CLASS.
# After self.setupUi() you can access any designer object by doing
# self.<objectname>, and you can use autoconnect slots - see
# http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html
# #widgets-and-dialogs-with-auto-connect
self.browser = QWebView(self) # https://github.com/qgis/QGIS/issues/26048
self.setupUi(self)
self.selectionDropdown.clear()
self.selectionDropdown.addItems(["area", "property value"])
self.selectionDropdown.setCurrentIndex(0)
self.selectionDropdown.currentIndexChanged.connect(self.populateUI)
def setup(self):
self.dataWidget.clear()
for i, (key, val) in enumerate(self.dataNumeric.items()):
# property_filter = self.selectionDropdown.currentText()
if self.current_filter in key or key in self.current_filter:
listItem = QListWidgetItem(f"{key}: {val}")
self.dataWidget.addItem(listItem)
# self.dataWidget.setMaximumHeight(50)
def populateUI(self, force=0):
print(self.selectionDropdown.currentIndex())
print(self.current_filter)
if self.selectionDropdown.currentText() == "":
self.current_filter = "area"
self.current_index = 0
self.setup()
self.selectionDropdown.setIndex(0)
self.createChart()
elif self.selectionDropdown.currentText() != self.current_filter:
self.current_filter = self.selectionDropdown.currentText()
self.current_index = self.selectionDropdown.currentIndex()
self.setup()
self.createChart()
if force == 1:
self.setup()
self.createChart()
def update(self):
self.dataNumeric = {}
self.dataText = {}
for i in range(10):
# keys = ["key1", "key2", "key3", "key4", "key5"]
# key = keys[random.randint(0, 4)]
value = random.randint(10, 100)
self.dataNumeric.update({"index": i, f"area {random.randint(1, 4)}": value})
for i in range(10):
# keys = ["key1", "key2", "key3", "key4", "key5"]
# key = keys[random.randint(0, 4)]
value = random.randint(10, 100)
self.dataNumeric.update(
{
"index": i + 10,
f"property value {random.randint(1, 4)}": [
value,
value * 0.5,
value * 2,
],
}
)
r"""
layer = getLayerByName(self.dataStorage.project, "Speckle_dashboard")
fields = layer.fields()
for i, key in enumerate(fields.names()):
if key in ["Branch URL", "commit_id", "updated"]:
continue
value = None
variant = fields.at(i).type()
if "value" in key:
value = []
if "area" in key:
value = 0
for feat in layer.getFeatures():
if isinstance(value, List):
if feat[key] is not None:
list_vals = (
feat[key]
.replace("[", "")
.replace("]", "")
.replace("'", "")
.split(",")
)
value.extend([x for x in list_vals if x != ""])
print(value)
elif isinstance(value, float) or isinstance(value, int):
if feat[key] is not None:
value += feat[key]
self.dataNumeric.update({key: value})
"""
self.populateUI(force=1)
def createChart(self):
# https://stackoverflow.com/questions/60522103/how-to-have-plotly-graph-as-pyqt5-widget
r"""
print("PRINT DATAFRAME")
df = pd.DataFrame.from_dict(self.dataNumeric, orient="index", columns=["value"])
df2 = df.reset_index()
print(df2)
property_filter = str(self.selectionDropdown.currentText())
if len(property_filter) <= 1:
property_filter = "area"
df2 = df2[df2["index"].str.lower().str.contains(property_filter)]
print(df2)
if "area" in property_filter:
fig = px.pie(
df2,
values="value",
names="index",
title="Land use distribution",
hole=0.5,
)
elif "value" in property_filter:
all_column_vals = df2["value"].to_list()
all_column_vals_separated = []
[all_column_vals_separated.extend(x) for x in all_column_vals]
all_vals = [float(x) for x in all_column_vals_separated]
df2 = pd.DataFrame([{property_filter: val} for val in all_vals])
fig = px.histogram(df2, x=property_filter, title="Property values")
else:
df2 = df2.loc["area" in df2["index"]]
fig = px.pie(
df2, values="value", names="index", title="Land use distribution"
)
print(df2)
# remove all buttons
# try:
# for i in reversed(range(self.chart.layout.count())):
# self.chart.layout.itemAt(i).widget().setParent(None)
# except: pass
"""
fig = self.assembleFigure()
if self.existing_web == 0:
self.browser = QWebView(self)
self.browser.setHtml(
fig.to_html(include_plotlyjs="cdn", config={"displayModeBar": False})
)
# self.browser.setUrl(QUrl("https://speckle.xyz/streams/e2effcfa27/commits/f76cedd9a6"))
self.chart.layout = QHBoxLayout(self.chart)
# self.browser.setMaximumHeight(400)
if self.existing_web == 0:
self.chart.layout.addWidget(self.browser)
self.existing_web = 1
return
# https://www.pythonguis.com/tutorials/plotting-pyqtgraph/
graphWidget = pg.PlotWidget()
hour = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
temperature = [30, 32, 34, 32, 33, 31, 29, 32, 35, 45]
# plot data: x, y values
graphWidget.plot(hour, temperature)
# remove all buttons
try:
for i in reversed(range(self.chart.layout.count())):
self.chart.layout.itemAt(i).widget().setParent(None)
except:
pass
self.chart.layout = QHBoxLayout(self.chart)
self.chart.layout.addWidget(graphWidget)
# set the QWebEngineView instance as main widget
# self.setCentralWidget(plot_widget)
def assembleFigure(self):
import plotly
from plotly.subplots import make_subplots
cols = 1
rows = 2 # len(TOTAL_SERVER_LIST) #math.ceil(len(TOTAL_SERVER_LIST)/cols)
# specs_col = [{"type": "bar"}, {"type": "sunburst"}]
specs = [[{"type": "sunburst"}], [{"type": "bar"}]]
# specs = [ specs_col for r in range(rows)]
# df = pd.DataFrame(columns=['Country', '', 'count'])
# for i in range(5): df = df.append({'Name' : 'Ankit', 'Articles' : 97, 'Improved' : 2200},ignore_index = True)
fig = make_subplots(rows=rows, cols=cols, specs=specs)
# dataframe
df = pd.DataFrame.from_dict(self.dataNumeric, orient="index", columns=["value"])
df = df.reset_index()
print(df)
# plot - pie chart
# df2 = df2.loc["area" in df2["index"]]
property_filter = "area"
df2 = df[df["index"].str.lower().str.contains(property_filter)].copy()
fig2 = px.pie(
df2,
values="value",
names="index",
title="Land use distribution",
hole=0.5,
)
fig.add_trace(fig2.data[0], row=1, col=1)
# plot - histogram
property_filter = "value"
# df2 = df[df["index"].str.lower().str.contains(property_filter)].copy()
all_column_vals = df[df["index"].str.lower().str.contains(property_filter)][
"value"
].to_list()
all_column_vals_separated = []
[
all_column_vals_separated.extend(x)
for x in all_column_vals
if isinstance(x, list)
]
all_vals = [float(x) for x in all_column_vals_separated]
df2 = pd.DataFrame([{property_filter: val} for val in all_vals])
print(df2)
fig2 = px.histogram(df2, x=property_filter, title="Property values")
fig.add_trace(fig2.data[0], row=2, col=1)
# plot - sunburst
# fig2 = px.sunburst(
# df2,
# path=["server_id", "isWebhook", "isMultiplayer"],
# color="isMultiplayer",
# values="count",
# color_discrete_map={True: "blue", False: "red"},
# )
# fig.add_trace(fig2.data[0], row=2, col=1)
fig.update_layout(
title="Some title",
)
width = 300
fig.update_layout(
autosize=False,
width=width,
height=width / cols * rows,
)
return fig
# fig.update_yaxes(range = [0, 30], col=1) #, title_text=f"Total receives: {total_receives} by {people} people")
# fig.update_xaxes(range = [0, 31*4], col=1)
# fig.show()
# plotly.offline.plot(fig, filename='Graphs/stats_perServer_pie.html')