messageboard-2020-06-09-1725.py
01234567890123456789012345678901234567890123456789012345678901234567890123456789









44084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463








45374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562 45634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594








470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736   473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763 476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811











                            <----SKIPPED LINES---->




    histograms_to_generate.append({'generate': 'bearing'})
  if which_histograms in ['distance', 'all']:
    histograms_to_generate.append({'generate': 'distance', 'exhaustive': True})
  if which_histograms in ['day_of_week', 'all']:
    histograms_to_generate.append({'generate': 'day_of_week'})
  if which_histograms in ['day_of_month', 'all']:
    histograms_to_generate.append({'generate': 'day_of_month'})

  if which_histograms in ['speed', 'all']:
    histograms_to_generate.append({'generate': 'speed', 'exhaustive': True})
  if which_histograms in ['aircraft_length', 'all']:
    histograms_to_generate.append({'generate': 'aircraft_length', 'exhaustive': True})
  if which_histograms in ['vert_rate', 'all']:
    histograms_to_generate.append({'generate': 'vert_rate', 'exhaustive': True})

  histograms_generated = []
  for histogram in histograms_to_generate:
    this_histogram = which_histograms
    if this_histogram == 'all':
      this_histogram = histogram['generate']
    (key, sort, title, hours) = HistogramSettingsKeySortTitle(
        this_histogram, hours, flights)

    # if multiple histograms are getting generated, this might take a few seconds;
    # logging a heartbeat with each histogram ensures that monitoring.py does not
    # mistake this pause for a hang.
    if heartbeat:
      Heartbeat()

    CreateSingleHistogramChart(
        flights,
        key,
        sort,
        title,
        truncate=histogram.get('truncate', TRUNCATE),
        hours=hours,
        exhaustive=histogram.get('exhaustive', False))

    filename = (
        WEBSERVER_IMAGE_RELATIVE_FOLDER +  # i.e.: images/
        filename_prefix +                  # i.e.: histogram_
        histogram['generate'] +            # i.e.: destination
        '.' + filename_suffix)             # i.e.: .png
    filepath = WEBSERVER_PATH + filename   # i.e.: /var/www/html/ + filename

    matplotlib.pyplot.savefig(filepath)
    matplotlib.pyplot.close()
    histograms_generated.append((histogram['generate'], filename))

  return histograms_generated


def MessageboardHistograms(
    flights,
    which_histograms,
    how_much_history,




                            <----SKIPPED LINES---->




        'suppress_percent_sign': True,
        'column_divider': '|',
        'absolute': True})
  if which_histograms in ['speed', 'all']:
    histograms_to_generate.append({
        'generate': 'speed',
        'columns': 2})
  if which_histograms in ['aircraft_length', 'all']:
    histograms_to_generate.append({
        'generate': 'aircraft_length',
        'columns': 3})
  if which_histograms in ['vert_rate', 'all']:
    histograms_to_generate.append({
        'generate': 'vert_rate',
        'columns': 2})

  for histogram in histograms_to_generate:
    this_histogram = which_histograms
    if this_histogram == 'all':
      this_histogram = histogram['generate']
    (key, sort, title, hours) = HistogramSettingsKeySortTitle(
        this_histogram, hours, flights)

    # if multiple histograms are getting generated, this might take a few seconds;
    # logging a heartbeat with each histogram ensures that monitoring.py does not
    # mistake this pause for a hang.

    Heartbeat()
    histogram = MessageboardHistogram(
        flights,
        key,
        sort,
        title,
        screen_limit=screen_limit,
        columns=histogram.get('columns', 2),
        suppress_percent_sign=histogram.get('suppress_percent_sign', False),
        column_divider=histogram.get('column_divider', ' '),
        data_summary=data_summary,
        hours=hours,
        absolute=histogram.get('absolute', False))
    messages.extend(histogram)

  messages = [(FLAG_MSG_HISTOGRAM, m) for m in messages]

  return messages


