Skip to content

Commit

Permalink
Merge pull request #10
Browse files Browse the repository at this point in the history
Fix linter warnings
  • Loading branch information
rtomek authored Aug 23, 2024
2 parents 709fbc8 + 62d47de commit 24987ba
Show file tree
Hide file tree
Showing 10 changed files with 100 additions and 80 deletions.
76 changes: 50 additions & 26 deletions ExcelLayout.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@

import re
import warnings
import pandas as pd
import math
import pandas as pd


class DataSource:
Expand Down Expand Up @@ -99,7 +99,7 @@ class DataSheet:
create_custom_age_columns(self, age_ranges): Scans the column headers in the age category to build consistent
age columns.
"""
def __init__(self, sheet_name, data_source, custom_age_ranges, is_excel=False, file=None):
def __init__(self, sheet_name, data_source, custom_age_ranges, is_excel=False, file: pd.ExcelFile = None):
"""
Initialize the DataSheet object.
Expand All @@ -116,34 +116,58 @@ def __init__(self, sheet_name, data_source, custom_age_ranges, is_excel=False, f
self.columns = {}
self.data_columns = []

if is_excel:
self.df = pd.read_excel(file, sheet_name, usecols=lambda x: '(%)' not in str(x), engine='openpyxl')
self.df.columns = self.df.columns.astype(str)
cols = [col for col in self.df.columns]

if data_source.get('date', None):
cols = ['date'] + cols[1:]
self.df.insert(0, 'date', data_source['date'], False)

self.df['date'] = pd.to_datetime(self.df['date'], errors='coerce')
if is_excel and file is not None:
self._load_excel_data(file, sheet_name, data_source)

if cols[-1].find('Not reported') == -1:
cols = cols + ['Not reported']
self.df['Not reported'] = 0
if custom_age_ranges and self.name in custom_age_ranges:
self.create_custom_age_columns(custom_age_ranges[self.name])

self.columns['date'] = cols[0]
for col in cols[1:]:
col_name = col
if data_source.get('remove column name text', None):
for txt in data_source['remove column name text']:
col_name = col.split(txt)[0]
self.df[col_name.rstrip()] = self.df[col]
self.columns[col_name.rstrip()] = col
def _load_excel_data(self, file: pd.ExcelFile, sheet_name: str, data_source: dict):
"""
Load and process data from an Excel file.
self.data_columns = list(self.columns.keys())[1:]
Args:
file (pd.ExcelFile): The Excel file to read the sheet from.
sheet_name (str): The name of the sheet to parse.
data_source (dict): The data source object containing additional settings.
if custom_age_ranges and self.name in custom_age_ranges:
self.create_custom_age_columns(custom_age_ranges[self.name])
Returns:
None
"""
self.df = file.parse(sheet_name=sheet_name, usecols=lambda x: '(%)' not in str(x), engine='openpyxl')
self.df.columns = self.df.columns.astype(str)
self._process_date_column(data_source)
print(sheet_name)
print(self.df.columns)
self._process_columns(data_source)

def _process_date_column(self, data_source: dict):
"""Process and format the date column."""

# This assumes that the first column is either the date column or does not have useful data
if data_source.get('date'):
self.df.drop(self.df.columns[0], axis=1, inplace=True)
self.df.insert(0, 'date', data_source['date'], False)

self.df['date'] = pd.to_datetime(self.df['date'], errors='coerce')

if 'Not reported' not in self.df.columns:
self.df['Not reported'] = 0

self.columns['date'] = self.df.columns[0]

def _process_columns(self, data_source: dict):
"""Process and rename columns according to the data source settings."""
for col in self.df.columns[1:]:
col_name = col
if 'remove column name text' in data_source:
for txt in data_source['remove column name text']:
col_name = col.split(txt)[0]
col_name = col_name.rstrip()
self.columns[col_name] = col
self.df[col_name] = self.df.pop(col)

self.data_columns = list(self.columns.keys())[1:]

def create_custom_age_columns(self, age_ranges):
"""
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ There is a requirements.txt file available to install requirements
#### Configure yaml
First, configure your own jsdconfig.yaml file to select which data to load by default. There is a jsdconfig-example.yaml file provided that may be copied over or used as a template for your own config file.
* The filename needs to be specified, and a human-readable name should be provided for use in the plots and figures.
* Please see the ***Generating custom excel files*** section for additional information.
* Please see the ***Generating custom Excel files*** section for additional information.
* On your first run, you may use ```cp jsdconfig-example.yaml jsdconfig.yaml``` to load the MIDRC data.

#### Run application
Expand All @@ -70,7 +70,7 @@ To start the application, run `python main.py`
- **Each attribute should have its own sheet** which will be automatically parsed by the application.
- Column names within each sheet are parsed and compared between files
- Where there is a matching column name within a worksheet of the same name, the JSD will be calculated using those values.
- ***A Date column is expected***, and it should be sorted. Please see how the census data is loaded using the example config file if your data does not have multiple dates and you do not have a date column.
- ***A Date column is expected***, and it should be sorted. Please see how the census data is loaded using the example config file if your data does not have multiple dates, and you do not have a date column.
- The list of attributes provided in the GUI should be a list where worksheets with an identical name exist in both files. If it is not, please check your spelling
- The ```remove column name text``` config parameter is due to how the MIDRC data is generated. There is a ```(CUSUM)``` suffix that needs to be removed to compare it to CDC and Census data.

Expand Down
8 changes: 4 additions & 4 deletions excelparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,16 @@ def excelparse(filename, sheet_name):
"""

# This opens the file and creates a list of sheet names, along with necessary readers
# TODO: this should probably be separate in case we want multiple sheets
xls = pd.ExcelFile(filename)

# This reads all Excel sheets, probably not worth it
# df_map = pd.read_excel(xls)

# This reads in the specified worksheet
df = pd.read_excel(xls, sheet_name)
df = xls.parse(sheet_name=sheet_name, usecols=lambda x: '(%)' not in str(x), engine='openpyxl')

# Find the columns that are percentages of the total distribution
pct_cols = [col for col in df.columns if '(%)' in col]
# pct_cols = [col for col in df.columns if '(%)' in col]

return df[['date'] + pct_cols]
# return df[['date'] + pct_cols]
return df
12 changes: 6 additions & 6 deletions grabbablewidget.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,14 +264,14 @@ def _setup_buttons(self, layout):
"""
button_layout = QHBoxLayout()

self.save_button = QPushButton("Save", self)
self.cancel_button = QPushButton("Cancel", self)
save_button = QPushButton("Save", self)
cancel_button = QPushButton("Cancel", self)

self.save_button.clicked.connect(self.save_image)
self.cancel_button.clicked.connect(self.cancel_save)
save_button.clicked.connect(self.save_image)
cancel_button.clicked.connect(self.cancel_save)

button_layout.addWidget(self.save_button)
button_layout.addWidget(self.cancel_button)
button_layout.addWidget(save_button)
button_layout.addWidget(cancel_button)

layout.addLayout(button_layout)

Expand Down
4 changes: 2 additions & 2 deletions jsdconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class JSDConfig:
__init__(self, filename='jsdconfig.yaml'): Initializes a new instance of the JSDConfig class.
"""
def __init__(self, filename='jsdconfig.yaml'):
stream = open(filename, 'r')
self.data = load(stream, Loader=Loader)
with open(filename, 'r', encoding='utf-8') as stream:
self.data = load(stream, Loader=Loader)

# print(dump(self.data))
12 changes: 6 additions & 6 deletions jsdcontroller.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class JSDController(QObject):
"""
modelChanged = Signal()
fileChangedSignal = Signal()

def __init__(self, jsd_view, jsd_model, config):
"""
Initialize the JSDController.
Expand Down Expand Up @@ -168,8 +168,8 @@ def get_file_sheets_from_combobox(self, index=0):
"""
try:
current_data = self.jsd_view.dataselectiongroupbox.file_comboboxes[index].currentData()
except IndexError:
raise IndexError("Index out of range")
except IndexError as exc:
raise IndexError("Index out of range") from exc

sheets = self.jsd_model.data_sources[current_data].sheets
return sheets
Expand Down Expand Up @@ -245,7 +245,7 @@ def update_file_based_charts(self):

try:
self.jsd_view.update_pie_chart_dock(sheet_dict)
except Exception:
except (ValueError, KeyError, TypeError):
return False

return True
Expand All @@ -262,13 +262,13 @@ def update_category_plots(self):
sheet_dict = {}
for i in range(len(self.jsd_view.dataselectiongroupbox.file_comboboxes)):
if self.jsd_view.dataselectiongroupbox.file_checkboxes[i].isChecked():
sheet_dict[i] = (self.get_file_sheets_from_combobox(i))
sheet_dict[i] = self.get_file_sheets_from_combobox(i)

try:
self.jsd_view.update_jsd_timeline_plot(self.jsd_model)
self.jsd_view.update_area_chart(sheet_dict)
return True
except Exception as e:
except (ValueError, KeyError, TypeError) as e:
print(f"An error occurred during the update of category plots: {e}")
return False

Expand Down
10 changes: 5 additions & 5 deletions jsdmodel.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@
# limitations under the License.
#

from ExcelLayout import DataSource
from typing import Optional, Any, List
from PySide6.QtCore import QAbstractTableModel, QModelIndex, Qt, Signal
from PySide6.QtGui import QColor
from typing import Optional, Any, List
from ExcelLayout import DataSource


class JSDTableModel(QAbstractTableModel):
Expand Down Expand Up @@ -151,20 +151,20 @@ def update_input_data(self, new_input_data, new_column_infos):
for c in range(self.columnCount()):
self.max_row_count = max(self.max_row_count, len(self._input_data[c]))

def columnCount(self, parent: QModelIndex = None) -> int:
def columnCount(self, _parent: QModelIndex = None) -> int:
"""
Returns the number of columns in the model.
Args:
parent (QModelIndex): The parent index. Defaults to QModelIndex().
_parent (QModelIndex): The parent index. Defaults to QModelIndex(). This is unused.
Returns:
int: The number of columns in the model.
"""
# return len(self.input_data[parent.row()])
return len(self._input_data)

def headerData(self, section: int, orientation: int, role: int, *args, **kwargs) -> Any:
def headerData(self, section: int, orientation: Qt.Orientation, role: int = Qt.DisplayRole, *args, **kwargs) -> Any:
"""
Returns the header data for the specified section, orientation, and role.
Expand Down
15 changes: 6 additions & 9 deletions jsdview.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
from typing import Type, Union, List, Tuple
from typing import Type, Union, List, Tuple, Iterable
import math
import io
import csv
from functools import partial
from PySide6.QtCore import (QRect, Qt, QDateTime, QTime, QPointF, QSignalBlocker, Signal,
QFileInfo, QEvent, QDate)
QFileInfo, QEvent, QDate, QObject)
from PySide6.QtGui import QPainter, QAction, QKeySequence, QGuiApplication
from PySide6.QtWidgets import (QHeaderView, QTableView, QWidget, QMainWindow, QGroupBox, QMenu, QFileDialog,
QVBoxLayout, QComboBox, QLabel, QHBoxLayout, QMenuBar, QDockWidget, QSplitter,
Expand All @@ -27,8 +28,6 @@
QPieSeries, QPolarChart, QAreaSeries, QCategoryAxis)
from datetimetools import numpy_datetime64_to_qdate, convert_date_to_milliseconds
from grabbablewidget import GrabbableChartView
from functools import partial
from typing import Iterable


