|
1 | 1 | """ pyplots.ai |
2 | 2 | hexbin-basic: Basic Hexbin Plot |
3 | | -Library: seaborn 0.13.2 | Python 3.13.11 |
4 | | -Quality: 90/100 | Created: 2025-12-23 |
| 3 | +Library: seaborn 0.13.2 | Python 3.14.3 |
| 4 | +Quality: /100 | Updated: 2026-02-21 |
5 | 5 | """ |
6 | 6 |
|
7 | 7 | import numpy as np |
8 | | -import pandas as pd |
9 | 8 | import seaborn as sns |
| 9 | +from matplotlib.colors import LogNorm |
10 | 10 |
|
11 | 11 |
|
12 | 12 | # Data - simulate GPS coordinates for urban traffic hotspot analysis |
13 | 13 | np.random.seed(42) |
14 | 14 |
|
15 | | -# Create realistic GPS coordinate clusters representing traffic hotspots |
16 | | -# Using a larger dataset (50,000 points) to demonstrate hexbin advantage over scatter |
| 15 | +# 50,000 points to demonstrate hexbin advantage over scatter |
17 | 16 | n_points = 50000 |
18 | 17 |
|
19 | | -# Downtown business district - high density |
| 18 | +# Downtown business district - high density cluster |
20 | 19 | downtown = np.random.multivariate_normal([-73.985, 40.748], [[0.0001, 0.00005], [0.00005, 0.0001]], n_points // 2) |
21 | 20 |
|
22 | | -# Airport area - medium density |
| 21 | +# Airport area - medium density cluster |
23 | 22 | airport = np.random.multivariate_normal([-73.875, 40.775], [[0.00008, -0.00003], [-0.00003, 0.00008]], n_points // 3) |
24 | 23 |
|
25 | 24 | # Shopping district - smaller cluster |
26 | 25 | shopping = np.random.multivariate_normal([-73.965, 40.785], [[0.00004, 0], [0, 0.00006]], n_points // 6) |
27 | 26 |
|
28 | | -# Combine clusters into DataFrame for seaborn |
29 | 27 | longitude = np.concatenate([downtown[:, 0], airport[:, 0], shopping[:, 0]]) |
30 | 28 | latitude = np.concatenate([downtown[:, 1], airport[:, 1], shopping[:, 1]]) |
31 | | -df = pd.DataFrame({"Longitude": longitude, "Latitude": latitude}) |
32 | 29 |
|
33 | | -# Set seaborn style for clean aesthetics |
| 30 | +# Plot - seaborn JointGrid with hexbin and marginal distributions |
34 | 31 | sns.set_theme(style="whitegrid", context="talk", font_scale=1.2) |
35 | 32 |
|
36 | | -# Create JointGrid for hexbin with marginal distributions |
37 | | -g = sns.JointGrid(data=df, x="Longitude", y="Latitude", height=12, ratio=5, space=0.2) |
| 33 | +g = sns.JointGrid(x=longitude, y=latitude, height=12, ratio=5, space=0.15) |
38 | 34 |
|
39 | | -# Main hexbin plot using plot_joint |
40 | | -hb = g.ax_joint.hexbin(df["Longitude"], df["Latitude"], gridsize=35, cmap="viridis", mincnt=1, edgecolors="none") |
| 35 | +# Main hexbin with log-normalized color scale for wide density variation |
| 36 | +hb = g.ax_joint.hexbin(longitude, latitude, gridsize=35, cmap="viridis", mincnt=1, norm=LogNorm(), edgecolors="none") |
41 | 37 |
|
42 | | -# Marginal distributions using seaborn's histplot |
43 | | -g.plot_marginals(sns.histplot, kde=True, color="#306998", alpha=0.6, linewidth=0) |
| 38 | +# Marginal distributions - distinctive seaborn feature |
| 39 | +g.plot_marginals(sns.kdeplot, color="#306998", fill=True, alpha=0.4, linewidth=2) |
44 | 40 |
|
45 | | -# Add colorbar to show density scale |
| 41 | +# Colorbar for density scale |
46 | 42 | cbar = g.figure.colorbar(hb, ax=g.ax_joint, pad=0.02, shrink=0.8) |
47 | | -cbar.set_label("Point Count", fontsize=20) |
| 43 | +cbar.set_label("Point Count (log scale)", fontsize=20) |
48 | 44 | cbar.ax.tick_params(labelsize=16) |
49 | 45 |
|
50 | | -# Labels and title with proper sizing |
| 46 | +# Style |
51 | 47 | g.ax_joint.set_xlabel("Longitude (°W)", fontsize=20) |
52 | 48 | g.ax_joint.set_ylabel("Latitude (°N)", fontsize=20) |
53 | 49 | g.ax_joint.tick_params(axis="both", labelsize=16) |
| 50 | +g.ax_joint.grid(True, alpha=0.2, linestyle="--", linewidth=0.8) |
| 51 | +g.ax_joint.spines["top"].set_visible(False) |
| 52 | +g.ax_joint.spines["right"].set_visible(False) |
54 | 53 |
|
55 | | -# Subtle grid on main plot |
56 | | -g.ax_joint.grid(True, alpha=0.3, linestyle="--", linewidth=0.8) |
57 | | - |
58 | | -# Title at top of figure |
59 | 54 | g.figure.suptitle("hexbin-basic · seaborn · pyplots.ai", fontsize=24, y=0.98) |
60 | 55 |
|
61 | | -# Adjust layout to prevent clipping |
| 56 | +# Save |
62 | 57 | g.figure.tight_layout(rect=[0, 0, 1, 0.96]) |
63 | 58 | g.savefig("plot.png", dpi=300, bbox_inches="tight") |
0 commit comments