ChannelPainter.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. from .DataStream import EChPosmap as pos_map, day_stamp, span_days, time_border, calc_interval
  2. from .ChannelReader import ChannelReader
  3. from collections import defaultdict
  4. from matplotlib.figure import Figure
  5. from matplotlib import ticker
  6. from io import BytesIO
  7. import numpy as np
  8. from .algorithm import calc_chratios
  9. import time as time
  10. import logging
  11. logger = logging.getLogger('painter')
  12. def ratio_pathes(reader: ChannelReader, tuple_pathes: dict, days: list, spec=None):
  13. count = len(days)
  14. show_detail = True if len(list(tuple_pathes.keys())) == 1 else False
  15. if show_detail == False:
  16. all_datas = reader.init_data(count)
  17. else:
  18. all_datas = None
  19. for mchid, tup in tuple_pathes.items():
  20. ch_datas = reader.init_data(count)
  21. for _card_type, _spec in tup:
  22. if spec is not None and _spec != spec:
  23. continue
  24. if show_detail:
  25. detail_datas = reader.init_data(count)
  26. else:
  27. detail_datas = None
  28. for i, day in enumerate(days):
  29. data = reader.read(day, mchid, _card_type, _spec)
  30. if data is not None:
  31. column_pos = i * 86400
  32. view = ch_datas[:, column_pos:column_pos + 86400]
  33. view += data
  34. if show_detail:
  35. view = detail_datas[:, column_pos:column_pos + 86400]
  36. view += data
  37. if show_detail:
  38. yield mchid, _card_type, _spec, detail_datas
  39. if all_datas is not None:
  40. all_datas += ch_datas
  41. yield mchid, None, None, ch_datas
  42. if show_detail == False:
  43. yield 'all', None, None, all_datas
  44. class ChannelPainter(object):
  45. def __init__(self, start_time: int, end_time: int, chnames: set = None, card_types: set = None, spec: int = None, filter_wave: int = None):
  46. self._reader = ChannelReader()
  47. _start_time, _end_time, self._chnames, self._card_types, self._spec, self._filter_wave = start_time, end_time, chnames, card_types, spec, filter_wave
  48. if _end_time is None:
  49. _end_time = int(time.time())
  50. end_time = self._reader.near_stamp(_end_time, False)
  51. if end_time is None:
  52. raise Exception('data is empty')
  53. if _start_time is None or start_time > end_time:
  54. _start_time = end_time - 7200
  55. start_time = self._reader.near_stamp(_start_time, True)
  56. if start_time is None:
  57. raise Exception('data is empty')
  58. stime = lambda t: time.strftime('%d-%H:%M:%S', time.localtime(t))
  59. logger.debug("start_time=%s end_time=%s",stime(start_time) ,stime(end_time))
  60. interval = calc_interval(start_time, end_time)
  61. start_time = time_border(interval, start_time, True)
  62. end_time = time_border(interval, end_time, False)
  63. self._days = span_days(start_time, end_time)
  64. self._start_time = start_time
  65. self._end_time = end_time
  66. self._interval = interval
  67. pass
  68. def _fig_funs(self):
  69. def create():
  70. fig = Figure(figsize=(19, 8))
  71. ax = fig.subplots()
  72. ax.set_title('success ratio')
  73. ax.set(xlabel='time', ylabel='ratio')
  74. return ax, fig
  75. def flush(ax, fig, ticks, lables):
  76. ax.yaxis.set_major_formatter(ticker.PercentFormatter(xmax=1, decimals=4))
  77. ax.set_xticks(ticks=ticks)
  78. ax.set_xticklabels(lables)
  79. fig.autofmt_xdate()
  80. ax.grid()
  81. fig.subplots_adjust(left=0.1, right=0.8, top=0.95, bottom=0.1)
  82. ax.legend(bbox_to_anchor=(1, 1), loc='upper left')
  83. buf = BytesIO()
  84. fig.savefig(buf, format="png")
  85. return buf
  86. return create, flush
  87. def paint(self):
  88. reader = ChannelReader()
  89. tuple_pathes = reader.many_tuple_path(self._days, self._chnames, self._card_types, self._spec)
  90. gen = ratio_pathes(self._reader, tuple_pathes, self._days, self._spec)
  91. if len(self._days) == 0:
  92. return BytesIO()
  93. day_stamp = self._days[0]
  94. fig_create, fig_flush = self._fig_funs()
  95. ax, fig = fig_create()
  96. x = np.array([d - self._start_time for d in range(self._start_time, self._end_time)])
  97. if self._filter_wave is not None and self._filter_wave > 1:
  98. window = np.ones(self._filter_wave) / self._filter_wave
  99. else:
  100. window = None
  101. for _chname, _card_type, _spec, _data in gen:
  102. succ, count, y = calc_chratios(_data, pos_map, self._start_time - day_stamp, self._end_time - day_stamp)
  103. y = np.convolve(y, window, 'same') if window is not None else y
  104. ax.plot(x, y, ls='-', label=self._label(chname=_chname, succ=succ, count=count, card_type=_card_type, spec=_spec))
  105. ticks = [d - self._start_time for d in range(self._start_time, self._end_time + 1, self._interval)]
  106. xlables = [time.strftime('%d-%H:%M:%S', time.localtime(d + self._start_time)) for d in ticks]
  107. return fig_flush(ax, fig, ticks, xlables)
  108. def _label(self, chname, succ, count, card_type=None, spec=None):
  109. _card_type = None
  110. if card_type == 1:
  111. _card_type = 'SY'
  112. elif card_type == 2:
  113. _card_type = 'SH'
  114. elif card_type == 4:
  115. _card_type = 'YD'
  116. elif card_type == 5:
  117. _card_type = 'LT'
  118. elif card_type == 6:
  119. _card_type = 'DX'
  120. elif card_type == 7:
  121. _card_type = 'TH'
  122. lable = f"{chname}"
  123. if _card_type is not None:
  124. lable += f"-{_card_type}"
  125. if spec is not None:
  126. lable += f"-{spec}"
  127. if count > 0:
  128. ratio = round(succ * 100 / count, 2)
  129. else:
  130. ratio = 0.00
  131. lable += f":{succ}/{count}={ratio}%"
  132. return lable