123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- from .DataStream import EMchPosmap as pos_map, span_days, time_border, calc_interval
- from .MerchantReader import MerchantReader
- from matplotlib.figure import Figure
- from matplotlib import ticker
- from io import BytesIO
- import numpy as np
- from .algorithm import calc_mchratios, calc_morder_send
- import time as time
- import logging
- logger = logging.getLogger('painter')
- def allpathes(reader: MerchantReader, tuple_pathes: dict, days: list, spec=None):
- count = len(days)
- show_detail = True if len(list(tuple_pathes.keys())) == 1 else False
- if show_detail == False:
- all_datas = reader.init_data(count)
- else:
- all_datas = None
- for name, tup in tuple_pathes.items():
- mch_datas = reader.init_data(count)
- for _card_type, _spec in tup:
- if spec is not None and _spec != spec:
- continue
- if show_detail:
- detail_datas = reader.init_data(count)
- else:
- detail_datas = None
- for i, day in enumerate(days):
- data = reader.read(day, name, _card_type, _spec)
- if data is not None:
- column_pos = i * 86400
- view = mch_datas[:, column_pos:column_pos + 86400]
- view += data
- if show_detail:
- view = detail_datas[:, column_pos:column_pos + 86400]
- view += data
- if show_detail:
- yield name, _card_type, _spec, detail_datas
- if all_datas is not None:
- all_datas += mch_datas
- yield name, None, None, mch_datas
- if show_detail == False:
- yield 'all', None, None, all_datas
- class MerchantPainter(object):
- def __init__(self, start_time: int, end_time: int, mchids: set = None, card_types: set = None, spec: int = None, filter_wave: int = None):
- self._reader = MerchantReader()
- _start_time, _end_time, self._mchids, self._card_types, self._spec, self._filter_wave = start_time, end_time, mchids, card_types, spec, filter_wave
- if _end_time is None:
- _end_time = int(time.time())
- end_time = self._reader.near_stamp(_end_time, False)
- if end_time is None:
- raise Exception('data is empty')
- if _start_time is None or start_time > end_time:
- _start_time = end_time - 7200
- start_time = self._reader.near_stamp(_start_time, True)
- if start_time is None:
- raise Exception('data is empty')
- stime = lambda t: time.strftime('%d-%H:%M:%S', time.localtime(t))
- logger.debug("start_time %d , %s end_time=%s", start_time, stime(start_time), stime(end_time))
- interval = calc_interval(start_time, end_time)
- start_time = time_border(interval, start_time, True)
- end_time = time_border(interval, end_time, False)
- self._days = span_days(start_time, end_time)
- self._start_time = start_time
- self._end_time = end_time
- self._interval = interval
- pass
- def _fig_funs(self):
- def create():
- fig = Figure(figsize=(19, 8))
- ax = fig.subplots()
- ax.set_title('success ratio')
- ax.set(xlabel='time', ylabel='ratio')
- return ax, fig
- def flush(ax, fig, xticks=None, xlables=None, yticks=None, ylables=None):
- ax.yaxis.set_major_formatter(ticker.PercentFormatter(xmax=1, decimals=4))
- if xticks is not None:
- ax.set_xticks(ticks=xticks)
- if xlables is not None:
- ax.set_xticklabels(xlables)
- if yticks is not None:
- ax.set_yticks(ticks=yticks)
- if ylables is not None:
- ax.set_yticklabels(ylables)
- fig.autofmt_xdate()
- ax.grid()
- fig.subplots_adjust(left=0.1, right=0.8, top=0.95, bottom=0.1)
- ax.legend(bbox_to_anchor=(1, 1), loc='upper left')
- buf = BytesIO()
- fig.savefig(buf, format="png")
- return buf
- return create, flush
- def paint_ratios(self):
- tuple_pathes = self._reader.many_tuple_path(self._days, self._mchids, self._card_types, self._spec)
- gen = allpathes(self._reader, tuple_pathes, self._days, self._spec)
- if len(self._days) == 0:
- return BytesIO()
- day_stamp = self._days[0]
- fig_create, fig_flush = self._fig_funs()
- ax, fig = fig_create()
- x = np.array([d - self._start_time for d in range(self._start_time, self._end_time)])
- if self._filter_wave is not None and self._filter_wave > 1:
- window = np.ones(self._filter_wave) / self._filter_wave
- else:
- window = None
- for _mchid, _card_type, _spec, _data in gen:
- succ, count, y = calc_mchratios(_data, pos_map, self._start_time - day_stamp, self._end_time - day_stamp)
- y = np.convolve(y, window, 'same') if window is not None else y
- ax.plot(x, y, ls='-', label=self._label(chname=_mchid, succ=succ, count=count, card_type=_card_type, spec=_spec))
- xticks = [d - self._start_time for d in range(self._start_time, self._end_time + 1, self._interval)]
- xlables = [time.strftime('%d-%H:%M:%S', time.localtime(d + self._start_time)) for d in xticks]
- return fig_flush(ax, fig, xticks=xticks, xlables=xlables)
- def _label(self, chname, succ, count, card_type=None, spec=None):
- _card_type = None
- if card_type == 1:
- _card_type = 'SY'
- elif card_type == 2:
- _card_type = 'SH'
- elif card_type == 4:
- _card_type = 'YD'
- elif card_type == 5:
- _card_type = 'LT'
- elif card_type == 6:
- _card_type = 'DX'
- elif card_type == 7:
- _card_type = 'TH'
- lable = f"{chname}"
- if _card_type is not None:
- lable += f"-{_card_type}"
- if spec is not None:
- lable += f"-{spec}"
- if count > 0:
- ratio = round(succ * 100 / count, 2)
- else:
- ratio = 0.00
- lable += f":{succ}/{count}={ratio}%"
- return lable
- def _fig_bar_funs(self):
- def create():
- fig = Figure(figsize=(19, 8))
- ax = fig.subplots()
- ax.set_title('success ratio')
- ax.set(xlabel='time', ylabel='ratio')
- return ax, fig
- def flush(ax, fig, xticks=None, xlables=None, yticks=None, ylables=None):
- if xticks is not None:
- ax.set_xticks(ticks=xticks)
- if xlables is not None:
- ax.set_xticklabels(xlables)
- if yticks is not None:
- ax.set_yticks(ticks=yticks)
- if ylables is not None:
- ax.set_yticklabels(ylables)
- ax.grid()
- fig.autofmt_xdate()
- buf = BytesIO()
- fig.savefig(buf, format="png")
- return buf
- return create, flush
- def paint_refilling(self):
- tuple_pathes = self._reader.many_tuple_path(self._days, self._mchids, self._card_types, self._spec)
- gen = allpathes(self._reader, tuple_pathes, self._days, self._spec)
- if len(self._days) == 0:
- return BytesIO()
- day_stamp = self._days[0]
- fig_create, fig_flush = self._fig_bar_funs()
- ax, fig = fig_create()
- lables = list()
- datas = list()
- for _mchid, _card_type, _spec, _data in gen:
- if _mchid == 'all':
- continue
- lables.append(f"{_mchid}")
- ret = calc_morder_send(_data, pos_map, self._start_time - day_stamp, self._end_time - day_stamp)
- datas.append(ret)
- send_count, submit_count, succ_count, fail_count, amounts, lack = zip(*datas)
- width = 0.20
- x_asix = np.arange(len(lables))
- rect_send = ax.bar(x_asix - width * 0.5, list(send_count), width, label='send', align='center')
- rect_submit = ax.bar(x_asix - width * 1.5, list(submit_count), width, label='summit',align='center')
- rect_succ = ax.bar(x_asix + width * 0.5, list(succ_count), width, label='succ',align='center')
- rect_fail = ax.bar(x_asix + width * 1.5, list(fail_count), width, label='fail', align='center')
- ax.bar_label(rect_send, padding=3)
- # ax.bar_label(rect_submit, padding=3)
- # ax.bar_label(rect_succ, padding=3)
- # ax.bar_label(rect_fail, padding=3)
- return fig_flush(ax, fig, xticks=x_asix, xlables=lables)
|