def MessageboardHistogram(
    data,
    keyfunction,
    sort_type,
    title,
    screen_limit=1,
    columns=2,
    column_divider=' ',
    data_summary=False,
    hours=0,
    suppress_percent_sign=False,
    absolute=False):




                            <----SKIPPED LINES---->




            # Otherwise, if it rounds to at least 0.1%, display i.e. '.5%'
            if values[index]/total*100 >= 0.95:
              value_string = '%2d' % round(values[index]/total*100)
            elif round(values[index]/total*1000)/10 >= 0.1:
              value_string = ('%.1f' % (round(values[index]/total*1000)/10))[1:]
            else:
              value_string = ' 0'
          key_value.append('%s %s%s' % (
              str(keys[index])[:column_key_width].ljust(column_key_width),
              value_string,
              printed_percent_sign))

      line = (column_divider.join(key_value)).upper()
      lines.append(line)

    split_flap_boards.append(lines)

  return split_flap_boards


def TriggerHistograms(flights, histogram_settings):
  """Triggers the text-based or web-based histograms.

  Based on the histogram settings, determines whether to generate text or image histograms
  (or both). For image histograms, also generates empty images for the histograms not
  created so that broken image links are not displayed in the webpage.

  Args:
    flights: List of flight attribute dictionaries.
    histogram_settings: Dictionary of histogram parameters.




  Returns:
    List of histogram messages, if text-based histograms are selected; empty list
    otherwise.
  """
  histogram_messages = []

  if histogram_settings['type'] in ('messageboard', 'both'):
    histogram_messages = MessageboardHistograms(
        flights,
        histogram_settings['histogram'],
        histogram_settings['histogram_history'],
        histogram_settings['histogram_max_screens'],
        histogram_settings.get('histogram_data_summary', False))
  if histogram_settings['type'] in ('images', 'both'):

    # Since Google Chrome seems to ignore all instructions to not cache, we need
    # to make sure we do not reuse file names - hence the epoch_string - and then
    # we need to 1) update the histograms.html file with the correct file links, and
    # 2) delete the images that are now obsolete.
    epoch_string = '%d_' % round(time.time())

    generated_histograms = ImageHistograms(
        flights,
        histogram_settings['histogram'],
        histogram_settings['histogram_history'],
        filename_prefix=HISTOGRAM_IMAGE_PREFIX + epoch_string)

    html_lines = ReadFile(HISTOGRAM_IMAGE_HTML).split('\n')
    replaced_images = []
    for identifier, new_filename in generated_histograms:
      # for each histogram, find the html_line with the matching id
      # Example line: <img id="destination" src="images/histogram_destination.png"><p>
      identifier = '"%s"' % identifier  # add quotations to make sure its complete
      n, line = None, None  # addresses pylint complaint
      found = False
      for n, line in enumerate(html_lines):
        if identifier in line:
          found = True
          break
        found = False
      if found:
        start_char = line.find(WEBSERVER_IMAGE_RELATIVE_FOLDER)
        end_character = (
            line.find(HISTOGRAM_IMAGE_SUFFIX, start_char) + len(HISTOGRAM_IMAGE_SUFFIX))
        old_filename = line[start_char:end_character]
        print(old_filename, new_filename)
        line = line.replace(old_filename, new_filename)
        html_lines[n] = line
        replaced_images.append(line[start_char:end_character])
    new_html = '\n'.join(html_lines)
    WriteFile(HISTOGRAM_IMAGE_HTML, new_html)

    # Remove those obsoleted files
    for f in replaced_images:
      RemoveFile(f)

  return histogram_messages


