I am striving to reproduce the visualization style in the provided image. It looks like a scatterplot is used to show the data points. When I attempt to create a similar visualization, all the locations become visible. My objective is to create the other scatterplot, featuring larger circles that exhibit a darker shade of red in areas with more activity and a lighter shade where activity is less pronounced.
I believe I need to implement a threshold to selectively display data points and avoid showing all of them. Can anyone provide guidance on how I can achieve a visualization similar to the one depicted in the picture?
My plot:
The plot i want:
My code:
def plot_cumulative_heatmap(positions: List[Tuple[float, float]], map_name: str = "de_mirage", map_type: str = "original", dark: bool = False, titel: str = "Counter-Terrorist Attacking", isPistol: str = "Pistol Round") -> Literal[True]:
heatmap_fig, heatmap_axes = plot_map(map_name=map_name, map_type=map_type, dark=dark)
heatmap_data = []
for position in positions:
x, y = position
heatmap_data.append((x, y))
# Extract data for plotting
x, y = zip(*heatmap_data)
sns.scatterplot(x=x, y=y, color='red', s=5, ax=heatmap_axes, alpha=0.5)
heatmap_axes.set_title(f"{titel}\nTotal Positions: {len(positions)}\n{isPistol}", fontsize=14, weight="bold")
heatmap_axes.get_xaxis().set_visible(False)
heatmap_axes.get_yaxis().set_visible(False)
print("Heatmap saved.")
return True
The following approach draws large transparent circles for each input coordinate pair. If the real input contains multiple points with the same coordinates, their transparency will add up.
import matplotlib.pyplot as plt
import numpy as np
# create some dummy test data
np.random.seed(20240311)
x = np.random.randn(20, 25).cumsum(axis=1).ravel()
y = np.random.randn(20, 25).cumsum(axis=1).ravel()
filter = (np.abs(x) < 7) & (np.abs(y) < 7) & ((np.abs(x) > 5) | (np.abs(y) > 5))
x = x[filter]
y = y[filter]
fig, ax = plt.subplots()
fig.set_facecolor('black')
ax.set_aspect('equal', 'datalim')
ax.scatter(x, y, color='salmon', alpha=0.3, lw=0, s=500)
# draw rectangles representing the walls
ax.add_patch(plt.Rectangle((-7, -7), 14, 14, fc='none', ec='w', lw=2))
ax.add_patch(plt.Rectangle((-5, -5), 10, 10, fc='none', ec='w', lw=2))
ax.axis('off')
plt.show()
Another approach uses KMeans to find the centers of groups of points that are close together. Then, large dots can be drawn at those places, with transparency depending on the number of points in each cluster.
Change the number of clusters (here n_clusters=20
) to get more or less circles.
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
import numpy as np
# dummy test data from the other example
kmeans = KMeans(n_clusters=20, init='k-means++', random_state=0)
kmeans.fit(np.c_[x, y])
centroids = kmeans.cluster_centers_
labels = kmeans.labels_
counts = np.bincount(labels)
max_count = counts.max()
fig, ax = plt.subplots()
fig.set_facecolor('black')
ax.set_facecolor('none')
alphas = 0.2 + 0.8 * counts / max_count
ax.scatter(x=centroids[:, 0], y=centroids[:, 1], color='salmon', s=1000, lw=0, alpha=alphas)
ax.set_aspect('equal', 'datalim')
# draw rectangles representing the walls
ax.add_patch(plt.Rectangle((-7, -7), 14, 14, fc='none', ec='w', lw=2, zorder=0))
ax.add_patch(plt.Rectangle((-5, -5), 10, 10, fc='none', ec='w', lw=2, zorder=0))
ax. Axis('off')
plt.tight_layout()
plt.show()