Skip to content

Commit

Permalink
table filtering;img2img etc
Browse files Browse the repository at this point in the history
  • Loading branch information
dmnfarrell committed Jan 29, 2024
1 parent 5554540 commit bc1f7da
Show file tree
Hide file tree
Showing 10 changed files with 2,272 additions and 273 deletions.
101 changes: 101 additions & 0 deletions gui/sample.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
"ec","cy","hy","rc","gf","label"
-0.867,-0.66,0.532,7.702,2.139,"orange"
-0.898,-0.872,-0.642,5.657,1.369,"red"
-1.802,-1.71,-0.498,8.657,-0.464,"blue"
-0.297,-0.219,-1.683,7.684,1.538,"red"
-1.003,-0.668,-0.077,7.375,2.491,"yellow"
-2.875,-2.671,-0.121,9.344,1.911,"yellow"
-2.858,-1.941,-0.31,7.88,1.975,"yellow"
-1.609,-1.176,-1.23,8.609,2.316,"blue"
-1.794,-1.423,-0.657,6.525,1.022,"yellow"
-1.559,-1.013,-0.119,6.033,0.958,"yellow"
-2.741,-2.022,-0.957,6.999,1.349,"blue"
-1.764,-1.846,-0.432,8.052,1.758,"red"
-0.657,-0.583,-0.403,6.635,-0.251,"green"
-1.876,-1.344,-0.542,7.317,0.07,"yellow"
0.943,0.764,-0.302,7.925,-1.483,"yellow"
-2.905,-1.701,0.052,4.881,1.791,"blue"
-1.977,-1.575,-0.642,7.185,1.306,"orange"
-0.69,-0.644,-1.797,7.377,2.005,"blue"
-0.497,-0.346,-1.009,8.866,0.546,"red"
-1.336,-1.129,-0.792,8.298,-0.556,"green"
-0.113,-0.105,-0.642,7.618,0.148,"orange"
-1.152,-0.921,-0.248,6.967,1.623,"red"
-1.968,-1.435,-0.997,7.331,0.784,"yellow"
-1.377,-1.268,-1.859,8.885,1.9,"blue"
-1.443,-1.024,-0.396,6.933,0.742,"blue"
-1.755,-1.182,-1.578,6.515,1.659,"yellow"
-3.564,-2.521,-0.116,6.903,1.055,"blue"
-2.807,-1.568,0.117,6.18,1.851,"green"
-2.367,-1.885,-0.674,8.19,1.99,"yellow"
-1.785,-1.802,-1.085,7.48,0.084,"green"
-2.203,-2.089,-0.731,6.315,-0.159,"orange"
-0.315,-0.245,-2.37,5.759,0.352,"orange"
-2.125,-1.793,0.363,6.622,1.203,"yellow"
-0.859,-0.647,0.337,7.069,0.521,"red"
-0.839,-0.683,-0.996,7.137,1.837,"green"
-2.424,-2.159,-0.375,7.051,2.24,"blue"
-2.716,-2.589,-0.046,7.381,0.491,"green"
-0.796,-0.699,1.311,9.197,2.665,"orange"
-1.919,-1.317,0.045,5.925,2.959,"green"
-1.346,-1.202,-1.18,8.637,2.887,"blue"
-0.505,-0.365,-0.621,6.6,1.573,"green"
-3.421,-2.623,-0.134,7.419,1.829,"green"
-1.909,-1.363,-1.357,7.668,1.687,"orange"
-0.606,-0.391,-1.192,7.805,1.736,"blue"
-1.55,-1.118,-0.095,7.413,0.416,"yellow"
-3.151,-2.809,-1.428,7.404,-1.107,"green"
-2.217,-1.511,-0.127,6.767,0.416,"green"
-3.748,-2.778,-1.187,7.165,-0.088,"blue"
-2.678,-2.382,-0.311,7.568,0.889,"orange"
-3.107,-1.902,-0.958,7.577,2.001,"red"
-0.085,-0.051,-0.219,7.149,0.827,"green"
-2.461,-2.012,-0.888,5.945,-0.821,"yellow"
0.172,0.147,-1.138,6.652,1.844,"orange"
-2.248,-1.814,-0.838,7.057,-0.355,"green"
-2.9,-2.27,-0.297,7.455,0.245,"orange"
-2.251,-1.782,-1.529,8.728,1.439,"blue"
-1.588,-1.081,-0.743,6.418,0.974,"red"
-2.023,-1.83,0.51,7.617,1.232,"red"
-1.67,-1.418,0.509,7.928,0.644,"red"
-0.929,-0.779,1.015,7.523,1.056,"blue"
0.289,0.203,-1.123,9.339,0.912,"red"
-1.503,-1.535,-1.316,7.299,1.333,"red"
-0.624,-0.469,0.91,6.104,1.626,"blue"
-3.011,-2.818,-0.513,6.744,-0.409,"orange"
-2.046,-1.36,-1.216,8.823,0.872,"yellow"
-2.036,-1.148,-1.286,7.8,1.518,"red"
-1.525,-1.193,0.583,7.563,2.025,"red"
-1.251,-1.06,0.882,6.947,0.758,"red"
-2.213,-1.484,0.906,7.643,-1.116,"yellow"
-1.869,-1.46,-1.584,6.76,0.694,"red"
-1.315,-0.931,-1.331,3.081,-0.111,"blue"
-3.28,-2.541,0.068,6.643,1.52,"yellow"
-0.029,-0.026,-1.606,8.556,1.226,"orange"
-0.456,-0.478,0.536,7.701,2.198,"blue"
-2.469,-2.057,-0.154,6.71,0.967,"orange"
-2.624,-2.108,1.131,7.916,0.8,"green"
-2.206,-1.975,1.021,7.324,1.998,"green"
0.025,0.021,-0.683,7.84,1.402,"orange"
-4.097,-3.096,-0.989,9.241,1.383,"green"
0.182,0.142,-1.287,8.087,2.425,"blue"
-2.499,-1.861,-1.162,7.134,2.952,"green"
-1.122,-0.835,-1.284,7.537,1.506,"orange"
-0.213,-0.145,-0.24,7.301,-0.08,"red"
-1.48,-1.17,0.248,5.554,1.511,"yellow"
-0.178,-0.137,-2.49,8.568,1.815,"red"
-1.095,-0.942,-1.173,7.572,1.131,"red"
-2.586,-2.062,-0.524,9.796,-0.216,"green"
-1.727,-1.494,0.093,7.858,1.31,"blue"
-2.052,-1.111,-1.277,5.087,-0.811,"blue"
-0.02,-0.017,-0.278,8.09,1.2,"blue"
-0.799,-0.764,-1.175,6.512,1.663,"red"
-1.607,-1.276,-1.046,7.942,0.971,"red"
-1.915,-1.537,-0.785,6.619,0.952,"yellow"
-0.419,-0.33,-0.813,6.924,1.701,"orange"
-2.757,-1.96,-0.116,9.023,0.413,"red"
-1.784,-1.582,-0.319,8.267,1.178,"blue"
-1.431,-1.329,0.587,8.462,2.483,"blue"
-0.97,-0.748,-0.239,7.13,0.207,"green"
-0.272,-0.237,-0.305,6.37,0.965,"blue"
-2.269,-1.855,0.146,6.455,1.891,"red"
258 changes: 258 additions & 0 deletions gui/table_filtering.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
#!/usr/bin/env python3

