Compare commits
	
		
			2 Commits
		
	
	
		
			ab1d541e2c
			...
			new_featur
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| e1b817252c | |||
| 2d73ae8d63 | 
| @ -58,4 +58,18 @@ hr { | ||||
|     .dropdown-container { | ||||
|         grid-template-columns: 1fr; | ||||
|     } | ||||
| } | ||||
| } | ||||
|  | ||||
| .feedback-button { | ||||
|     background-color: #007bff; | ||||
|     color: white; | ||||
|     border: none; | ||||
|     padding: 5px 10px; | ||||
|     text-align: center; | ||||
|     text-decoration: none; | ||||
|     display: inline-block; | ||||
|     font-size: 12px; | ||||
|     margin: 2px 2px; | ||||
|     cursor: pointer; | ||||
|     border-radius: 4px; | ||||
| } | ||||
|  | ||||
							
								
								
									
										2
									
								
								data/feedback.csv
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								data/feedback.csv
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,2 @@ | ||||
| timestamp,category,comment | ||||
| 2025-09-07 20:02:38,groceries,"ABZT please change this air to P1231313" | ||||
| 
 | 
							
								
								
									
										4
									
								
								main.py
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								main.py
									
									
									
									
									
								
							| @ -1,6 +1,6 @@ | ||||
| # initial commit | ||||
| from dash import Dash | ||||
| from dash_bootstrap_components.themes import BOOTSTRAP | ||||
| import dash_bootstrap_components as dbc | ||||
|  | ||||
| from src.components.layout import create_layout | ||||
| from src.data.loader_gz import load_spc_data | ||||
| @ -21,7 +21,7 @@ def main() -> None: | ||||
|     # load the data and create the data manager | ||||
|     data = load_spc_data(config["DATA_PATH"]) | ||||
|  | ||||
|     app = Dash(external_stylesheets=[BOOTSTRAP]) | ||||
|     app = Dash(external_stylesheets=[dbc.themes.LUX]) | ||||
|     app.title = "Reliability Dashboard" | ||||
|     app.layout = create_layout(app, data) | ||||
|     app.run() | ||||
|  | ||||
										
											Binary file not shown.
										
									
								
							| @ -12,15 +12,15 @@ def render(app: Dash, data: pd.DataFrame) -> html.Div: | ||||
