Ejemplo n.º 1
0
    def update(self, elapsed):
        Painter.update(self, elapsed)
        self.set_dirty() # always dirty

        # choose steering
        if self._target:
            # steer toward target
            target_direction = math.atan((self._target.x - self._relative_position.x)/(self._target.y - self._relative_position.y))
            if self._target.y < self._relative_position.y:
                target_direction += math.pi
            target_direction %= math.pi * 2
            delta = (target_direction - self._direction)
            if (target_direction > self._direction and delta < math.pi) or (target_direction < self._direction and math.fabs(delta) > math.pi):
                self._direction = (self._direction + 0.1) % (math.pi * 2)
            else:
                self._direction = (self._direction - 0.1) % (math.pi * 2)
        else:
            # wander
            self._direction += (random.random() - 0.5) % (math.pi * 2)

        # update position
        distance = elapsed * Human.SPEED * self._scale
        self.set_relative_position(self._relative_position + Point(math.sin(self._direction) * distance, math.cos(self._direction) * distance))

        self._rotation = self._direction

        
        """
Ejemplo n.º 2
0
 def __init__(self, game_map, position):
     """Place a circular notification on the map that will disappear after
     *timeout* milliseconds
     """
     position = Point(position.x, position.y, 1000) - (Point(Ping.RADIUS, Ping.RADIUS) * (float(game_map._scale) / 16))
     Painter.__init__(self, game_map, Point(Ping.RADIUS * 2 / (float(game_map._scale) / 16), Ping.RADIUS * 2 / (float(game_map._scale) / 16)), position)
     self.__age = 0 # in ms
Ejemplo n.º 3
0
 def update(self, elapsed):
     Painter.update(self, elapsed)
     self.set_dirty()
     self.__age += elapsed
     if self.expired():
         self._parent_painter.remove(self)
     else:
         progress = self.__age / float(Ping.TIMEOUT)
         color = pygame.color.Color(255, 0, 0, 255 - int(255 * progress))
         self._surface.fill(pygame.Color(0,0,0,0))
         pygame.draw.circle(self._surface, color, (Ping.RADIUS, Ping.RADIUS), max(4, int(Ping.RADIUS * progress)), 1)
     self.set_surface(self._surface)
Ejemplo n.º 4
0
 def __init__(self, game_map, position):
     # Place a human on the map
     position = Point(position.x, position.y, 5) - (Point(Human.WIDTH / 2, Human.HEIGHT / 2) * game_map._scale)
     self._scale = 16
     surface = pygame.Surface((Human.WIDTH * self._scale, Human.HEIGHT * self._scale)).convert_alpha()
     top = (Human.WIDTH * self._scale / 2, 0)
     left = (0, Human.HEIGHT * self._scale)
     right = (Human.WIDTH * self._scale, Human.HEIGHT * self._scale)
     pygame.draw.polygon(surface, Human.COLOR, (top, left, right), 1)
     
     Painter.__init__(self, game_map, Point(Human.WIDTH, Human.HEIGHT), position, surface)
     Human.all.append(self)
     self._direction = 0
     self._target = None
Ejemplo n.º 5
0
    def __init__(self, view_size, parent_painter):
        self._log = logging.getLogger("map")
        print "building mountains"
        terrain = pygame.image.load(os.path.abspath(os.path.join("media", "PerlinNoise2d.png"))).convert()
        self.coordinates = []
        terrain_array = pygame.surfarray.pixels2d(terrain)
        for x in xrange(0, len(terrain_array)):
            self.coordinates.append([])
            for y in xrange(0, len(terrain_array[x])):
                h, s, v, a = terrain.unmap_rgb(terrain_array[x][y]).hsva
                if v < 50: # water
                    self.coordinates[x].append(False)
                    terrain_array[x][y] = terrain.map_rgb(70 - (50 - v), 70 - (50 - v), 100 + v * 2)
                else: # land
                    self.coordinates[x].append(True)
                    terrain_array[x][y] = terrain.map_rgb(70 - v * 0.1, v * 1.5, 40 + v * 0.3)

        print "digging oceans"
        surface = pygame.transform.scale(terrain, (terrain.get_width() * 16, terrain.get_height() * 16))
        Painter.__init__(self, parent_painter, Point(0,0), Point(0,0,0), surface, Point(0,0))
Ejemplo n.º 6
0
 def __init__(self, parent_painter, size = Point(0, 0), relative_position = Point(0, 0, 1000), surface = None):
     Painter.__init__(self, parent_painter, size, relative_position, surface)
     pygame.time.set_timer(UPDATE_FPS_PAINTER_EVENT, 1000)
Ejemplo n.º 7
0
 def update(self, elapsed):
     Painter.update(self, elapsed)
     self.set_surface(Painter.font.render("FPS: %0.2f" % GameState.clock.get_fps(), True, (255,255,255)))
Ejemplo n.º 8
0
 def __init__(self):
     self.graph = Graph(URI, auth=(USERNAME, PASSWORD))
     self.painter = Painter()
Ejemplo n.º 9
0
class AnswerSearcher:

    def __init__(self):
        self.graph = Graph(URI, auth=(USERNAME, PASSWORD))
        self.painter = Painter()

    def search(self, result: Result) -> [Answer]:
        debug('||QUESTION ORIGINAL||', result.raw_question)
        debug('||QUESTION FILTERED||', result.filtered_question)
        answers = []
        for qt, chain in result.sqls.items():
            answer = self.organize(qt, chain, result)
            answers.append(answer)
        return answers

    def _search_direct(self, sql_gen, offset: int = 0, unpack: bool = False) -> list:
        """ 进行直接查询 """
        # 只支持双层列表的嵌套,有第三层列表嵌套时令unpack=True

        def perform_sql(query_sql: str):
            rs = self.graph.run(query_sql).data()
            if len(rs) > 1:
                return [Formatter(r) for r in rs]
            elif len(rs) == 1:
                return Formatter(rs[0])
            else:
                return Formatter(rs)

        results = []
        if isinstance(sql_gen, TranslationChain):
            generator = sql_gen.iter(offset, unpack)
        else:
            generator = sql_gen
        for sqls in generator:
            debug('||GENERATED SQL||', sqls)
            if isinstance(sqls, list):
                sub_results = []
                for sql in sqls:
                    if sql is None:
                        sub_results.append(Formatter(None))
                        continue
                    sub_results.append(perform_sql(sql))
                results.append(sub_results)
            else:
                sql = sqls
                if sql is None:
                    results.append(Formatter(None))
                    continue
                results.append(perform_sql(sql))
        return results

    def _search_direct_then_feed(self, chain: TranslationChain, unpack_key_name: str) -> tuple:
        """ 将第一次直接查询的结果作为第二次查询的输入 """
        results_1 = self._search_direct(chain)
        pattern_sql = next(chain.iter(1))
        sqls = []
        for items in results_1:
            if not items:
                sqls.append(None)
                continue
            for item in items:
                sqls.append(pattern_sql.format(item[unpack_key_name]))
        results_2 = self._search_direct(sqls)
        return results_1, results_2

    def _search_double_direct_then_feed(self, chain: TranslationChain, unpack: bool = False) -> tuple:
        """ 第一次直接查询,第二次先执行直接查询后将查询结果投递至最后的查询 """
        results_1 = self._search_direct(chain, unpack=unpack)
        temp_res = self._search_direct(chain, 1)
        final_sqls = []
        for feed in temp_res:
            sqls = []
            for pattern_sql in chain.iter(2, unpack=unpack):
                if not feed:
                    sqls.append(None)
                    continue
                sqls.append(pattern_sql.format(feed.name))
            final_sqls.append(sqls)
        results_2 = self._search_direct(final_sqls)
        return results_1, results_2, temp_res

    def organize(self, qt: str, chain: TranslationChain, result: Result) -> Answer:
        answer = Answer()
        builder = AnswerBuilder(answer)
        # 年度总体状况
        if qt == 'year_status':
            self.make_year_status_ans(answer, chain, result)
        # 年度目录状况
        elif qt == 'catalog_status':
            self.make_catalog_status_ans(answer, builder, chain, result)
        # 年度目录包含哪些
        elif qt == 'exist_catalog':
            self.make_exist_catalog_ans(answer, chain, result)
        # 指标值
        elif qt == 'index_value':
            self.make_index_value_ans(answer, builder, chain, result)
        # 指标占总比 & 地区指标占总比
        elif qt in ('index_overall', 'area_overall'):
            self.make_index_or_area_overall_ans(qt, answer, builder, chain, result)
        # 指标组成
        elif qt == 'index_compose':
            self.make_index_compose_ans(answer, builder, chain, result)
        # 指标倍数比较(只有两个指标) & 指标数量比较(只有两个指标)
        elif qt in ('indexes_m_compare', 'indexes_n_compare'):
            self.make_indexes_m_or_n_compare_ans(qt, answer, builder, chain, result)
        elif qt in ('indexes_2m_compare', 'indexes_2n_compare', 'areas_2m_compare', 'areas_2n_compare'):
            self.make_indexes_or_areas_2m_or_2n_compare_ans(qt, answer, builder, chain, result)
        # 指标值同比比较
        elif qt == 'indexes_g_compare':
            self.make_indexes_g_compare_ans(answer, builder, chain, result)
        # 地区指标值
        elif qt == 'area_value':
            self.make_area_value_ans(answer, builder, chain, result)
        # 地区指标占总比的变化 & 指标占总比的变化
        elif qt in ('area_2_overall', 'index_2_overall'):
            self.make_index_or_area_2_overall_ans(qt, answer, builder, chain, result)
        # 地区指标倍数比较(只有两个地区) & 地区指标数量比较(只有两个地区)
        elif qt in ('areas_m_compare', 'areas_n_compare'):
            self.make_areas_m_or_n_compare_ans(qt, answer, builder, chain, result)
        # 地区指标值同比比较
        elif qt == 'areas_g_compare':
            self.make_areas_g_compare_ans(answer, builder, chain, result)
        # 两年目录的变化 & 两年指标的变化
        elif qt in ('catalog_change', 'index_change'):
            self.make_catalog_or_index_change_ans(qt, answer, builder, chain, result)
        # 多年目录的变化 & 多年指标的变化
        elif qt in ('catalogs_change', 'indexes_change'):
            self.make_catalogs_or_indexes_change_ans(qt, answer, chain, result)
        # 指标值变化(多年份)
        elif qt in ('indexes_trend', 'areas_trend'):
            self.make_indexes_or_areas_trend_ans(qt, answer, builder, chain, result)
        # 占总指标比的变化
        elif qt in ('indexes_overall_trend', 'areas_overall_trend'):
            self.make_indexes_or_areas_overall_trend_ans(qt, answer, builder, chain, result)
        # 几个年份中的最值
        elif qt in ('indexes_max', 'areas_max'):
            self.make_indexes_or_areas_max_ans(qt, answer, builder, chain, result)
        # 何时开始统计此指标
        elif qt == 'begin_stats':
            self.make_begin_stats_ans(answer, builder, chain, result)

        return answer

    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}')

    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_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_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_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_indexes_m_or_n_compare_ans(self, qt: str, answer: Answer, builder: AnswerBuilder,
                                        chain: TranslationChain, result: Result):
        data = self._search_direct(chain)
        builder.feed_data(data)
        operator = truediv if qt == 'indexes_m_compare' else sub
        for (x, y), (n1, n2) in builder.product_data_with_binary(
                result['index'],
                if_x_is_none=lambda _1, _2, na: f'无{na[0].subject()}数据记录,无法比较',
                if_y_is_none=lambda _1, _2, na: f'无{na[1].subject()}数据记录,无法比较'
        ):
            # 单位检查
            ux, uy = x.unit or '无', y.unit or '无'
            if builder.add_if_is_equal_or_not(ux, uy,
                                              no=f'{n1.subject()}的单位({ux})与{n2.subject()}的单位({uy})不同,无法比较'):
                answer.begin_sub_answers()
                answer.add_sub_answers(f'{n1.subject()}为{x.val()},{n2.subject()}为{y.val()}')
                res1 = builder.binary_calculation(x.value, y.value, operator)
                if builder.add_if_is_not_none(res1,
                                              no=f'{n1.subject()}或{n2.subject()}非数值类型,无法比较'):
                    if qt == 'indexes_m_compare':
                        answer.add_sub_answers(f'前者是后者的{res1}倍')
                    else:
                        answer.add_sub_answers(f'前者比后者{sign(res1)}{abs(res1)}{ux}')
                if qt == 'indexes_m_compare':
                    res2 = builder.binary_calculation(y.value, x.value, truediv)
                    if builder.add_if_is_not_none(res2,
                                                  no=f'{n1.subject()}或{n2.subject()}非数值类型,无法比较'):
                        answer.add_sub_answers(f'后者是前者的{res2}倍')
                answer.end_sub_answers()

    def make_indexes_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['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_area_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['area'], result['index'],
                if_is_none=lambda _, na: f'{na.subject()}无数据记录'
        ):
            name.repr = item.repr
            answer.add_answer(f'{name.subject()}为{item.value}{item.unit}')

    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_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_areas_m_or_n_compare_ans(self, qt: str, answer: Answer, builder: AnswerBuilder,
                                      chain: TranslationChain, result: Result):
        data = self._search_direct(chain)
        operator = truediv if qt == 'areas_m_compare' else sub
        builder.feed_data(data)
        for (x, y), (n1, n2) in builder.product_data_with_binary(
                result['area'], result['index'],
                if_x_is_none=lambda _1, _2, na: f'无{na[0].subject()}数据记录,无法比较',
                if_y_is_none=lambda _1, _2, na: f'无{na[1].subject()}数据记录,无法比较'
        ):
            # 单位检查
            ux, uy = x.unit or '无', y.unit or '无'
            if builder.add_if_is_equal_or_not(ux, uy,
                                              no=f'{n1.subject()}的单位({ux})与{n2.subject()}的单位({uy})不同,无法比较'):
                answer.begin_sub_answers()
                n1.repr, n2.repr = x.repr, y.repr
                answer.add_sub_answers(f'{n1.subject()}为{x.val()},{n2.subject()}为{y.val()}')
                res1 = builder.binary_calculation(x.value, y.value, operator)
                if builder.add_if_is_not_none(res1,
                                              no=f'{n1.subject()}或{n2.subject()}非数值类型,无法比较'):
                    if qt == 'areas_m_compare':
                        answer.add_sub_answers(f'前者是后者的{res1}倍')
                    else:
                        answer.add_sub_answers(f'前者比后者{sign(res1)}{abs(res1)}{ux}')
                if qt == 'areas_m_compare':
                    res2 = builder.binary_calculation(y.value, x.value, truediv)
                    if builder.add_if_is_not_none(res2,
                                                  no=f'{n1.subject()}或{n2.subject()}非数值类型,无法比较'):
                        answer.add_sub_answers(f'后者是前者的{res2}倍')
                answer.end_sub_answers()

    def make_indexes_or_areas_2m_or_2n_compare_ans(self, qt: str, answer: Answer, builder: AnswerBuilder,
                                                   chain: TranslationChain, result: Result):
        # set operator
        if qt in ('areas_2m_compare', 'indexes_2m_compare'):
            operator = truediv
        else:
            operator = sub
        # set gen and flatten
        if qt in ('areas_2m_compare', 'areas_2n_compare'):
            gen = [result['area'], result['index']]
            unpack = True
        else:
            gen = [result['index']]
            unpack = False
        # code begin
        data = self._search_direct(chain, unpack=unpack)
        builder.feed_data(data)
        for item, name in builder.product_data_with_name(*gen):
            x, y = item
            if builder.binary_decision(
                    x, y,
                    not_x=f'无关于{result["year"][0]}年的{name.subject()}的记录',
                    not_y=f'无关于{result["year"][1]}年的{name.subject()}的记录'
            ):
                answer.begin_sub_answers()
                res = builder.binary_calculation(x.value, y.value, operator)
                if builder.add_if_is_not_none(res, no=f'{name.subject()}的记录为无效的值类型,无法比较'):
                    answer.add_sub_answers(f'{result["year"][0]}年的{name.subject()}为{x.val()}')
                    answer.add_sub_answers(f'{result["year"][1]}年的{name.subject()}为{y.val()}')
                    if qt in ('areas_2m_compare', 'indexes_2m_compare'):
                        ux, uy = x.unit, y.unit
                        # 单位为%的数值不支持此类型比较
                        if ux == uy == '%':
                            answer.add_sub_answers(f'它们单位为‘%’,不支持此类型的比较')
                        else:
                            answer.add_sub_answers(f'前者是后者的{res}倍')
                    else:
                        answer.add_sub_answers(f'前者比后者{sign(res, ("减少", "增加"))}{abs(res)}{x.unit}')
                answer.end_sub_answers()

    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_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_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_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_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_indexes_or_areas_max_ans(self, qt: str, answer: Answer, builder: AnswerBuilder,
                                      chain: TranslationChain, result: Result):
        # 可以直接复用
        if qt == 'areas_max':
            self.make_indexes_or_areas_trend_ans('areas_trend', answer, builder, chain, result, mark_point=True)
        else:
            self.make_indexes_or_areas_trend_ans('indexes_trend', answer, builder, chain, result, mark_point=True)

    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)}年开始统计')
Ejemplo n.º 10
0
    def update(self, elapsed):
        Painter.update(self, elapsed)
#        self._surface = terrain#.subsurface(self._view)
        # ugly hack to pre-populate the grid
        """