"""
Test table filtering with pyqt5 with dataframe model
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""

import sys,os
import numpy as np
import pandas as pd
import geopandas as gpd

from PySide2 import QtCore
from PySide2.QtWidgets import *
from PySide2.QtGui import *
from PySide2.QtCore import Qt, QUrl, QObject, Signal, Slot
from PySide2.QtWebEngineWidgets import QWebEngineView
from pandas.api.types import is_datetime64_any_dtype as is_datetime

class DataFrameModel(QtCore.QAbstractTableModel):
def __init__(self, dataframe=None, *args):
super(DataFrameModel, self).__init__()
if dataframe is None:
self.df = pd.DataFrame()
else:
self.df = dataframe
self.bg = '#F4F4F3'
self.rowcolors = None
return

def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.df.index)

def columnCount(self, parent=QtCore.QModelIndex()):
#if parent.isValid():
# return 0
return len(self.df.columns.values)

def data(self, index, role=QtCore.Qt.DisplayRole):
"""Edit or display roles. Handles what happens when the Cells
are edited or what appears in each cell.
"""

i = index.row()
j = index.column()
#print (self.df.dtypes)
#coltype = self.df.dtypes[j]
coltype = self.df[self.df.columns[j]].dtype
isdate = is_datetime(coltype)
if role == QtCore.Qt.DisplayRole:
value = self.df.iloc[i, j]
if isdate:
return value.strftime(core.TIMEFORMAT)
elif type(value) != str:
if type(value) in [float,np.float64] and np.isnan(value):
return ''
elif type(value) == float:
return value
else:
return (str(value))
else:
return '{0}'.format(value)
elif (role == QtCore.Qt.EditRole):
value = self.df.iloc[i, j]
if type(value) is str:
try:
return float(value)
except:
return str(value)
if np.isnan(value):
return ''

def headerData(self, col, orientation, role=QtCore.Qt.DisplayRole):
"""What's displayed in the headers"""