|         Output(ids.BAR_CHART, "children"), | ||||
|         [ | ||||
|             Input(ids.YEAR_DROPDOWN, "value"), | ||||
|             Input(ids.MONTH_DROPDOWN, "value"), | ||||
|             Input(ids.WEEK_DROPDOWN, "value"), | ||||
|             Input(ids.CATEGORY_DROPDOWN, "value"), | ||||
|         ], | ||||
|     ) | ||||
|     def update_bar_chart( | ||||
|         years: list[str], months: list[str], categories: list[str] | ||||
|         years: list[str], weeks: list[str], categories: list[str] | ||||
|     ) -> html.Div: | ||||
|         filtered_data = data.query( | ||||
|             "year in @years and month in @months and category in @categories" | ||||
|             "year in @years and week in @weeks and category in @categories" | ||||
|         ) | ||||
|  | ||||
|         if filtered_data.shape[0] == 0: | ||||
| @ -45,4 +45,4 @@ def render(app: Dash, data: pd.DataFrame) -> html.Div: | ||||
|  | ||||
|         return html.Div(dcc.Graph(figure=fig), id=ids.BAR_CHART) | ||||
|  | ||||
|     return html.Div(id=ids.BAR_CHART) | ||||
|     return html.Div(id=ids.BAR_CHART) | ||||
| @ -14,12 +14,12 @@ def render(app: Dash, data: pd.DataFrame) -> html.Div: | ||||
|         Output(ids.CATEGORY_DROPDOWN, "value"), | ||||
|         [ | ||||
|             Input(ids.YEAR_DROPDOWN, "value"), | ||||
|             Input(ids.MONTH_DROPDOWN, "value"), | ||||
|             Input(ids.WEEK_DROPDOWN, "value"), | ||||
|             Input(ids.SELECT_ALL_CATEGORIES_BUTTON, "n_clicks"), | ||||
|         ], | ||||
|     ) | ||||
|     def select_all_categories(years: list[str], months: list[str], _: int) -> list[str]: | ||||
|         filtered_data = data.query("year in @years and month in @months") | ||||
|     def select_all_categories(years: list[str], weeks: list[str], _: int) -> list[str]: | ||||
|         filtered_data = data.query("year in @years and week in @weeks") | ||||
|         return sorted(set(filtered_data[DataSchema.CATEGORY].tolist())) | ||||
|  | ||||
|     return html.Div( | ||||
| @ -42,4 +42,4 @@ def render(app: Dash, data: pd.DataFrame) -> html.Div: | ||||
|                 n_clicks=0, | ||||
|             ), | ||||
|         ], | ||||
|     ) | ||||
|     ) | ||||
| @ -1,40 +1,123 @@ | ||||
| import pandas as pd | ||||
| import plotly.express as px | ||||
| from dash import Dash, dcc, html | ||||
| from dash.dependencies import Input, Output | ||||
| from dash import Dash, dcc, html, dash_table, Input, Output, State, callback_context | ||||
| from datetime import datetime | ||||
| import os | ||||
| import dash_bootstrap_components as dbc | ||||
|  | ||||
| from ..data.loader import DataSchema | ||||
| from . import ids | ||||
|  | ||||
|  | ||||
| def render(app: Dash, data: pd.DataFrame) -> html.Div: | ||||
|     @app.callback( | ||||
|         Output(ids.BAR_CHART, "children"), | ||||
|         Output(ids.DATA_TABLE, "children"), | ||||
|         [ | ||||
|             Input(ids.YEAR_DROPDOWN, "value"), | ||||
|             Input(ids.MONTH_DROPDOWN, "value"), | ||||
|             Input(ids.WEEK_DROPDOWN, "value"), | ||||
|             Input(ids.CATEGORY_DROPDOWN, "value"), | ||||
|         ], | ||||
|     ) | ||||
|     def update_data_table( | ||||
|         years: list[str], months: list[str], categories: list[str] | ||||
|         years: list[str], weeks: list[str], categories: list[str] | ||||
|     ) -> html.Div: | ||||
|         filtered_data = data.query( | ||||
|             "year in @years and month in @months and category in @categories" | ||||
|             "year in @years and week in @weeks and category in @categories" | ||||
|         ) | ||||
|  | ||||
|         if filtered_data.shape[0] == 0: | ||||
|             return html.Div("No data selected.", id=ids.DATA_TABLE) | ||||
|         def create_pivot_table() -> pd.DataFrame: | ||||
|             pt = filtered_data.pivot_table( | ||||
|                 values=DataSchema.AMOUNT, | ||||
|                 index=[DataSchema.CATEGORY], | ||||
|                 aggfunc="sum", | ||||
|                 fill_value=0, | ||||
|                 dropna=False, | ||||
|             ) | ||||
|             return pt.reset_index().sort_values(DataSchema.AMOUNT, ascending=False) | ||||
|             return html.Div("No data selected.") | ||||
|  | ||||
|         return html.Div(dcc.Data_table(data=create_pivot_table(data), id=ids.DATA_TABLE) | ||||
|         pt = filtered_data.pivot_table( | ||||
|             values=DataSchema.AMOUNT, | ||||
|             index=[DataSchema.CATEGORY], | ||||
|             aggfunc="sum", | ||||
|             fill_value=0, | ||||
|             dropna=False, | ||||
|         ).reset_index().sort_values(DataSchema.AMOUNT, ascending=False) | ||||
|  | ||||
|     return html.Div(id=ids.DATA_TABLE) | ||||
|         columns = [{"name": i.capitalize(), "id": i} for i in pt.columns] | ||||
|  | ||||
|         return dash_table.DataTable( | ||||
|             id=ids.CATEGORY_TABLE, | ||||
|             data=pt.to_dict("records"), | ||||
|             columns=columns, | ||||
|             row_selectable='single', | ||||
|             selected_rows=[] | ||||
|         ) | ||||
|  | ||||
|     @app.callback( | ||||
|         Output(ids.FEEDBACK_MODAL, "is_open"), | ||||
|         Output(ids.FEEDBACK_MESSAGE, "children"), | ||||
|         Input(ids.CATEGORY_TABLE, "selected_rows"), | ||||
|         Input(ids.SAVE_FEEDBACK_BUTTON_POPUP, "n_clicks"), | ||||
|         Input(ids.CLOSE_FEEDBACK_BUTTON_POPUP, "n_clicks"), | ||||
|         State(ids.FEEDBACK_MODAL, "is_open"), | ||||
|         State(ids.CATEGORY_TABLE, "data"), | ||||
|         State(ids.FEEDBACK_INPUT, "value"), | ||||
|     ) | ||||
|     def handle_feedback_modal(selected_rows, save_clicks, close_clicks, is_open, data, comment): | ||||
|         ctx = callback_context | ||||
|         if not ctx.triggered: | ||||
|             return False, "" | ||||
|  | ||||
|         triggered_id = ctx.triggered[0]['prop_id'].split('.')[0] | ||||
|          | ||||
|         if triggered_id == ids.CATEGORY_TABLE and selected_rows: | ||||
|             return True, "" | ||||
|  | ||||
|         if triggered_id == ids.SAVE_FEEDBACK_BUTTON_POPUP and selected_rows: | ||||
|             selected_row_data = data[selected_rows[0]] | ||||
|             category = selected_row_data[DataSchema.CATEGORY] | ||||
|             timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S') | ||||
|             if not comment: | ||||
|                 comment = "" | ||||
|             feedback_data = f'{timestamp},{category},"{comment}"\n' | ||||
|             file_path = "data/feedback.csv" | ||||
|             try: | ||||
|                 is_new_file = not os.path.exists(file_path) or os.path.getsize(file_path) == 0 | ||||
|                 with open(file_path, "a") as f: | ||||
|                     if is_new_file: | ||||
|                         f.write("timestamp,category,comment\n") | ||||
|                     f.write(feedback_data) | ||||
|                 message = f"Feedback for category '{category}' has been saved successfully at {timestamp}." | ||||
|                 return False, message | ||||
|             except Exception as e: | ||||
|                 return True, "An error occurred while saving feedback." | ||||
|  | ||||
|         if triggered_id == ids.CLOSE_FEEDBACK_BUTTON_POPUP: | ||||
|             return False, "" | ||||
|  | ||||
|         return is_open, "" | ||||
|  | ||||
|     @app.callback( | ||||
|         Output("feedback-category-label", "children"), | ||||
|         Input(ids.CATEGORY_TABLE, "selected_rows"), | ||||
|         State(ids.CATEGORY_TABLE, "data"), | ||||
|         prevent_initial_call=True | ||||
|     ) | ||||
|     def update_feedback_category_label(selected_rows, data): | ||||
|         if selected_rows: | ||||
|             category = data[selected_rows[0]][DataSchema.CATEGORY] | ||||
|             return f"Category: {category}" | ||||
|         return "Category: " | ||||
|  | ||||
|     modal = dbc.Modal( | ||||
|         [ | ||||
|             dbc.ModalHeader(dbc.ModalTitle("Submit Feedback")), | ||||
|             dbc.ModalBody([ | ||||
|                 html.H6("Category: ", id="feedback-category-label"), | ||||
|                 dcc.Input(id=ids.FEEDBACK_INPUT, type='text', placeholder='Enter feedback...', style={'width': '100%'}), | ||||
|             ]), | ||||
|             dbc.ModalFooter([ | ||||
|                 dbc.Button("Save", id=ids.SAVE_FEEDBACK_BUTTON_POPUP, className="ms-auto", n_clicks=0), | ||||
|                 dbc.Button("Close", id=ids.CLOSE_FEEDBACK_BUTTON_POPUP, className="ms-auto", n_clicks=0) | ||||
|             ]), | ||||
|         ], | ||||
|         id=ids.FEEDBACK_MODAL, | ||||
|         is_open=False, | ||||
|     ) | ||||
|  | ||||
|     return html.Div([ | ||||
|         html.Div(id=ids.DATA_TABLE), | ||||
|         html.Div(id=ids.FEEDBACK_MESSAGE), | ||||
|         modal | ||||
|     ]) | ||||
							
								
								
									
										22
									
								
								src/components/explanation_tab.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/components/explanation_tab.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| from dash import Dash, dcc, html | ||||
|  | ||||
| def render(_: Dash) -> html.Div: | ||||
|     return html.Div([ | ||||
|         dcc.Markdown(""" | ||||
|             ### How to use this Dashboard | ||||
|  | ||||
|             **Dashboard Tab:** | ||||
|             - Use the dropdowns at the top to filter the data by year, week, and category. | ||||
|             - The bar chart shows the total amount per category for the selected period. | ||||
|             - The data table shows the detailed data. | ||||
|  | ||||
|             **Feedback:** | ||||
|             - In the data table on the Dashboard tab, you can select a row to provide feedback. | ||||
|             - A popup will appear where you can enter your comments for the selected category. | ||||
|             - Click "Save" to store your feedback. | ||||
|  | ||||
|             **Feedback Tab:** | ||||
|             - This tab displays all the feedback that has been submitted. | ||||
|             - The table on this tab updates automatically every 5 seconds. | ||||
|         """) | ||||
|     ]) | ||||
							
								
								
									
										27
									
								
								src/components/feedback_tab.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/components/feedback_tab.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | ||||
| from dash import Dash, dcc, html, dash_table | ||||
| from dash.dependencies import Input, Output | ||||
| import pandas as pd | ||||
|  | ||||
| def render(app: Dash) -> html.Div: | ||||
|     @app.callback( | ||||
|         Output("feedback-table-content", "children"), | ||||
|         Input("feedback-interval", "n_intervals") | ||||
|     ) | ||||
|     def update_feedback_table(_): | ||||
|         try: | ||||
|             feedback_df = pd.read_csv("data/feedback.csv") | ||||
|             return dash_table.DataTable( | ||||
|                 data=feedback_df.to_dict("records"), | ||||
|                 columns=[{"name": i, "id": i} for i in feedback_df.columns], | ||||
|                 page_size=10, | ||||
|             ) | ||||
|         except FileNotFoundError: | ||||
|             return html.P("No feedback submitted yet.") | ||||
|         except Exception as e: | ||||
|             return html.P(f"An error occurred: {e}") | ||||
|  | ||||
|     return html.Div([ | ||||
|         html.H4("Submitted Feedback"), | ||||
|         html.Div(id="feedback-table-content"), | ||||
|         dcc.Interval(id="feedback-interval", interval=5 * 1000, n_intervals=0) # 5 seconds | ||||
|     ]) | ||||
| @ -5,8 +5,16 @@ DATA_TABLE = "data-table" | ||||
| SELECT_ALL_CATEGORIES_BUTTON = "select-all-categories-button" | ||||
| CATEGORY_DROPDOWN = "category-dropdown" | ||||
|  | ||||
| SELECT_ALL_MONTHS_BUTTON = "select-all-months-button" | ||||
| MONTH_DROPDOWN = "month-dropdown" | ||||
|  | ||||
| YEAR_DROPDOWN = "year-dropdown" | ||||
| SELECT_ALL_YEARS_BUTTON = "select-all-years-button" | ||||
|  | ||||
| WEEK_DROPDOWN = "week-dropdown" | ||||
| SELECT_ALL_WEEKS_BUTTON = "select-all-weeks-button" | ||||
|  | ||||
| CATEGORY_TABLE = "category-table" | ||||
|  | ||||
| FEEDBACK_INPUT = "feedback-input" | ||||
| FEEDBACK_MESSAGE = "feedback-message" | ||||
| FEEDBACK_MODAL = "feedback-modal" | ||||
| SAVE_FEEDBACK_BUTTON_POPUP = "save-feedback-button-popup" | ||||
| CLOSE_FEEDBACK_BUTTON_POPUP = "close-feedback-button-popup" | ||||
| @ -1,29 +1,48 @@ | ||||
| import pandas as pd | ||||
| from dash import Dash, html | ||||
| from dash import Dash, dcc, html | ||||
| from src.components import ( | ||||
|     bar_chart, | ||||
|     category_dropdown, | ||||
|     month_dropdown, | ||||
|     data_table, | ||||
|     year_dropdown, | ||||
|     week_dropdown, | ||||
|     category_dropdown, | ||||
|     feedback_tab, | ||||
|     explanation_tab, | ||||
| ) | ||||
|  | ||||
|  | ||||
| def create_layout(app: Dash, data: pd.DataFrame) -> html.Div: | ||||
|     tab_content_style = {'height': 'calc(100vh - 220px)', 'overflowY': 'auto', 'padding': '15px'} | ||||
|  | ||||
|     return html.Div( | ||||
|         className="app-div", | ||||
|         children=[ | ||||
|             html.H1(app.title), | ||||
|             html.Hr(), | ||||
|             html.Div( | ||||
|                 className="dropdown-container", | ||||
|                 children=[ | ||||
|                     year_dropdown.render(app, data), | ||||
|                     month_dropdown.render(app, data), | ||||
|                     category_dropdown.render(app, data), | ||||
|                 ], | ||||
|             ), | ||||
|             bar_chart.render(app, data), | ||||
|             data_table.render(app, data), | ||||
|             dcc.Tabs(id="tabs", value='tab-dashboard', children=[ | ||||
|                 dcc.Tab(label='Dashboard', value='tab-dashboard', children=[ | ||||
|                     html.Div(style=tab_content_style, children=[ | ||||
|                         html.Div( | ||||
|                             className="dropdown-container", | ||||
|                             children=[ | ||||
|                                 year_dropdown.render(app, data), | ||||
|                                 week_dropdown.render(app, data), | ||||
|                                 category_dropdown.render(app, data), | ||||
|                             ], | ||||
|                         ), | ||||
|                         bar_chart.render(app, data), | ||||
|                         data_table.render(app, data), | ||||
|                     ]) | ||||
|                 ]), | ||||
|                 dcc.Tab(label='Feedback', value='tab-feedback', children=[ | ||||
|                     html.Div(style=tab_content_style, children=[ | ||||
|                         feedback_tab.render(app) | ||||
|                     ]) | ||||
|                 ]), | ||||
|                 dcc.Tab(label='Explanation', value='tab-explanation', children=[ | ||||
|                     html.Div(style=tab_content_style, children=[ | ||||
|                         explanation_tab.render(app) | ||||
|                     ]) | ||||
|                 ]), | ||||
|             ]), | ||||
|         ], | ||||
|     ) | ||||
|     ) | ||||
| @ -1,40 +0,0 @@ | ||||
| import pandas as pd | ||||
| from dash import Dash, dcc, html | ||||
| from dash.dependencies import Input, Output | ||||
|  | ||||
| from ..data.loader import DataSchema | ||||
| from . import ids | ||||
|  | ||||
|  | ||||
| def render(app: Dash, data: pd.DataFrame) -> html.Div: | ||||
|     all_months: list[str] = data[DataSchema.MONTH].tolist() | ||||
|     unique_months = sorted(set(all_months)) | ||||
|  | ||||
|     @app.callback( | ||||
|         Output(ids.MONTH_DROPDOWN, "value"), | ||||
|         [ | ||||
|             Input(ids.YEAR_DROPDOWN, "value"), | ||||
|             Input(ids.SELECT_ALL_MONTHS_BUTTON, "n_clicks"), | ||||
|         ], | ||||
|     ) | ||||
|     def select_all_months(years: list[str], _: int) -> list[str]: | ||||
|         filtered_data = data.query("year in @years") | ||||
|         return sorted(set(filtered_data[DataSchema.MONTH].tolist())) | ||||
|  | ||||
|     return html.Div( | ||||
|         children=[ | ||||
|             html.H6("Month"), | ||||
|             dcc.Dropdown( | ||||
|                 id=ids.MONTH_DROPDOWN, | ||||
|                 options=[{"label": month, "value": month} for month in unique_months], | ||||
|                 value=unique_months, | ||||
|                 multi=True, | ||||
|             ), | ||||
|             html.Button( | ||||
|                 className="dropdown-button", | ||||
|                 children=["Select All"], | ||||
|                 id=ids.SELECT_ALL_MONTHS_BUTTON, | ||||
|                 n_clicks=0, | ||||
|             ), | ||||
|         ] | ||||
|     ) | ||||
							
								
								
									
										53
									
								
								src/components/week_dropdown.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/components/week_dropdown.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,53 @@ | ||||
