def make_catalogs_or_indexes_change_ans(self, qt: str, answer: Answer, chain: TranslationChain, result: Result): tag = '目录' if qt == 'catalogs_change' else '指标' data = self._search_direct(chain) y = [len(item) for item in data] line = self.painter.paint_line(result['year'], f'{tag}个数', y, result.raw_question) answer.save_chart(line) answer.add_answer(f'该问题的回答已渲染为图像,详见:{CHART_RENDER_DIR}/{result.raw_question}.html')
def make_begin_stats_ans(self, answer: Answer, builder: AnswerBuilder, chain: TranslationChain, result: Result): data = self._search_direct(chain) builder.feed_data(data) for item, name in builder.product_data_with_name(result['index']): years = [int(year.name) for year in item] answer.add_answer(f'指标“{name.name}”最早于{min(years)}年开始统计')
def make_indexes_or_areas_trend_ans(self, qt: str, answer: Answer, builder: AnswerBuilder, chain: TranslationChain, result: Result, mark_point: bool = False): if qt == 'areas_trend': unpack = True gen = [result['area'], result['index']] else: unpack = False gen = [result['index']] # collect data = self._search_direct(chain, unpack=unpack) builder.feed_data(data) collects = [] # 根据不同单位划分数据 for item, name in builder.product_data_with_name(*gen): collect = [] units = set([n.unit for n in item if n.unit != '']) ys = builder.group_mapping_to_float(item) if builder.add_if_is_equal_or_not(sum(ys), 0, equal=False, no=f'指标“{name.subject()}”无任何值记录,无法比较'): for unit in units: tmp = [] for y, n in zip(ys, item): tmp.append(y if n.unit == unit else 0) collect.append((name.subject(), unit, tmp)) collects.append(collect) # paint if len(collects) != 0: bar = self.painter.paint_bar(result['year'], collects, title=result.raw_question, mark_point=mark_point) answer.save_chart(bar) answer.add_answer(f'该问题的回答已渲染为图像,详见:{CHART_RENDER_DIR}/{result.raw_question}.html')
def make_index_value_ans(self, answer: Answer, builder: AnswerBuilder, chain: TranslationChain, result: Result): data = self._search_direct(chain) builder.feed_data(data) for item, name in builder.product_data_with_name( result['index'], if_is_none=lambda _, na: f'无{na.subject()}数据记录' ): answer.add_answer(f'{name.subject()}为{item.val()}')
def make_catalog_status_ans(self, answer: Answer, builder: AnswerBuilder, chain: TranslationChain, result: Result): data = self._search_direct(chain) builder.feed_data(data) for item, name in builder.product_data_with_name( result['catalog'], if_is_none=lambda _, na: f'并没有关于{result["year"][0]}年{na.subject()}的描述' ): answer.add_answer(item.info)
def make_catalog_or_index_change_ans(self, qt: str, answer: Answer, builder: AnswerBuilder, chain: TranslationChain, result: Result): data = self._search_direct(chain) tag_name = '指标' if qt == 'index_change' else '目录' set1, set2 = set([n.name for n in data[0]]), set([n.name for n in data[1]]) diff1, diff2 = set1.difference(set2), set2.difference(set1) n1, n2 = len(diff1), len(diff2) if builder.add_if_is_equal_or_not( n1, 0, equal=False, no=f'{result["year"][1]}年与{result["year"][0]}年的{tag_name}相同' ): answer.add_answer(f'{result["year"][1]}年与{result["year"][0]}年相比,未统计{n1}个{tag_name}:' + '、'.join(diff1)) if builder.add_if_is_equal_or_not( n2, 0, equal=False, no=f'{result["year"][0]}年与{result["year"][1]}年的{tag_name}相同' ): answer.add_answer(f'{result["year"][0]}年与{result["year"][1]}年相比,未统计{n2}个{tag_name}:' + '、'.join(diff2))
def make_areas_g_compare_ans(self, answer: Answer, builder: AnswerBuilder, chain: TranslationChain, result: Result): data = self._search_direct(chain) builder.feed_data(data) for item, name in builder.product_data_with_name(result['area'], result['index']): x, y = item if builder.binary_decision( x, y, not_x=f'无{result["year"][0]}年关于{name.subject()}的数据', not_y=f'无{result["year"][0]}前一年关于{name.subject()}的数据' ): res = builder.growth_calculation(y.value, x.value) if builder.add_if_is_not_none( res, to_sub=False, no=f'{result["year"][0]}年{name.subject()}的记录非数值类型,无法计算' ): answer.add_answer(f'{result["year"][0]}年的{name.subject()}为{y.val()},' f'其去年的为{x.val()},同比{sign(res, ("减少", "增长"))}{abs(res)}%')
def make_index_or_area_2_overall_ans(self, qt: str, answer: Answer, builder: AnswerBuilder, chain: TranslationChain, result: Result): years = '、'.join(result['year']) # init if qt == 'area_2_overall': unpack = True gen = [result["area"], result["index"]] else: unpack = False gen = [result["index"]] # collect data data = self._search_double_direct_then_feed(chain, unpack=unpack) builder.feed_data(data) # product data for x, y, f, n in builder.product_data_with_feed( *gen, if_x_is_none=lambda _1, _2, _3, na: f'无{years}这几年{na.subject()}的数据记录,无法比较', if_y_is_none=lambda _1, _2, _3, na: f'无{years}这几年{na.subject()}的父级数据记录,无法比较' ): temp = [] # 记录两次计算的结果值 for i, year in enumerate(result["year"]): f.life_check(year) if not f: answer.add_answer(f'无{year}年{n.subject()}的父级数据记录,无法比较') continue unit_x, unit_y = x[i].unit, y[i].unit answer.begin_sub_answers() n.repr = x[i].repr answer.add_sub_answers(f'{year}年{n.subject()}为{x[i].value}{unit_x}') answer.add_sub_answers(f'其总体{f.name}{y[i].repr}为{y[i].value}{unit_y}') if unit_x != unit_y: answer.add_sub_answers('两者单位不同,无法比较') answer.end_sub_answers() continue res = builder.binary_calculation(x[i].value, y[i].value, truediv, percentage=True) if builder.add_if_is_not_none(res, no=f'无效的{n}值类型,无法比较'): answer.add_sub_answers(f'约占总体的{res}%') temp.append(res) answer.end_sub_answers() if len(temp) == 2: num = round(temp[0] - temp[1], 2) answer.add_answer(f'前者相比后者{sign(num, ("降低", "提高"))}{abs(num)}%')
def make_index_or_area_overall_ans(self, qt: str, answer: Answer, builder: AnswerBuilder, chain: TranslationChain, result: Result): if qt == 'index_overall': gen = [result['index']] tag = '指标' else: gen = [result['area'], result['index']] tag = '' data = self._search_double_direct_then_feed(chain) builder.feed_data(data) for x, y, f, n in builder.product_data_with_feed( *gen, if_x_is_none=lambda _1, _2, _3, na: f'无{na.subject()}的数据记录,无法比较', if_y_is_none=lambda _1, _2, _3, na: f'无{na.subject()}的父级{tag}数据记录,无法比较' ): f.life_check(result['year'][0]) if not f: answer.add_answer(f'无{n.subject()}父级{tag}数据记录,无法比较') return answer.begin_sub_answers() unit_x, unit_y = x.unit, y[0].unit if qt == 'area_overall': # 交换值域 f.area, f.name = f.name, n.name n.repr = f.repr = x.repr answer.add_sub_answers(f'{n.subject()}为{x.val()}') answer.add_sub_answers(f'其父级{tag}{f.subject()}为{y[0].val()}') if unit_x != unit_y: answer.add_sub_answers('两者单位不同,无法比较') answer.end_sub_answers() return res1 = builder.binary_calculation(x.value, y[0].value, truediv, percentage=True) if builder.add_if_is_not_none(res1, no=f'无效的{n.subject()}值类型,无法比较'): answer.add_sub_answers(f'前者占后者的{res1}%') res2 = builder.binary_calculation(y[0].value, x.value, truediv) if builder.add_if_is_not_none(res2, no=f'无效的{n.subject()}值类型,无法比较'): answer.add_sub_answers(f'后者是前者的{res2}倍') answer.end_sub_answers()
def make_indexes_or_areas_overall_trend_ans(self, qt: str, answer: Answer, builder: AnswerBuilder, chain: TranslationChain, result: Result): if qt == 'areas_overall_trend': unpack = True gen = [result["area"], result["index"]] else: unpack = False gen = [result["index"]] data = self._search_double_direct_then_feed(chain, unpack) builder.feed_data(data) parents = {} children = {} for x, y, f, n in builder.product_data_with_feed( *gen, if_x_is_none=lambda _1, _2, _3, na: f'无关于”{na.subject()}“的记录', if_y_is_none=lambda _1, _2, _3, na: f'无关于”{na.subject()}“的父级记录' ): xs = builder.group_mapping_to_float(x) if not builder.add_if_is_not_none(xs, to_sub=False, no=f'{n.subject()}的记录非数值类型,无法比较'): return parent = f.name + n.name if qt == 'areas_overall_trend' else f.name ys = builder.group_mapping_to_float(y) if not builder.add_if_is_not_none(ys, to_sub=False, no=f'{n.subject()}的父级记录({parent})非数值类型,无法比较'): return overall = [round(i / j, 3) if j != 0 else 0 for i, j in zip(xs, ys)] # 同一个父级指标将其子孙合并 parents[parent] = ys children.setdefault((parent, x[-1].unit), []).append((n.subject(), xs, overall)) # paint if len(parents) != 0: for bar in self.painter.paint_bar_stack_with_line(result['year'], children, parents, result.raw_question): answer.save_chart(bar) answer.add_answer(f'该问题的回答已渲染为图像,详见:{CHART_RENDER_DIR}/{result.raw_question}.html')
def make_index_compose_ans(self, answer: Answer, builder: AnswerBuilder, chain: TranslationChain, result: Result): data = self._search_direct(chain) builder.feed_data(data) collect = [] units = [] sub_titles = [] # for overall sqls_overall = [sql for sql in chain.iter(3)] data_overall = self._search_direct(sqls_overall) # collect for total, (item, name) in zip( data_overall, builder.product_data_with_name(result['index']) ): # 为使两可迭代对象同步迭代和collect不用做判空,此处不使用if_is_none参数 if not item: answer.add_answer(f'指标“{name.name}”没有任何组成') continue indexes, areas = [], [] for n in item: n.life_check(result['year'][0]) if n: if n.label == 'Index': indexes.append(n.name) else: areas.append(n.name) if len(indexes) == 0 and len(areas) == 0: answer.add_answer(f'指标“{name.name}”没有任何组成') continue # for indexes sqls1 = [sql.format(i) for sql in chain.iter(1) for i in indexes] data1 = self._search_direct(sqls1) # for areas sqls2 = [sql.format(name.name, a) for sql in chain.iter(2) for a in areas] data2 = self._search_direct(sqls2) # make data pairs final_data = {} for k, v in zip(indexes + areas, data1 + data2): if not v: continue if v.child_id is None: continue try: final_data.setdefault(v.child_id, []).append((k, float(v.value))) except ValueError or TypeError: answer.add_answer(f'{name.name}中{k}的记录非数值类型,无法比较') return # make other for k, v in final_data.items(): op1 = sum([x[1] for x in v]) op2 = float(total.value) if op1 < int(op2): # 舍弃一些误差,避免图中出现极小的部分 final_data[k].append(('其他', round(op2 - op1, 2))) collect.append(final_data) units.append(total.unit) sub_titles.append(f'{name.subject()}为{total.val()},其构成分为:') # paint for pie in self.painter.paint_pie(collect, units, title=result.raw_question, sub_titles=sub_titles): answer.save_chart(pie) answer.add_answer(f'该问题的回答已渲染为图像,详见:{CHART_RENDER_DIR}/{result.raw_question}.html')
def make_exist_catalog_ans(self, answer: Answer, chain: TranslationChain, result: Result): data = self._search_direct(chain) if not all(data): answer.add_answer(f'无{result["year"][0]}年的记录。') else: answer.add_answer(f'{result["year"][0]}年目录包括: ' + ','.join([item.name for item in data[0]]))
def make_year_status_ans(self, answer: Answer, chain: TranslationChain, result: Result): data = self._search_direct(chain) answer.add_answer(f'{result["year"][0]}年,{data[0].info}')