class JsdDataSelectionGroupBox(QGroupBox):
Expand Down Expand Up @@ -269,7 +268,6 @@ def __init__(self, data_sources):
self.area_chart_widget = QWidget()
# self.area_chart_layout = QVBoxLayout()
self.area_chart_widget.setLayout(QVBoxLayout())
self.area_charts = {}
self.spider_chart_vbox = QSplitter(Qt.Vertical)
self.spider_chart_dock_widget = self.create_spider_chart_dock_widget(self.spider_chart_vbox,
'Diversity Charts - ' + JsdWindow.WINDOW_TITLE)
Expand Down Expand Up @@ -346,7 +344,7 @@ def populate_dock_widget_menu(self, dock_widget_menu: QMenu) -> None:
"""
Clear the dock widget menu and populate it with actions for each dock widget.
This method clears the existing menu items in the dock widget menu and creates a new action for each dock widget found.
This method clears the existing menu items in the menu and creates a new action for each dock widget found.
Each action corresponds to a dock widget and allows the user to toggle the visibility of the dock widget.
"""
dock_widget_menu.clear()
Expand Down Expand Up @@ -477,8 +475,7 @@ def update_pie_chart_dock(self, sheet_dict):
label_text = file_comboboxes[index].currentText() + ':'
label = QLabel(label_text)
label_width = label.sizeHint().width()
if label_width > max_label_width:
max_label_width = label_width
max_label_width = max(max_label_width, label_width)

for index, sheets in sheet_dict.items():
row_layout = QHBoxLayout()
Expand Down Expand Up @@ -980,7 +977,7 @@ def __init__(self):
super().__init__()
self.installEventFilter(self)

def eventFilter(self, source, event):
def eventFilter(self, source: QObject, event):
"""
Filters and handles key press events.
Expand Down
6 changes: 3 additions & 3 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,14 @@ def _create_pixmap():
painter.drawText(pixmap.rect(), Qt.AlignCenter, SPLASH_SCREEN_MESSAGE)
return pixmap

def __init__(self, parent: Optional[QWidget] = None) -> None:
def __init__(self) -> None:
"""
Initialize the object.
Args:
parent: The parent widget.
None
"""
super().__init__(parent)
super().__init__()
pixmap = self._create_pixmap()
self.setPixmap(pixmap)

Expand Down
Loading

0 comments on commit 24987ba

Please sign in to comment.