【问题标题】:Is there a way to visualise large 2d arrays in python with a scrollable map?有没有办法用可滚动的地图在 python 中可视化大型二维数组?
【发布时间】:2020-08-18 02:17:12
【问题描述】:

我正在用 python 进行基因模拟,我有一张地图,“世界”,它是一个二维列表,根据它们的位置保存所有对象(动物/树木/草)。我想知道是否有一种简单的方法可以使用诸如 matplotlib 之类的库来创建一个地图,您可以从这些数据中滚动、放大等等。理想情况下,我希望有一个界面,我可以创建一个字典,其中包含将“世界”列表中的字符映射到的内容(例如,将草的“g”映射到地图上的绿色方块),以及这些的二维数组字符,并用简单的语句生成地图。

如果这是不可能的,我愿意接受其他可视化的想法。

编辑:这是我的数据在将其设为 pandas 数据框(用于 5x5 世界地图)后的格式示例。 g是草,w是水,h是草食动物,t是树

【问题讨论】:

    标签: python matplotlib


    【解决方案1】:

    您可以使用 pandas 和 matplotlib 完成此操作。

    如果您有每个数据点的经度和纬度值,使用 matplotlib 散点图绘制它们将为您提供数据地图。然后,您可以指定第三列以使用散点的颜色或大小来显示其他一些变量。在这个例子中,我使用了人口。

    给定一个看起来像 this 的 csv 文件

    import pandas as pd
    import matplotlib.pyplot as plt
    
    data = pd.read_csv("./housing.csv")
    
    plt.scatter(data["Longitude"], data["Latitude"], c=data["Population"], cmap="hsv", s=data["Population"]/500)
    plt.colorbar()
    

    上面的代码给你this

    此示例仅使用来自加利福尼亚的数据,但如果您有来自整个世界或要显示的地区的经纬度数据,则可以相应地绘制图表。

    如果您要使用 2d 列表而不是 csv 数据。您可以很容易地将该列表转换为 pandas 数据框。 This question covers how to do that

    【讨论】:

    • 您好@MattCarlson,我已经尝试过您链接的问题中推荐的 pd.Dataframe 方法,但是当我在 100x100 地图上尝试时,它给了我一个 100x100 的表格,其中坐标作为标题,而不是您用于演示的 10000x3 表。您知道在两者之间转移的任何巧妙方法吗?
    • @Arkleseisure 你能发布一个你的数据样例吗?
    【解决方案2】:

    为了未来的人,我用pygame编写了自己的地图:

    import pygame
    import random
    import os
    from math import floor, ceil
    
    
    screen_width = 1400
    screen_height = 700
    square_size = 20
    pygame.init()
    
    
    class Map:
        def __init__(self, world, names):
            os.environ['SDL_VIDEO_CENTERED'] = '1'
            self.screen = pygame.display.set_mode([screen_width, screen_height])
            pygame.display.set_caption("Map")
    
            # creates a dictionary of random colors to represent each character
            colors = {}
            for item in names.keys():
                if item not in colors.keys():
                    colors[item] = [random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)]
    
            # creates a new map with the square sprites in which will form the map
            self.map = []
            self.square_group = pygame.sprite.Group()
            for i in range(len(world)):
                self.map.append([])
                for j in range(len(world[i])):
                    square = Square(colors[str(world[i][j])], i, j)
                    self.map[i].append(square)
                    self.square_group.add(square)
            self.x = 0
            self.y = 0
            self.draw(self.screen)
            pygame.display.flip()
    
        def draw(self, screen):
            self.square_group.draw(screen)
    
        def observe(self):
            has_quit = False
            mouse_down = False
            original_x = 0
            original_y = 0
            while not has_quit:
                for event in pygame.event.get():
                    if event.type == pygame.MOUSEBUTTONDOWN and not mouse_down:
                        original_x, original_y = pygame.mouse.get_pos()
                        mouse_down = True
    
                        # quits if the user clicks outside the map (probably a bad way of doing it)
                        if not 0 <= original_x <= screen_width or not 0 <= original_y <= screen_height:
                            has_quit = True
                            pygame.QUIT()
    
                # scrolls the map around while the user is holding the mouse down
                while mouse_down:
                    final_x, final_y = pygame.mouse.get_pos()
                    new_x = (final_x - original_x) / square_size + self.x
                    new_y = (final_y - original_y) / square_size + self.y
                    original_x = final_x
                    original_y = final_y
                    if new_x > 0:
                        new_x = 0
                    elif -new_x * square_size > len(self.map) * square_size - screen_width:
                        new_x = screen_width / square_size - len(self.map)
                    if new_y > 0:
                        new_y = 0
                    elif -new_y * square_size > len(self.map[0]) * square_size - screen_height:
                        new_y = screen_height / square_size - len(self.map[0])
                    for i in range(floor(-max(self.x, new_x)), ceil(-min(self.x, new_x) + screen_width/square_size)):
                        for j in range(floor(-max(self.y, new_y)), ceil(-min(self.y, new_y) + screen_height/square_size)):
                            self.map[i][j].sync(square_size, new_x*square_size, new_y*square_size)
                    self.square_group.draw(self.screen)
                    pygame.display.flip()
                    self.x = new_x
                    self.y = new_y
    
                    # checks whether the user has stopped holding their mouse down
                    for event in pygame.event.get():
                        if event.type == pygame.MOUSEBUTTONUP:
                            mouse_down = False
    
    
    # class for the squares on the map
    class Square(pygame.sprite.Sprite):
        def __init__(self, colour, x, y, size=square_size):
            super().__init__()
            self.colour = colour
            self.x = x
            self.y = y
            self.image = pygame.Surface([size, size])
            self.rect = self.image.get_rect()
            pygame.draw.rect(self.image, self.colour, [0, 0, size, size])
            self.sync(size, 0, 0)
    
        # makes sure the square is in the correct position and is the correct size
        def sync(self, size, map_x, map_y):
            self.rect = self.image.get_rect()
            self.rect.x = self.x * size + map_x
            self.rect.y = self.y * size + map_y
            pygame.transform.scale(self.image, (size, size))
    

    这不是最好的或最好的,但我希望它有所帮助。随意使用它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-06-13
      • 1970-01-01
      • 1970-01-01
      • 2020-12-17
      • 2011-01-16
      • 1970-01-01
      • 2021-12-26
      相关资源
      最近更新 更多