'How do I force a color on top of a colormap in matplotlib?
I'm working on a 0 player game where a "creature" moves around a map eating food to survive, with every turn costing it energy and eating food adding energy. The food map is a randomly generated 2D numpy array, with each position having a random amount of food on it.
food = np.random.randint(0, high=8, size=[10,10])
As creatures eat food the value of food on that location decreases correspondingly.
The creature is an object with the variables "id", "energy", "xpos", and "ypos". The id is an integer that is the "name" of that creature. (I eventually want this game to have multiple creatures competing with each other.)
class Creature:
def __init__(self, xpos,ypos, energy):
self.id = 1
self.xpos = xpos
self.ypos = ypos
self.energy = energy
The program runs in a loop where every turn costs the creature 1 energy point. If its energy falls below a value it gets hungry and tries to find a position that contains food, which it begins to eat. As the creature eats food the food value for that position decreases.
I am trying to display this visually using matplotlib. I currently use this to create the heatmap of food and, separately, a grid showing the location of the creature:
def colormap(data):
fig, ax = plt.subplots()
ax.imshow(data)
ax.grid(which='major', axis='both', linestyle='-', color='k', linewidth=2)
ax.set_xticks(np.arange(-.5, 10, 1));
ax.set_yticks(np.arange(-.5, 10, 1));
plt.show()
I would like to overlay the position of the creature on top of the food map represented by a color that is distinct from the colors used by the food map.
I am stuck on where to go next. Perhaps matplotlib is not the right tool to use here.
Here is the minimal code I am using to generate two different grids; one showing the value of the food across the map and the second showing the location of the creature. I would like the creature to overlay on the food map in a color such as red regardless of the value of the food value in that position.
Thank you for any help, I realize I may be off base in my approach
#Import modules
import random
import matplotlib.pyplot as plt
import numpy as np
#Create a heatmap grid from an array
def colormap(data):
fig, ax = plt.subplots()
ax.imshow(data)
ax.grid(which='major', axis='both', linestyle='-', color='k', linewidth=2)
ax.set_xticks(np.arange(-.5, 10, 1));
ax.set_yticks(np.arange(-.5, 10, 1));
plt.show()
#Creatue a new creature object
class Creature:
def __init__(self,ID, xpos,ypos,energy):
self.id = 1
self.xpos = xpos
self.ypos = ypos
self.energy = energy
#Create the variables of that creature
xpos = random.randint(0,9)
ypos = random.randint(0,9)
energy = (10)
#Now that random attributes have been chosed and it has found a unique location, it spawns
newcreature = Creature(id,xpos,ypos,energy)
#Create an array to hold the ID of the creature occupying each space
occupant = np.full((10,10),0)
#creatue food map
food = np.random.randint(0, high=8, size=[10,10])
#Write the ID of the creature to the map of creature occupying that place in the map
occupant[newcreature.xpos,newcreature.ypos] = newcreature.id
#Display the food map
colormap(food)
#Display the creature map
colormap(occupant)
Solution 1:[1]
Matplotlib might be the tool for this job, if frame-per-second is not bothering you.
You are very close to your objective: you need to use a colormap for the food map, and a scatter plot to overlay the position of the creature (also with a colormap to indicate the energy level). Here is the modified code, I have commented it to give you a better understanding:
import random
import matplotlib.pyplot as plt
from matplotlib.colors import Normalize
import matplotlib.cm as cm
import numpy as np
#Create a heatmap grid from an array
def colormap(data, cmap_food, norm_food, pos, energy_cmap, norm_energy, current_energy):
fig, ax = plt.subplots()
img = ax.imshow(data, cmap=cmap_food, norm=norm_food)
s = ax.scatter(*pos, s=150, cmap=energy_cmap, norm=norm_energy, c=current_energy, label="energy")
ax.grid(which='major', axis='both', linestyle='-', color='k', linewidth=2)
cb_energy = fig.colorbar(s)
cb_energy.set_label("Energy", rotation=90)
cb_food = fig.colorbar(img)
cb_food.set_label("Food", rotation=90)
ax.set_xticks(np.arange(-.5, 10, 1));
ax.set_yticks(np.arange(-.5, 10, 1));
plt.show()
#Creatue a new creature object
class Creature:
def __init__(self,ID, xpos,ypos,energy):
self.id = 1
self.xpos = xpos
self.ypos = ypos
self.energy = energy
#Create the variables of that creature
xpos = random.randint(0,9)
ypos = random.randint(0,9)
energy = 10
#Now that random attributes have been chosed and it has found a unique location, it spawns
newcreature = Creature(id,xpos,ypos,energy)
#creatue food map
max_food = 8
food = np.random.randint(0, high=max_food, size=[10,10])
# colormap used to visualize food
# You can explore more colormaps at:
# https://matplotlib.org/stable/tutorials/colors/colormaps.html
cmap_food = cm.YlGn
# Normalize the colors
# If we think that the food colormap is too intesense, we can either
# change the food colormap, or increase vmax to a number greater than
# max_food.
# Maybe, we would like the minimum food location not to be white:
# then we can change vmin to a negative number.
norm_food = Normalize(vmin=0, vmax=max_food)
# Choose an appropriate colormap, one that should be visible at
# every energy/food level on top of the food colormap.
energy_cmap = cm.cool_r
# normalize the energy of the creature between the minimum and maximum
norm_energy = Normalize(vmin=0, vmax=energy)
# position of the creature
pos = (newcreature.xpos, newcreature.ypos)
#Display the food map
colormap(food, cmap_food, norm_food, pos, energy_cmap, norm_energy, newcreature.energy)
Once you understand this code, you can start playing with the selection of better colormaps and setting better values in the Normalize objects.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Davide_sd |