| import pandas as pd | ||||
| from dash import Dash, dcc, html | ||||
| from dash.dependencies import Input, Output | ||||
| from datetime import datetime, timedelta | ||||
|  | ||||
| from ..data.loader import DataSchema | ||||
| from . import ids | ||||
|  | ||||
| def render(app: Dash, data: pd.DataFrame) -> html.Div: | ||||
|     all_weeks: list[str] = data[DataSchema.WEEK].tolist() | ||||
|     unique_weeks = sorted(set(all_weeks), reverse=True) | ||||
|  | ||||
|     # determine default weeks (last 13) | ||||
|     today = datetime.now() | ||||
|     last_13_weeks = [] | ||||
|     for i in range(13): | ||||
|         date = today - timedelta(weeks=i) | ||||
|         year, week, _ = date.isocalendar() | ||||
|         last_13_weeks.append(f"{year}{week:02d}") | ||||
|  | ||||
|     default_weeks = [week for week in last_13_weeks if week in unique_weeks] | ||||
|     if not default_weeks and unique_weeks: | ||||
|         default_weeks = unique_weeks[:13] | ||||
|  | ||||
|  | ||||
|     @app.callback( | ||||
|         Output(ids.WEEK_DROPDOWN, "value"), | ||||
|         [ | ||||
|             Input(ids.YEAR_DROPDOWN, "value"), | ||||
|             Input(ids.SELECT_ALL_WEEKS_BUTTON, "n_clicks"), | ||||
|         ], | ||||
|     ) | ||||
|     def select_all_weeks(years: list[str], _: int) -> list[str]: | ||||
|         filtered_data = data.query("year in @years") | ||||
|         return sorted(set(filtered_data[DataSchema.WEEK].tolist())) | ||||
|  | ||||
|     return html.Div( | ||||
|         children=[ | ||||
|             html.H6("Week"), | ||||
|             dcc.Dropdown( | ||||
|                 id=ids.WEEK_DROPDOWN, | ||||
|                 options=[{"label": f"{week[:4]}-{week[4:]}", "value": week} for week in unique_weeks], | ||||
|                 value=default_weeks, | ||||
|                 multi=True, | ||||
|             ), | ||||
|             html.Button( | ||||
|                 className="dropdown-button", | ||||
|                 children=["Select All"], | ||||
|                 id=ids.SELECT_ALL_WEEKS_BUTTON, | ||||
|                 n_clicks=0, | ||||
|             ), | ||||
|         ] | ||||
|     ) | ||||
| @ -7,6 +7,7 @@ class DataSchema: | ||||
|     DATE = "date" | ||||
|     MONTH = "month" | ||||
|     YEAR = "year" | ||||
|     WEEK = "week" | ||||
|  | ||||
|  | ||||
| def load_transaction_data(path: str) -> pd.DataFrame: | ||||
| @ -22,4 +23,8 @@ def load_transaction_data(path: str) -> pd.DataFrame: | ||||
|     ) | ||||
|     data[DataSchema.YEAR] = data[DataSchema.DATE].dt.year.astype(str) | ||||
|     data[DataSchema.MONTH] = data[DataSchema.DATE].dt.month.astype(str) | ||||
|     return data | ||||
|     data[DataSchema.WEEK] = ( | ||||
|         data[DataSchema.DATE].dt.isocalendar().year.astype(str) | ||||
|         + data[DataSchema.DATE].dt.isocalendar().week.astype(str).str.zfill(2) | ||||
|     ) | ||||
|     return data | ||||
| @ -6,6 +6,7 @@ class DataSchema: | ||||
|     DATE = "date" | ||||
|     MONTH = "month" | ||||
|     YEAR = "year" | ||||
|     WEEK = "week" | ||||
|  | ||||
| class SPC_Schema: | ||||
|     FC = "FC" | ||||
| @ -30,4 +31,8 @@ def load_spc_data(path: str) -> pd.DataFrame: | ||||
|     ) | ||||
|     data[DataSchema.YEAR] = data[DataSchema.DATE].dt.year.astype(str) | ||||
|     data[DataSchema.MONTH] = data[DataSchema.DATE].dt.month.astype(str) | ||||
|     return data | ||||
|     data[DataSchema.WEEK] = ( | ||||
|         data[DataSchema.DATE].dt.isocalendar().year.astype(str) | ||||
|         + data[DataSchema.DATE].dt.isocalendar().week.astype(str).str.zfill(2) | ||||
|     ) | ||||
|     return data | ||||
		Reference in New Issue
	
	Block a user