def SaveFlightsByAltitudeDistanceCSV(
    flights,
    max_days=0,
    filename='flights_by_alt_dist.csv',
    precision=100):
  """Extracts hourly histogram into text file for a variety of altitudes and distances.

  Generates a csv with 26 columns:
  - col#1: altitude (in feet)
  - col#2: distance (in feet)
  - cols#3-26: hour of the day

  The first row is a header row; subsequent rows list the number of flights that have
  occurred in the last max_days with an altitude and min distance less than that identified
  in the first two columns. Each row increments elevation or altitude by precision feet,
  up to the max determined by the max altitude and max distance amongst all the flights.




                            <----SKIPPED LINES---->





01234567890123456789012345678901234567890123456789012345678901234567890123456789









44084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463








45374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595








4708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786 47874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815











                            <----SKIPPED LINES---->




    histograms_to_generate.append({'generate': 'bearing'})
  if which_histograms in ['distance', 'all']:
    histograms_to_generate.append({'generate': 'distance', 'exhaustive': True})
  if which_histograms in ['day_of_week', 'all']:
    histograms_to_generate.append({'generate': 'day_of_week'})
  if which_histograms in ['day_of_month', 'all']:
    histograms_to_generate.append({'generate': 'day_of_month'})

  if which_histograms in ['speed', 'all']:
    histograms_to_generate.append({'generate': 'speed', 'exhaustive': True})
  if which_histograms in ['aircraft_length', 'all']:
    histograms_to_generate.append({'generate': 'aircraft_length', 'exhaustive': True})
  if which_histograms in ['vert_rate', 'all']:
    histograms_to_generate.append({'generate': 'vert_rate', 'exhaustive': True})

  histograms_generated = []
  for histogram in histograms_to_generate:
    this_histogram = which_histograms
    if this_histogram == 'all':
      this_histogram = histogram['generate']
    (key, sort, title, updated_hours) = HistogramSettingsKeySortTitle(
        this_histogram, hours, flights)

    # if multiple histograms are getting generated, this might take a few seconds;
    # logging a heartbeat with each histogram ensures that monitoring.py does not
    # mistake this pause for a hang.
    if heartbeat:
      Heartbeat()

    CreateSingleHistogramChart(
        flights,
        key,
        sort,
        title,
        truncate=histogram.get('truncate', TRUNCATE),
        hours=updated_hours,
        exhaustive=histogram.get('exhaustive', False))

    filename = (
        WEBSERVER_IMAGE_RELATIVE_FOLDER +  # i.e.: images/
        filename_prefix +                  # i.e.: histogram_
        histogram['generate'] +            # i.e.: destination
        '.' + filename_suffix)             # i.e.: .png
    filepath = WEBSERVER_PATH + filename   # i.e.: /var/www/html/ + filename

    matplotlib.pyplot.savefig(filepath)
    matplotlib.pyplot.close()
    histograms_generated.append((histogram['generate'], filename))

  return histograms_generated


def MessageboardHistograms(
    flights,
    which_histograms,
    how_much_history,




                            <----SKIPPED LINES---->




        'suppress_percent_sign': True,
        'column_divider': '|',
        'absolute': True})
  if which_histograms in ['speed', 'all']:
    histograms_to_generate.append({
        'generate': 'speed',
        'columns': 2})
  if which_histograms in ['aircraft_length', 'all']:
    histograms_to_generate.append({
        'generate': 'aircraft_length',
        'columns': 3})
  if which_histograms in ['vert_rate', 'all']:
    histograms_to_generate.append({
        'generate': 'vert_rate',
        'columns': 2})

  for histogram in histograms_to_generate:
    this_histogram = which_histograms
    if this_histogram == 'all':
      this_histogram = histogram['generate']
    (key, sort, title, updated_hours) = HistogramSettingsKeySortTitle(
        this_histogram, hours, flights)

    # if multiple histograms are getting generated, this might take a few seconds;
    # logging a heartbeat with each histogram ensures that monitoring.py does not
    # mistake this pause for a hang.
    if heartbeat:
      Heartbeat()
    histogram = MessageboardHistogram(
        flights,
        key,
        sort,
        title,
        screen_limit=screen_limit,
        columns=histogram.get('columns', 2),
        suppress_percent_sign=histogram.get('suppress_percent_sign', False),
        column_divider=histogram.get('column_divider', ' '),
        data_summary=data_summary,
        hours=updated_hours,
        absolute=histogram.get('absolute', False))
    messages.extend(histogram)

  messages = [(FLAG_MSG_HISTOGRAM, m) for m in messages]

  return messages


def MessageboardHistogram(
    data,
    keyfunction,
    sort_type,
    title,
    screen_limit=1,
    columns=2,
    column_divider=' ',
    data_summary=False,
    hours=0,
    suppress_percent_sign=False,
    absolute=False):




                            <----SKIPPED LINES---->




            # Otherwise, if it rounds to at least 0.1%, display i.e. '.5%'
            if values[index]/total*100 >= 0.95:
              value_string = '%2d' % round(values[index]/total*100)
            elif round(values[index]/total*1000)/10 >= 0.1:
              value_string = ('%.1f' % (round(values[index]/total*1000)/10))[1:]
            else:
              value_string = ' 0'
          key_value.append('%s %s%s' % (
              str(keys[index])[:column_key_width].ljust(column_key_width),
              value_string,
              printed_percent_sign))

      line = (column_divider.join(key_value)).upper()
      lines.append(line)

    split_flap_boards.append(lines)

  return split_flap_boards


def TriggerHistograms(flights, histogram_settings, heartbeat=True):
  """Triggers the text-based or web-based histograms.

  Based on the histogram settings, determines whether to generate text or image histograms
  (or both). For image histograms, also generates empty images for the histograms not
  created so that broken image links are not displayed in the webpage.

  Args:
    flights: List of flight attribute dictionaries.
    histogram_settings: Dictionary of histogram parameters.
    heartbeat: boolean indicating whether we should log heartbeats between each histogram
      to make sure monitoring does not mistake this slow procedure for being hung; this
      should be set to false if this is called from outside of messageboard.main.

  Returns:
    List of histogram messages, if text-based histograms are selected; empty list
    otherwise.
  """
  histogram_messages = []

  if histogram_settings['type'] in ('messageboard', 'both'):
    histogram_messages = MessageboardHistograms(
        flights,
        histogram_settings['histogram'],
        histogram_settings['histogram_history'],
        histogram_settings['histogram_max_screens'],
        histogram_settings.get('histogram_data_summary', False))
  if histogram_settings['type'] in ('images', 'both'):

    # Since Google Chrome seems to ignore all instructions to not cache, we need
    # to make sure we do not reuse file names - hence the epoch_string - and then
    # we need to 1) update the histograms.html file with the correct file links, and
    # 2) delete the images that are now obsolete.
    epoch_string = '%d_' % round(time.time())

    generated_histograms = ImageHistograms(
        flights,
        histogram_settings['histogram'],
        histogram_settings['histogram_history'],
        filename_prefix=HISTOGRAM_IMAGE_PREFIX + epoch_string,
        heartbeat=heartbeat)
    html_lines = ReadFile(HISTOGRAM_IMAGE_HTML).split('\n')
    replaced_images = []
    for identifier, new_filename in generated_histograms:
      # for each histogram, find the html_line with the matching id
      # Example line: <img id="destination" src="images/histogram_destination.png"><p>
      identifier = '"%s"' % identifier  # add quotations to make sure its complete
      n, line = None, None  # addresses pylint complaint
      found = False
      for n, line in enumerate(html_lines):
        if identifier in line:
          found = True
          break
        found = False
      if found:
        start_char = line.find(WEBSERVER_IMAGE_RELATIVE_FOLDER)
        end_character = (
            line.find(HISTOGRAM_IMAGE_SUFFIX, start_char) + len(HISTOGRAM_IMAGE_SUFFIX))
        old_filename = line[start_char:end_character]

        line = line.replace(old_filename, new_filename)
        html_lines[n] = line
        replaced_images.append(old_filename)
    new_html = '\n'.join(html_lines)
    WriteFile(HISTOGRAM_IMAGE_HTML, new_html)

    # Remove those obsoleted files
    for f in replaced_images:
      RemoveFile(WEBSERVER_PATH + f)

  return histogram_messages


def SaveFlightsByAltitudeDistanceCSV(
    flights,
    max_days=0,
    filename='flights_by_alt_dist.csv',
    precision=100):
  """Extracts hourly histogram into text file for a variety of altitudes and distances.

  Generates a csv with 26 columns:
  - col#1: altitude (in feet)
  - col#2: distance (in feet)
  - cols#3-26: hour of the day

  The first row is a header row; subsequent rows list the number of flights that have
  occurred in the last max_days with an altitude and min distance less than that identified
  in the first two columns. Each row increments elevation or altitude by precision feet,
  up to the max determined by the max altitude and max distance amongst all the flights.




                            <----SKIPPED LINES---->