Private
Public Access
1
0
Files
rowsandall/rowers/utils.py
Sander Roosendaal 3ba9bbf93a age calculations
2018-04-27 09:30:03 +02:00

371 lines
10 KiB
Python

import math
import numpy as np
import pandas as pd
import colorsys
from django.conf import settings
import uuid
import datetime
lbstoN = 4.44822
landingpages = (
('workout_edit_view','Edit View'),
('workout_workflow_view','Workflow View'),
)
workflowmiddlepanel = (
('panel_statcharts.html','Static Charts'),
('flexthumbnails.html','Flex Charts'),
('panel_summary.html','Summary'),
('panel_map.html','Map'),
('panel_comments.html','Basic Info and Links'),
('panel_notes.html','Workout Notes'),
('panel_shortcomment.html','Comment Link'),
('panel_middlesocial.html','Social Media Share Buttons'),
)
defaultmiddle = ['panel_middlesocial.html',
'panel_statcharts.html',
'flexthumbnails.html',
'panel_summary.html',
'panel_map.html']
workflowleftpanel = (
('panel_navigationheader.html','Navigation Header'),
('panel_editbuttons.html','Edit Workout Button'),
('panel_delete.html','Delete Workout Button'),
('panel_export.html','Export Workout Button'),
('panel_social.html','Social Media Share Buttons'),
('panel_advancededit.html','Advanced Workout Edit Button'),
('panel_editintervals.html','Edit Intervals Button'),
('panel_stats.html','Workout Statistics Button'),
('panel_flexchart.html','Flex Chart'),
('panel_staticchart.html','Create Static Charts Buttons'),
('panel_uploadimage.html','Attach Image'),
('panel_geekyheader.html','Geeky Header'),
('panel_editwind.html','Edit Wind Data'),
('panel_editstream.html','Edit Stream Data'),
('panel_otwpower.html','Run OTW Power Calculations'),
('panel_mapview.html','Map'),
('panel_ranking.html','Ranking View'),
)
defaultleft = [
'panel_navigationheader.html',
'panel_editbuttons.html',
'panel_advancededit.html',
'panel_editintervals.html',
'panel_stats.html',
'panel_staticchart.html',
'panel_uploadimage.html',
]
coxes_calls = [
'Sit Ready!',
"Let's relax the shoulders, and give me a power ten to the finish!",
"Almost there. Give me ten strokes on the legs!",
"Let it run!",
"Don't rush the slides!",
"Quick hands.",
"You are clearing the puddles.",
"Let's push through now. Get me that open water.",
"We're going for the line now. Power ten on the next.",
]
info_calls = [
"Please give us a minute to count all those strokes, you've been working hard!",
"Please give us a minute to count all your strokes."
]
import random
def get_call():
call1 = random.choice(coxes_calls)
call2 = random.choice(info_calls)
call = """<div id="id_sitready" class="successmessage">
<p>
%s (%s)
</p>
</div>
""" % (call1, call2)
return call
def absolute(request):
urls = {
'ABSOLUTE_ROOT': request.build_absolute_uri('/')[:-1].strip("/"),
'ABSOLUTE_ROOT_URL': request.build_absolute_uri('/').strip("/"),
'PATH':request.build_absolute_uri(),
}
return urls
def trcolors(r1,g1,b1,r2,g2,b2):
r1 = r1/255.
r2 = r2/255.
g1 = g1/255.
g2 = g2/255.
b2 = b2/255.
b1 = b1/255.
h1,s1,v1 = colorsys.rgb_to_hsv(r1,g1,b1)
h2,s2,v2 = colorsys.rgb_to_hsv(r2,g2,b2)
return 360*h1,360*(h2-h1),s1,(s2-s1),v1,(v2-v1)
palettes = {
'monochrome_blue':(207,-4,0.06,0.89,1.0,-0.38),
'gold_sunset':(47,-31,.26,-0.12,0.94,-0.5),
'blue_red':(207,-200,.85,0,.74,-.24),
'blue_green':(207,-120,.85,0,.75,.25),
'cyan_green':(192,-50,.08,.65,.98,-.34),
'cyan_purple':trcolors(237,248,251,136,65,157),
'green_blue':trcolors(240,249,232,8,104,172),
'orange_red':trcolors(254,240,217,179,0,0),
'cyan_blue':trcolors(241,238,246,4,90,141),
'cyan_green':trcolors(246,239,247,1,108,89),
'cyan_magenta':trcolors(241,238,246,152,0,67),
'beige_magenta':trcolors(254,235,226,122,1,119),
'yellow_green':trcolors(255,255,204,0,104,55),
'yellow_blue':trcolors(255,255,205,37,52,148),
'autumn':trcolors(255,255,212,153,52,4),
'yellow_red':trcolors(255,255,178,189,0,39)
}
rankingdistances = [100,500,1000,2000,5000,6000,10000,21097,42195,100000]
rankingdurations = []
rankingdurations.append(datetime.time(minute=1))
rankingdurations.append(datetime.time(minute=4))
rankingdurations.append(datetime.time(minute=30))
rankingdurations.append(datetime.time(hour=1,minute=15))
rankingdurations.append(datetime.time(hour=1))
def is_ranking_piece(workout):
if workout.distance in rankingdistances:
return True
elif workout.duration in rankingdurations:
return True
return False
def range_to_color_hex(groupcols,palette='monochrome_blue'):
try:
plt = palettes[palette]
except KeyError:
plt = palettes['monochrome_blue']
rgb = [colorsys.hsv_to_rgb((plt[0]+plt[1]*x)/360.,
plt[2]+plt[3]*x,
plt[4]+plt[5]*x) for x in groupcols]
RGB = [(int(255.*r),int(255.*g),int(255.*b)) for (r, g, b) in rgb]
colors = ["#%02x%02x%02x" % (r, g, b) for (r, g, b) in RGB]
return colors
def str2bool(v):
return v.lower() in ("yes", "true", "t", "1")
def uniqify(seq, idfun=None):
# order preserving
if idfun is None:
def idfun(x): return x
seen = {}
result = []
for item in seq:
marker = idfun(item)
# in old Python versions:
# if seen.has_key(marker)
# but in new ones:
if marker in seen: continue
seen[marker] = 1
result.append(item)
return result
def serialize_list(value,token=','):
assert(isinstance(value, list) or isinstance(value, tuple) or isinstance(value,np.ndarray))
return token.join([unicode(s) for s in value])
def deserialize_list(value,token=','):
if isinstance(value, list):
return value
elif isinstance(value, np.ndarray):
return value
return value.split(token)
def geo_distance(lat1,lon1,lat2,lon2):
""" Approximate distance and bearing between two points
defined by lat1,lon1 and lat2,lon2
This is a slight underestimate but is close enough for our purposes,
We're never moving more than 10 meters between trackpoints
Bearing calculation fails if one of the points is a pole.
(Hey, from the North pole you can walk South, East, North and end up
on the same spot!)
"""
# radius of our earth in km --> should be moved to settings if
# rowing takes off on other planets
R = 6373.0
# pi
pi = math.pi
lat1 = math.radians(lat1)
lat2 = math.radians(lat2)
lon1 = math.radians(lon1)
lon2 = math.radians(lon2)
dlon = lon2 - lon1
dlat = lat2 - lat1
a = math.sin(dlat / 2)**2 + math.cos(lat1) * math.cos(lat2) * math.sin(dlon / 2)**2
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
distance = R * c
tc1 = math.atan2(math.sin(lon2-lon1)*math.cos(lat2),
math.cos(lat1)*math.sin(lat2)-math.sin(lat1)*math.cos(lat2)*math.cos(lon2-lon1))
tc1 = tc1 % (2*pi)
bearing = math.degrees(tc1)
return [distance,bearing]
def isbreakthrough(delta,cpvalues,p0,p1,p2,p3,ratio):
pwr = abs(p0)/(1+(delta/abs(p2)))
pwr += abs(p1)/(1+(delta/abs(p3)))
dd = 0.25*(ratio-1)
pwr2 = pwr*(1+dd)
pwr *= ratio
delta = delta.values
cpvalues = cpvalues.values
res = np.sum(cpvalues>pwr)
res2 = np.sum(cpvalues>pwr2)
btdf = pd.DataFrame(
{
'delta':delta[cpvalues>pwr],
'cpvalues':cpvalues[cpvalues>pwr],
'pwr':pwr[cpvalues>pwr],
}
)
btdf.sort_values('delta',axis=0,inplace=True)
return res>1,btdf,res2>1
def myqueue(queue,function,*args,**kwargs):
if settings.DEBUG:
kwargs['debug'] = True
job = function.delay(*args,**kwargs)
else:
job_id = str(uuid.uuid4())
kwargs['job_id'] = job_id
kwargs['jobkey'] = job_id
job = queue.enqueue(function,*args,**kwargs)
return job
from datetime import date
def calculate_age(born):
today = date.today()
if born:
return today.year - born.year - ((today.month, today.day) < (born.month, born.day))
else:
return None
def my_dict_from_instance(instance,model):
thedict = {}
thedict['id'] = instance.id
for f in instance._meta.fields:
fname = f.name
try:
verbosename = f.verbose_name
except:
verbosename = f.name
get_choice = 'get_'+fname+'_display'
if hasattr( instance, get_choice):
value = getattr(instance, get_choice)()
else:
try:
value = getattr(instance,fname)
except AttributeError:
value = None
if f.editable and value:
thedict[fname] = (verbosename,value)
return thedict
def wavg(group, avg_name, weight_name):
""" http://stackoverflow.com/questions/10951341/pandas-dataframe-aggregate-function-using-multiple-columns
In rare instance, we may not have weights, so just return the mean. Customize this if your business case
should return otherwise.
"""
d = group[avg_name]
try:
w = group[weight_name]
except KeyError:
return d.mean()
try:
return (d * w).sum() / w.sum()
except ZeroDivisionError:
return d.mean()
def totaltime_sec_to_string(totaltime):
hours = int(totaltime / 3600.)
if hours > 23:
message = 'Warning: The workout duration was longer than 23 hours. '
hours = 23
minutes = int((totaltime - 3600. * hours) / 60.)
if minutes > 59:
minutes = 59
if not message:
message = 'Warning: there is something wrong with the workout duration'
seconds = int(totaltime - 3600. * hours - 60. * minutes)
if seconds > 59:
seconds = 59
if not message:
message = 'Warning: there is something wrong with the workout duration'
tenths = int(10 * (totaltime - 3600. * hours - 60. * minutes - seconds))
if tenths > 9:
tenths = 9
if not message:
message = 'Warning: there is something wrong with the workout duration'
duration = "%s:%s:%s.%s" % (hours, minutes, seconds, tenths)
return duration