Browse Source

HUE-8178 [charts] Improve timeline intervals for weeks & months

jdesjean 7 years ago
parent
commit
7e5e9ecb4a
1 changed files with 61 additions and 45 deletions
  1. 61 45
      desktop/libs/dashboard/src/dashboard/facet_builder.py

+ 61 - 45
desktop/libs/dashboard/src/dashboard/facet_builder.py

@@ -40,41 +40,8 @@ DAY_MS = HOUR_MS * 24
 WEEK_MS = DAY_MS * 7
 MONTH_MS = DAY_MS * 30
 YEAR_MS = DAY_MS * 365
-TIME_INTERVALS = [
-  {'ms': SECOND_MS * 1, 'base_ms': SECOND_MS, 'coeff': '1', 'unit': 'SECONDS'},
-  {'ms': SECOND_MS * 2, 'base_ms': SECOND_MS, 'coeff': '2', 'unit': 'SECONDS'},
-  {'ms': SECOND_MS * 5, 'base_ms': SECOND_MS, 'coeff': '5', 'unit': 'SECONDS'},
-  {'ms': SECOND_MS * 10, 'base_ms': SECOND_MS, 'coeff': '10', 'unit': 'SECONDS'},
-  {'ms': SECOND_MS * 15, 'base_ms': SECOND_MS, 'coeff': '15', 'unit': 'SECONDS'},
-  {'ms': SECOND_MS * 30, 'base_ms': SECOND_MS, 'coeff': '30', 'unit': 'SECONDS'},
-  {'ms': MINUTE_MS * 1, 'base_ms': MINUTE_MS, 'coeff': '1', 'unit': 'MINUTES'},
-  {'ms': MINUTE_MS * 2, 'base_ms': MINUTE_MS, 'coeff': '2', 'unit': 'MINUTES'},
-  {'ms': MINUTE_MS * 5, 'base_ms': MINUTE_MS, 'coeff': '5', 'unit': 'MINUTES'},
-  {'ms': MINUTE_MS * 10, 'base_ms': MINUTE_MS, 'coeff': '10', 'unit': 'MINUTES'},
-  {'ms': MINUTE_MS * 15, 'base_ms': MINUTE_MS, 'coeff': '15', 'unit': 'MINUTES'},
-  {'ms': MINUTE_MS * 30, 'base_ms': MINUTE_MS, 'coeff': '30', 'unit': 'MINUTES'},
-  {'ms': HOUR_MS * 1, 'base_ms': HOUR_MS, 'coeff': '1', 'unit': 'HOURS'},
-  {'ms': HOUR_MS * 2, 'base_ms': HOUR_MS, 'coeff': '2', 'unit': 'HOURS'},
-  {'ms': HOUR_MS * 4, 'base_ms': HOUR_MS, 'coeff': '4', 'unit': 'HOURS'},
-  {'ms': HOUR_MS * 6, 'base_ms': HOUR_MS, 'coeff': '6', 'unit': 'HOURS'},
-  {'ms': HOUR_MS * 8, 'base_ms': HOUR_MS, 'coeff': '8', 'unit': 'HOURS'},
-  {'ms': HOUR_MS * 12, 'base_ms': HOUR_MS, 'coeff': '12', 'unit': 'HOURS'},
-  {'ms': DAY_MS * 1, 'base_ms': DAY_MS, 'coeff': '1', 'unit': 'DAYS'},
-  {'ms': DAY_MS * 2, 'base_ms': DAY_MS, 'coeff': '2', 'unit': 'DAYS'},
-  {'ms': WEEK_MS * 1, 'base_ms': DAY_MS, 'coeff': '7', 'unit': 'DAYS'},
-  {'ms': WEEK_MS * 2, 'base_ms': DAY_MS, 'coeff': '14', 'unit': 'DAYS'},
-  {'ms': MONTH_MS * 1, 'base_ms': MONTH_MS, 'coeff': '1', 'unit': 'MONTHS'},
-  {'ms': MONTH_MS * 2, 'base_ms': MONTH_MS, 'coeff': '2', 'unit': 'MONTHS'},
-  {'ms': MONTH_MS * 3, 'base_ms': MONTH_MS, 'coeff': '3', 'unit': 'MONTHS'},
-  {'ms': MONTH_MS * 6, 'base_ms': MONTH_MS, 'coeff': '6', 'unit': 'MONTHS'},
-  {'ms': YEAR_MS * 1, 'base_ms': YEAR_MS, 'coeff': '1', 'unit': 'YEARS'}];
-TIME_INTERVAL_SORTED = [{'key': 'microsecond', 'value': 0},
-                        {'key': 'second', 'value': 0},
-                        {'key': 'minute', 'value': 0},
-                        {'key': 'hour', 'value': 0},
-                        {'key': 'day', 'value': 1},
-                        {'key': 'month', 'value': 1}]
 TIME_INTERVALS_MS = {
+  'MICROSECONDS': MS,
   'SECONDS': SECOND_MS,
   'MINUTES': MINUTE_MS,
   'HOURS': HOUR_MS,
@@ -83,6 +50,44 @@ TIME_INTERVALS_MS = {
   'MONTHS': MONTH_MS,
   'YEARS': YEAR_MS
 }
+TIME_INTERVALS_STARTING_VALUE = {
+  'microsecond': 0,
+  'second': 0,
+  'minute': 0,
+  'hour': 0,
+  'day': 1,
+  'month': 1
+}
+TIME_INTERVAL_SORTED = ['microsecond', 'second', 'minute', 'hour', 'day', 'month']
+TIME_INTERVALS = [
+  {'coeff': 1, 'unit': 'SECONDS'},
+  {'coeff': 2, 'unit': 'SECONDS'},
+  {'coeff': 5, 'unit': 'SECONDS'},
+  {'coeff': 10, 'unit': 'SECONDS'},
+  {'coeff': 15, 'unit': 'SECONDS'},
+  {'coeff': 30, 'unit': 'SECONDS'},
+  {'coeff': 1, 'unit': 'MINUTES'},
+  {'coeff': 2, 'unit': 'MINUTES'},
+  {'coeff': 5, 'unit': 'MINUTES'},
+  {'coeff': 10, 'unit': 'MINUTES'},
+  {'coeff': 15, 'unit': 'MINUTES'},
+  {'coeff': 30, 'unit': 'MINUTES'},
+  {'coeff': 1, 'unit': 'HOURS'},
+  {'coeff': 2, 'unit': 'HOURS'},
+  {'coeff': 4, 'unit': 'HOURS'},
+  {'coeff': 6, 'unit': 'HOURS'},
+  {'coeff': 8, 'unit': 'HOURS'},
+  {'coeff': 12, 'unit': 'HOURS'},
+  {'coeff': 1, 'unit': 'DAYS'},
+  {'coeff': 2, 'unit': 'DAYS'},
+  {'coeff': 7, 'unit': 'DAYS', 'start_relative': 'WEEKS'},
+  {'coeff': 14, 'unit': 'DAYS', 'start_relative': 'WEEKS'},
+  {'coeff': 1, 'unit': 'MONTHS'},
+  {'coeff': 3, 'unit': 'MONTHS'},
+  {'coeff': 6, 'unit': 'MONTHS'},
+  {'coeff': 1, 'unit': 'YEARS'}];
+for interval in TIME_INTERVALS:
+  interval['ms'] = TIME_INTERVALS_MS[interval['unit']] * interval['coeff']
 
 def utf_quoter(what):
   return urllib.quote(unicode(what).encode('utf-8'), safe='~@#$&()*!+=:;,.?/\'')
@@ -104,7 +109,7 @@ def _get_interval(domain_ms, SLOTS):
   biggest_interval_is_too_small = domain_ms / biggest_interval['ms'] > SLOTS
   if biggest_interval_is_too_small:
     coeff = min(ceil(domain_ms / SLOTS), 100) # If we go over 100 years, something has gone wrong.
-    return {'ms': YEAR_MS * coeff, 'base_ms': YEAR_MS, 'coeff': coeff, 'unit': 'YEARS'}
+    return {'ms': YEAR_MS * coeff, 'coeff': coeff, 'unit': 'YEARS'}
 
   for i in range(len(TIME_INTERVALS) - 2, 0, -1):
     slots = domain_ms / TIME_INTERVALS[i]['ms']
@@ -114,7 +119,7 @@ def _get_interval(domain_ms, SLOTS):
   return TIME_INTERVALS[0]
 
 def _format_interval(interval):
-  return '+' + interval['coeff'] + interval['unit']
+  return '+' + str(interval['coeff']) + interval['unit']
 
 def _get_interval_duration(text):
   regex = re.search('.*-(\d*)(.*)', text)
@@ -129,23 +134,33 @@ def _clamp_date(interval, time):
   gap_duration_lower = interval['unit'].lower()
   gap_duration_lowers = gap_duration_lower[:-1]  # Removes 's'
   for time_interval in TIME_INTERVAL_SORTED:
-    if time_interval['key'] != gap_duration_lowers:
-      kwargs = {time_interval['key']: time_interval['value']}
+    if time_interval != gap_duration_lowers:
+      kwargs = {time_interval: TIME_INTERVALS_STARTING_VALUE[time_interval]}
       time = time.replace(**kwargs)
     else:
       break
   return time
 
 def _get_next_interval(interval, start_time, do_at_least_once):
-  gap_duration_lower = interval['unit'].lower()
-  gap_duration_lowers = gap_duration_lower[:-1]  # Removes 's'
-  gap_duration = int(interval['coeff'])
   time = start_time
-  while getattr(time, gap_duration_lowers) % gap_duration or (do_at_least_once and time == start_time): # Do while
-    kwargs = {gap_duration_lower: 1}
-    time = time + relativedelta(time, **kwargs)
+  if interval.get('start_relative'):
+    time = time + relativedelta(weekday=MO)
+  else:
+    gap_duration_lower = interval['unit'].lower()
+    gap_duration_lowers = gap_duration_lower[:-1]  # Removes 's'
+    gap_duration = int(interval['coeff'])
+    while (getattr(time, gap_duration_lowers) - TIME_INTERVALS_STARTING_VALUE[gap_duration_lowers]) % gap_duration or (do_at_least_once and time == start_time): # Do while
+      kwargs = {gap_duration_lower: 1}
+      time = time + relativedelta(**kwargs)
+
   return time
 
+def _remove_duration(interval, nb_slot, time):
+  gap_duration_lower = interval['unit'].lower()
+  gap_duration = int(interval['coeff']) * nb_slot
+  kwargs = {gap_duration_lower: -1 * gap_duration}
+  return time + relativedelta(**kwargs)
+
 def _compute_range_facet(widget_type, stat_facet, properties, start=None, end=None, gap=None, SLOTS=0, window_size=None):
     if SLOTS == 0:
       if widget_type == 'pie-widget' or widget_type == 'pie2-widget':
@@ -225,11 +240,12 @@ def _compute_range_facet(widget_type, stat_facet, properties, start=None, end=No
       is_date = True
       domain_ms = _get_interval_duration(stat_facet['min'])
       interval = _get_interval(domain_ms, SLOTS)
+      nb_slot = domain_ms / interval['ms']
       gap = _format_interval(interval)
       end_ts = datetime.utcnow()
       end_ts_clamped = _clamp_date(interval, end_ts)
       end_ts = _get_next_interval(interval, end_ts_clamped, end_ts_clamped != end_ts)
-      start_ts = end_ts - timedelta(milliseconds=domain_ms)
+      start_ts = _remove_duration(interval, nb_slot, end_ts)
       stats_max = end = end_ts.strftime('%Y-%m-%dT%H:%M:%SZ')
       stats_min = start = start_ts.strftime('%Y-%m-%dT%H:%M:%SZ')