Ke Ma
Ke Ma

Reputation: 43

draw a color grid based on points density using python matplotlib

The question is to read 10,000 coordinate points from a file and create a colored grid based on the density of each block on the grid. The range of x-axis is [-73.59, -73.55] and the y-axis is [45.49,45.530]. My code will plot a grid with many different colors, now I need a feature to only color the grid that has a specific density n, for example, The n = 100, only the grid with 100 points or higher will be colored to yellow, and other grids will be black.

I just added a link to my shapefile https://drive.google.com/open?id=1H-8FhfonnPrYW9y7RQZDtiNLxVEiC6R8

import numpy as np
import matplotlib.pyplot as plt
import shapefile

grid_size = 0.002
x1 = np.arange(-73.59,-73.55,grid_size)
y1 = np.arange(45.49,45.530,grid_size)
shape = shapefile.Reader("Shape/crime_dt.shp",encoding='ISO-8859-1')
shapeRecords = shape.shapeRecords()

x_coordinates=[]
y_coordinates=[]

# read all points in .shp file, and store them in 2 lists.
for k in range(len(shapeRecords)):
    x = float(shapeRecords[k].shape.__geo_interface__["coordinates"][0])
    y = float(shapeRecords[k].shape.__geo_interface__["coordinates"][1])
    x_coordinates.append(x)
    y_coordinates.append(y)

plt.hist2d(x_coordinates,y_coordinates,bins=[x1,y1])
plt.show()

Upvotes: 4

Views: 1654

Answers (1)

JohanC
JohanC

Reputation: 80319

You can create a colormap with just two colors, and set vmin and vmax to be symmetrical around your desired pivot value.

Optionally you put the value of each bin inside the cells, while the pivot value decides the text color.

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap

grid_size = 0.002
x1 = np.arange(-73.59, -73.55, grid_size)
y1 = np.arange(45.49, 45.530, grid_size)

# read coordinates from file and put them into two lists, similar to this
x_coordinates = np.random.uniform(x1.min(), x1.max(), size=40000)
y_coordinates = np.random.uniform(y1.min(), y1.max(), size=40000)
pivot_value = 100
# create a colormap with two colors, vmin and vmax are chosen so that their center is the pivot value
cmap = ListedColormap(['indigo', 'gold'])
# create a 2d histogram with xs and ys as bin boundaries
binvalues, _, _, _ = plt.hist2d(x_coordinates, y_coordinates, bins=[x1, y1], cmap=cmap, vmin=0, vmax=2*pivot_value)
binvalues = binvalues.astype(np.int)
for i in range(len(x1) - 1):
    for j in range(len(y1) - 1):
        plt.text((x1[i] + x1[i + 1]) / 2, (y1[j] + y1[j + 1]) / 2, binvalues[i, j],
                 color='white' if binvalues[i, j] < pivot_value else 'black',
                 ha='center', va='center', size=8)
plt.show()

example plot

PS: If the bin values are very important, you can add them all as ticks. Then, their positions can also be used to draw gridlines as a division between the cells.

plt.yticks(y1)
plt.xticks(x1, rotation=90)
plt.grid(True, ls='-', lw=1, color='black')

To obtain contours based on these data, you could plt.contourf with the generated matrix. (You might want to use np.histogram2d to directly create the matrix.)

plt.contourf((x1[1:]+x1[:-1])/2, (y1[1:]+y1[:-1])/2, binvalues.T, levels=[0,100,1000], cmap=cmap)

contour plot

Upvotes: 1

Related Questions