if len(self.df.columns) == 0:
return
if role == QtCore.Qt.DisplayRole:
if orientation == QtCore.Qt.Horizontal:
return str(self.df.columns[col])
if orientation == QtCore.Qt.Vertical:
value = self.df.index[col]
if type( self.df.index) == pd.DatetimeIndex:
if not value is pd.NaT:
try:
return value.strftime(TIMEFORMAT)
except:
return ''
else:
return str(value)
return None

class DataFrameTable(QTableView):
"""
QTableView with pandas DataFrame as model.
"""
def __init__(self, parent=None, dataframe=None):

QTableView.__init__(self)
self.parent = parent
vh = self.verticalHeader()
vh.setVisible(True)
vh.setDefaultSectionSize(28)
vh.setMinimumWidth(20)
vh.setMaximumWidth(500)

hh = self.horizontalHeader()
hh.setVisible(True)
hh.setSectionsMovable(True)
hh.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
hh.setSelectionBehavior(QTableView.SelectColumns)
hh.setSelectionMode(QAbstractItemView.ExtendedSelection)
#hh.sectionClicked.connect(self.columnClicked)
hh.setSectionsClickable(True)

self.resizeColumnsToContents()
self.setCornerButtonEnabled(True)

tm = DataFrameModel(dataframe)
self.model = tm

self.proxy = QtCore.QSortFilterProxyModel()
self.proxy.setSourceModel(self.model)
self.setModel(self.proxy)
self.proxy.sort(0, Qt.AscendingOrder)
self.setWordWrap(False)
self.setCornerButtonEnabled(True)
return

def applyFilters(self, query):
"""Apply filter to table"""

self.proxy.setFilterFixedString(query)
return

class FilterWidget(QWidget):
"""Simple filtering for tables"""

def __init__(self, parent, table, title=None):
super(FilterWidget, self).__init__(parent)
self.parent = parent
self.table = table
self.createWidgets()
self.setMaximumHeight(200)
return

def createWidgets(self):
"""Create widgets"""

style = '''
QWidget {
font-size: 12px;
}
QScrollBar:vertical {
width: 15px;
margin: 1px 0 1px 0;
}
QScrollBar::handle:vertical {
min-height: 20px;
}
QComboBox {
combobox-popup: 0;
max-height: 30px;
max-width: 150px;
}
'''

df = self.table.model.df
cols = list(df.columns)
cols.insert(0,'Any')

self.setWindowTitle('Search')
#self.main = QWidget()
self.setStyleSheet(style)
self.setMaximumHeight(200)

l = self.layout = QVBoxLayout(self)
l.setContentsMargins(0, 0, 0, 0)
l.setSpacing(0)
w = self.queryedit = QLineEdit(self)
w.returnPressed.connect(self.apply)

l.addWidget(QLabel("Query:"))
l.addWidget(w)

w = QWidget()
l.addWidget(w)
hb = QHBoxLayout(w)
hb.addWidget(QLabel('Column:'))
w = self.searchcolw = QComboBox()
w.addItems(cols)
hb.addWidget(w)

btn = QPushButton('Search')
btn.clicked.connect(self.apply)
l.addWidget(btn)
return

def closeEvent(self, ce):
self.clear()

def apply(self):
"""Apply filters"""

df = self.table.model.df
proxy = self.table.proxy
searchcol = self.searchcolw.currentText()
text = self.queryedit.text()
if searchcol == 'Any':
proxy.setFilterKeyColumn(-1)
else:
c = df.columns.get_loc(searchcol)
proxy.setFilterKeyColumn(c)
proxy.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive)
self.table.applyFilters(text)
return

def clear(self):
self.table.proxy.setFilterFixedString("")

class MainWindow(QMainWindow):
def __init__(self):
super().__init__()

self.setGeometry(QtCore.QRect(100, 100, 800, 500))

df = pd.read_csv('sample.csv')
self.main = QWidget()
layout = QVBoxLayout()
#add table
self.table = DataFrameTable(dataframe=df)
layout.addWidget(self.table)
#add filter widget
self.filterw = FilterWidget(self, self.table)
layout.addWidget(self.filterw)

container = QWidget()
container.setLayout(layout)
self.setCentralWidget(container)


app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()

0 comments on commit bc1f7da

Please sign in to comment.