diff --git a/GSS/GSSutils/data_read.py b/GSS/GSSutils/data_read.py
index 461de70..6f56df4 100755
--- a/GSS/GSSutils/data_read.py
+++ b/GSS/GSSutils/data_read.py
@@ -26,17 +26,19 @@
cols = ['Activity number','Activity Type','Date','Distance','Time','Shoes','Rise','Fall','1km','1 mile','1.5 mile','3 mile','5km','5 mile','10km','10 mile','20km','Half','Full','C10k','C20k','C50k','C100k','C200k','C250k','Run Rankings','Notes','Admin']
-dist_dict = {'1km': 1000,
- '1 mile': 1609.34,
- '1.5 mile': 2414.02,
- '3 mile': 4828.03,
- '5km': 5000,
- '5 mile': 8046.72,
- '10km': 10000,
- '10 mile': 16093.40,
- '20km': 20000,
- 'Half': 21097.7,
- 'Full': 42195}
+dist_dict = {
+ '1km': 1000,
+ '1 mile': 1609.34,
+ '1.5 mile': 2414.02,
+ '3 mile': 4828.03,
+ '5km': 5000,
+ '5 mile': 8046.72,
+ '10km': 10000,
+ '10 mile': 16093.40,
+ '20km': 20000,
+ 'Half': 21097.7,
+ 'Full': 42195
+}
dist_list = list(dist_dict.keys())
@@ -546,10 +548,14 @@ def route_data(activity_number):
return(df)
'''
-def pull_csv_pd(activity_number,option='column_name'):
+def generate_gpx_archive_filename(activity_number: str)->str:
fileDir = os.path.dirname(os.path.realpath('__file__'))
+
+ return os.path.join(fileDir, 'GPXarchive.gitignore/activity_{}.csv'.format(activity_number))
- filename = os.path.join(fileDir, 'GPXarchive.gitignore/activity_{}.csv'.format(activity_number))
+def pull_csv_pd(activity_number, option='column_name'):
+
+ filename = generate_gpx_archive_filename(activity_number)
#I think I only need distance and time
@@ -567,11 +573,9 @@ def pull_csv_pd(activity_number,option='column_name'):
return(df)
-def route_data(activity_number,option='column_name'):
- #if len(activity_number) == 10:
- # df = pull_gpx(activity_number)
- #if len(activity_number) == 8 or len(activity_number) == 9:
- df = pull_csv_pd(activity_number,option)
+def route_data(activity_number, option='column_name'):
+
+ df = pull_csv_pd(activity_number, option)
return(df)
@@ -601,7 +605,7 @@ def __init__(self, activity_id):
#Date-related qualities
self.date_str = self.activity_dict['Date']
- self.date_dt = datetime.strptime(self.date_str, '%Y-%m-%d %H:%M:%S')
+ self.date_dt = datetime.strptime(self.date_str, '%Y-%m-%d %H:%M:%S')# if isinstance(self.date_str, str) else self.date_str
self.date = self.strftime('%Y-%m-%d')
self.time = self.strftime('%H:%M:%S')
self.year, self.month, self.day = (round(float(self.strftime(fmt))) for fmt in ('%Y', '%m', '%d'))
diff --git a/GSS/GSSutils/editing.py b/GSS/GSSutils/editing.py
index cf82c3f..faa91aa 100755
--- a/GSS/GSSutils/editing.py
+++ b/GSS/GSSutils/editing.py
@@ -1,10 +1,3 @@
-# -*- coding: utf-8 -*-
-"""
-Created on Sun Feb 21 09:03:26 2021
-
-@author: WS
-"""
-
import haversine
import os
import pandas as pd
@@ -12,8 +5,7 @@
from math import sqrt
from datetime import datetime
-from typing import List
-
+from typing import Dict, List, Optional, Tuple
from . import data_read as dr
from . import loading_modules as lm
@@ -67,23 +59,55 @@ def reset_distance_column(a_df: pd.DataFrame, include_altitude=False)->List[floa
distances.append(new)
return distances
+
+def recalculate_and_return_best_distances(df: pd.DataFrame, activity_number: str, final_distance: Optional[float] = None)->Tuple[pd.DataFrame, Dict[str, str]]:
+
+ filename = dr.generate_gpx_archive_filename(activity_number)
+
+ if not final_distance:
+ final_distance = df['Distance'].tolist()[-1]
+
+ times = {}
+
+ for i in dr.dist_list:
+ if final_distance >= dr.dist_dict[i]:
+ df = lm.best_time_ws(i, df)
+ df.to_csv(r'{}'.format(filename))
+ print(df.columns)
+
+ times[i] = lm.best_time_ws(i, df, True)
-def reset_distances(user_df,activity_number,column,new, include_distance=False):
- """
- Turning off the distance resetting in favour of just resetting the times
+ return df, times
+
+def reset_best_times(user_df: pd.DataFrame, activity_number: str, best_times: Dict[str, str])->pd.DataFrame:
+ for d in dr.dist_list:
+ user_df.loc[user_df['Activity number']==activity_number, d] = best_times.get(d) or 'NONE'
+ return user_df
+
+def reset_activity_time(user_df: pd.DataFrame, activity_df: pd.DataFrame, activity_number: str)->pd.DataFrame:
+ times = activity_df['time'].tolist()
+
+ duration = times[-1] - times[0]
+
+ full_secs = duration.total_seconds()
+
+ user_df.loc[user_df['Activity number']==activity_number, ['Time']] = time.strftime('%H:%M:%S',time.gmtime(full_secs))
+ return user_df
+
+def reset_distances(user_df, activity_number, column, new, include_distance=False)->None:
+ """
+ NOTE: Turning off the distance resetting in favour of just resetting the times
"""
location = user_df.loc[user_df['Activity number'] == activity_number].index.values[0]
- fileDir = os.path.dirname(os.path.realpath('__file__'))
-
- filename = os.path.join(fileDir, 'GPXarchive.gitignore/activity_{}.csv'.format(activity_number))
+ filename = dr.generate_gpx_archive_filename(activity_number)
a_df = pd.read_csv(r'{}'.format(filename))
- archive = os.path.join(fileDir, 'GPXarchive.gitignore/activity_{}_a.csv'.format(activity_number))
+ archive = dr.generate_gpx_archive_filename(activity_number+'_a')
a_df.to_csv(archive)
@@ -91,7 +115,6 @@ def reset_distances(user_df,activity_number,column,new, include_distance=False):
cols = [c for c in cols if c in list(a_df.columns)]
a_df = a_df[cols]
-
if include_distance:
a_df['distance'] = reset_distance_column(a_df)
@@ -101,21 +124,14 @@ def reset_distances(user_df,activity_number,column,new, include_distance=False):
a_df['time'] = a_df['time'].apply(lambda x: datetime.strptime(x,'%Y-%m-%d %H:%M:%S'))
- times = {}
-
+ best_times = {}
+
if activity == 'Running':
- for i in dr.dist_list:
- if final_distance >= dr.dist_dict[i]:
- a_df = lm.best_time_ws(i, a_df)
-
- a_df.to_csv(r'{}'.format(filename))
-
- times[i] = lm.best_time_ws(i, a_df, True)
-
- a_df = a_df[cols+list(times.keys())]
+ a_df, best_times = recalculate_and_return_best_distances(a_df, activity_number, final_distance)
+
+ a_df = a_df[cols+list(best_times.keys())]
- for i in dr.dist_list:
- user_df.at[location, i] = times.get(i) or 'NONE'
+ user_df = reset_best_times(user_df, activity_number, best_times)
user_df.at[location, 'Distance'] = round(final_distance/1000,2)
@@ -131,18 +147,85 @@ def reset_distances(user_df,activity_number,column,new, include_distance=False):
user_df.at[location, 'Notes'] = notes
- times = a_df['time'].tolist()
+ user_df.at[location, 'Date'] = datetime.strftime(a_df['time'].tolist()[0], '%Y-%m-%d %H:%M:%S')
- user_df.at[location, 'Date'] = times[0]
+ user_df = reset_activity_time(user_df, a_df, activity_number)
- duration = times[-1] - times[0]
- full_secs = duration.total_seconds()
+ user_df.to_csv('activities.csv',index=False)
+
+def remove_activity_from_df(user_df: pd.DataFrame, activity_number: str)->None:
+ """
+ Removes the database
+ Does not remove the activity.csv file
+ """
+
+ user_df = user_df[user_df['Activity number'] != activity_number]
- user_df.at[location, 'Time'] = time.strftime('%H:%M:%S',time.gmtime(full_secs))
-
user_df.to_csv('activities.csv',index=False)
+
+def merge_activities(user_df: pd.DataFrame, this_activity: str, activity_to_merge: str, **kwargs)->None:
+ """
+ Adds records for activity_to_merge to this_activity
+ Removes this activity_to_merge from activities df
+ Runs best times if appropriate
+ """
+ archive_name = dr.generate_gpx_archive_filename(this_activity+'_a')
+ this_activity_bool = user_df['Activity number'] == this_activity
+ to_merge_bool = user_df['Activity number'] == activity_to_merge
+
+ this_activity_df = dr.route_data(this_activity)
+ this_activity_filename = dr.generate_gpx_archive_filename(this_activity)
+
+ this_activity_df.to_csv(archive_name)
+
+ to_merge = dr.route_data(activity_to_merge)
+
+ df = pd.concat([this_activity_df, to_merge])
+
+ df = df.sort_values(by=['time'], ascending=True)
-def download_as_csv(activity_number,suffix):
+ df['distance'] = df['distance'].diff(periods=1).fillna(0).apply(lambda x: 0 if x<0 else x).cumsum().apply(lambda x: round(x, 2))
+ #shift(1).fillna(0)#.cumsum() # from 0->X, 0-Y to 0->X+Y
+ # there is no elapsed time equivalent
+
+ if 'alt' in df.columns:
+ df['alt'] = df['alt'].fillna(0)
+ # a hack, admittedly, but when I wrote this it was a coastal route that kept returning na
+
+ final_distance = df['distance'].tolist()[-1]
+
+ user_df.loc[this_activity_bool, ['Distance']] = round(final_distance/1000, 2)
+ user_df = reset_activity_time(user_df, df, this_activity)
+
+ for measure in ['Rise', 'Fall']:
+ this_activity_measure = user_df.loc[this_activity_bool, measure].tolist()[0]
+ to_merge_measure = user_df.loc[to_merge_bool, measure].tolist()[0]
+ if this_activity_measure != 'NONE' and to_merge_measure != 'NONE':
+ if isinstance(this_activity_measure, str):
+ this_activity_measure = float(this_activity_measure)
+ if isinstance(to_merge_measure, str):
+ to_merge_measure = float(to_merge_measure)
+ # would be good to convert to the classes with typing
+
+ new_measure = this_activity_measure + to_merge_measure
+ new_measure = f'{round(new_measure,1)}'
+ else:
+ new_measure = 'NONE'
+ user_df.loc[this_activity_bool, measure] = new_measure
+
+ activity_type = user_df.loc[this_activity_bool, 'Activity Type'].tolist()[0]
+
+ if activity_type == 'Running':
+ df, best_times = recalculate_and_return_best_distances(df, this_activity, final_distance)
+ user_df = reset_best_times(user_df, this_activity, best_times)
+ else:
+ df.to_csv(r'{}'.format(this_activity_filename))
+
+ user_df.to_csv('activities.csv', index=False)
+
+ # remove_activity_from_df(user_df, activity_to_merge)
+
+def download_as_csv(activity_number, suffix):
fileDir = os.path.dirname(os.path.realpath('__file__'))
@@ -165,14 +248,18 @@ def add_csv(x:str)->str:
return output_filename
-
def gen_trkpt(route_data: pd.Series)->str:
time = str(route_data['time']).replace(' ', 'T') + '.000Z'
+
+ if 'alt' in route_data.index:
+ elevation = f" Type
+ Type
or type the desired filename into the url bar"""
+ download_as_gpx_prompt = "Download"
+ removal_prompt = "If you're sure, confirm removal"
+
+ simple_prompt_conversion = {
+ 'download_csv': download_as_csv_prompt,
+ 'download_gpx': download_as_gpx_prompt,
+ 'merge_with': 'Enter id of activity to merge with',
+ 'Remove': removal_prompt
+ }
+
+ if column in simple_prompt_conversion:
+
+ text = simple_prompt_conversion[column]
+
+ elif column == 'Shoes':
s_df = user_df[['Date','Shoes']].sort_values(by='Date',ascending=False)
s_df['Shoes'] = s_df['Shoes'].fillna('NONE')
@@ -234,31 +335,25 @@ def shoes_link(shoe):
Remember that dictionaries must be in the form {"Shoes 1": 5.00, "Shoes 2": 5.00} for 5km in Shoes 1
and Shoes 2, with double and not single quotes
'''
-
-
-
- elif column == 'download_csv':
- text = """Download or archive
-
or type the desired filename into the url bar
- """
-
- elif column == 'download_gpx':
- text = "Download"
else:
+
text = 'To amend, add to url with underscores in lieu of spaces'
return text
-def edit_field(user_df,activity_number,column,new, activity: dr.Activity):
+def edit_field(user_df, activity_number, column, new, activity: dr.Activity):
+ """
+ Note column is capitalised
+ """
location = user_df.loc[user_df['Activity number'] == activity_number].index.values[0]
- allowed = ['Notes','Admin','Activity Type','Shoes']#At some point do type, but, for the moment, that contains a space
+ edit_fields = ['Notes','Admin','Activity Type','Shoes']#At some point do type, but, for the moment, that contains a space
column = format_url(column)
- if column in allowed:
+ if column in edit_fields:
print(user_df[column].dtype)
@@ -277,7 +372,7 @@ def edit_field(user_df,activity_number,column,new, activity: dr.Activity):
elif column == 'Reset':
- reset_distances(user_df,activity_number,column,new)
+ reset_distances(user_df,activity_number,column,new, False)
out = 'File reset'
@@ -291,8 +386,14 @@ def edit_field(user_df,activity_number,column,new, activity: dr.Activity):
path = download_as_gpx(activity)
out = 'GPX downloaded'
-
+
+ elif column == 'Remove':
+ remove_activity_from_df(user_df, activity_number)
+ out = 'Activity removed'
+ elif column == 'Merge with':
+ merge_activities(user_df, activity_number, new)
+ out = f'{new} activity merged with {activity_number}'
else:
out = f'{column} not editable'
diff --git a/GSS/htmls.py b/GSS/htmls.py
index 589304f..f52a52a 100755
--- a/GSS/htmls.py
+++ b/GSS/htmls.py
@@ -451,7 +451,7 @@ def edit_prompt(field):
return prompt
-def return_edit(ac_no,field,new_string, activity):
+def return_edit(ac_no, field, new_string, activity):
user_df = dr.pull_data()
diff --git a/GSS/templates/edit_index.html b/GSS/templates/edit_index.html
index a451904..7aff072 100755
--- a/GSS/templates/edit_index.html
+++ b/GSS/templates/edit_index.html
@@ -13,14 +13,20 @@
-
+
Shoes
- Notes
- Admin
- Download csv
- Download GPX
- Reset
+ Admin
+ Download csv
+ Download GPX
+ Reset
+ Merge with
+ Delete
+