|
import matplotlib.pyplot as plt |
|
import geopandas as gpd |
|
from shapely.geometry import box |
|
from matplotlib.patches import Polygon, Rectangle |
|
import matplotlib.patheffects as PathEffects |
|
|
|
# Set the figure DPI to 300 |
|
plt.rcParams['figure.dpi'] = 300 |
|
|
|
# Define the country name |
|
country_name = "Indonesia" |
|
|
|
# Load the world shapefile dataset |
|
world = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres')) |
|
|
|
# Get the bounding box for the country |
|
country_geom = world[world.name == country_name].geometry.unary_union |
|
bbox = country_geom.bounds |
|
|
|
# Add a buffer of 5 degrees |
|
buffer = 5 |
|
bbox = (bbox[0] - buffer, bbox[1] - buffer, bbox[2] + buffer, bbox[3] + buffer) |
|
|
|
# Clip the world data to the bounding box |
|
bbox_shape = box(*bbox) |
|
world_clip = world[world.intersects(bbox_shape)] |
|
|
|
# Calculate the aspect ratio of the bounding box |
|
bbox_width = bbox[2] - bbox[0] |
|
bbox_height = bbox[3] - bbox[1] |
|
aspect_ratio = bbox_width / bbox_height |
|
|
|
# Set minimum width for the figure to avoid extremely thin plots |
|
min_width = 5 |
|
fig_width = max(min_width, aspect_ratio * 5) |
|
fig_height = fig_width / aspect_ratio + 0.5 # Add extra space for legend |
|
|
|
# Set XKCD style |
|
plt.xkcd() |
|
|
|
# Create the plot with tight layout to ensure bbox fit |
|
fig, ax = plt.subplots(1, 1, figsize=(10, 5), tight_layout=True) |
|
|
|
# Set the plot limits to the bounding box |
|
ax.set_xlim(bbox[0], bbox[2]) |
|
ax.set_ylim(bbox[1], bbox[3]) |
|
|
|
# Plot the sea with light blue color within the bbox |
|
ax.add_patch(Rectangle((bbox[0], bbox[1]), |
|
bbox[2] - bbox[0], bbox[3] - bbox[1], |
|
color='#ADD8E6', zorder=0)) |
|
|
|
# Plot all countries |
|
world_clip.boundary.plot(ax=ax, edgecolor='black', zorder=2) |
|
world_clip.plot(ax=ax, color='white', edgecolor='black', zorder=3) |
|
|
|
# Highlight the specified country in grey |
|
highlight_country = world_clip[world_clip.name == country_name] |
|
highlight_country.plot(ax=ax, color='grey', edgecolor='black', zorder=4) |
|
|
|
# Plot the rectangle border for bbox |
|
bbox_patch = Polygon([(bbox[0], bbox[1]), (bbox[0], bbox[3]), |
|
(bbox[2], bbox[3]), (bbox[2], bbox[1]), |
|
(bbox[0], bbox[1])], closed=True, |
|
edgecolor='black', facecolor='none', linewidth=0.5, zorder=5) |
|
ax.add_patch(bbox_patch) |
|
|
|
# Add title |
|
plt.title(f'Map of {country_name} and Surrounding Areas', fontsize=18) |
|
|
|
# Remove axes |
|
ax.set_axis_off() |
|
|
|
# Add custom legend |
|
legend_patches = [ |
|
Polygon([(0,0)], closed=True, edgecolor='black', facecolor='grey', label=country_name), |
|
Polygon([(0,0)], closed=True, edgecolor='black', facecolor='white', label='Other Countries'), |
|
Rectangle((0,0),1,1, color='#ADD8E6', label='Sea') |
|
] |
|
legend = plt.legend(handles=legend_patches, loc='lower left') |
|
|
|
# Adjust the position of the scale bar and north arrow |
|
scale_bar_x_offset = 0.15 * (bbox[2] - bbox[0]) |
|
scale_bar_y_offset = 0.05 * (bbox[3] - bbox[1]) |
|
|
|
# Add scale bar next to the legend box |
|
scalebar_length = 500 # in kilometers |
|
scale_x = bbox[0] + 0.3 * (bbox[2] - bbox[0]) |
|
scale_y = bbox[1] + 0.08 * (bbox[3] - bbox[1]) |
|
scale_length_deg = scalebar_length / 111 # approximate conversion from km to degrees |
|
|
|
# Plot the scale bar |
|
ax.plot([scale_x, scale_x + scale_length_deg], [scale_y, scale_y], color='k', linewidth=3) |
|
ax.text(scale_x + scale_length_deg / 2, scale_y - 0.5, f'{scalebar_length} km', ha='center', va='top', fontsize=12, color='k', |
|
path_effects=[PathEffects.withStroke(linewidth=3, foreground="white")]) |
|
|
|
# Add north arrow |
|
x, y, arrow_length = 0.34, 0.22, 0.1 |
|
ax.annotate('N', xy=(x, y), xytext=(x, y - arrow_length), |
|
arrowprops=dict(facecolor='black', width=5, headwidth=15), |
|
ha='center', va='center', fontsize=15, |
|
xycoords=ax.transAxes) |
|
|
|
# Add data source label |
|
plt.text(bbox[2], bbox[1], "Data: Natural Earth", fontsize=8, ha='right', va='bottom', zorder=6) |
|
|
|
# Add world map inset |
|
inset_width = 0.3 |
|
inset_height = inset_width * (fig_height / fig_width) |
|
|
|
# Calculate the top right corner of the main map in figure coordinates |
|
bbox_main = ax.get_position() |
|
inset_left = bbox_main.x1 - inset_width |
|
inset_bottom = bbox_main.y1 - inset_height |
|
|
|
# Adjust inset position to align with top right corner of the main map area |
|
inset_ax = fig.add_axes([inset_left + 0.05, inset_bottom - 0.06, inset_width, inset_height]) |
|
world.plot(ax=inset_ax, color='lightgrey') |
|
highlight_country_inset = world[world.name == country_name] |
|
highlight_country_inset.plot(ax=inset_ax, color='red', edgecolor='red') |
|
inset_ax.set_xticks([]) |
|
inset_ax.set_yticks([]) |
|
inset_ax.set_xlim(-180, 180) |
|
inset_ax.set_ylim(-90, 90) |
|
|
|
# Add country labels |
|
ax.text(bbox[0] + 0.4 * bbox_width, bbox[3] - 0.5 * bbox_height, "I n d o n e s i a", fontsize=15, ha='left', zorder=6, path_effects=[PathEffects.withStroke(linewidth=3, foreground="white")]) |
|
ax.text(bbox[0] + 0.1 * bbox_width, bbox[3] - 0.1 * bbox_height, "Thailand", fontsize=11, ha='left', zorder=6, path_effects=[PathEffects.withStroke(linewidth=3, foreground="white")]) |
|
ax.text(bbox[0] + 0.25 * bbox_width, bbox[3] - 0.06 * bbox_height, "Viet Nam", fontsize=11, ha='left', zorder=6, path_effects=[PathEffects.withStroke(linewidth=3, foreground="white")]) |
|
ax.text(bbox[0] + 0.18 * bbox_width, bbox[3] - 0.27 * bbox_height, "Malaysia", fontsize=11, ha='left', zorder=6, path_effects=[PathEffects.withStroke(linewidth=3, foreground="white")]) |
|
ax.text(bbox[0] + 0.37 * bbox_width, bbox[3] - 0.3 * bbox_height, "Malaysia", fontsize=11, ha='left', zorder=6, path_effects=[PathEffects.withStroke(linewidth=3, foreground="white")]) |
|
ax.text(bbox[0] + 0.24 * bbox_width, bbox[3] - 0.37 * bbox_height, "Singapore", fontsize=11, ha='left', zorder=6, path_effects=[PathEffects.withStroke(linewidth=3, foreground="white")]) |
|
ax.text(bbox[0] + 0.45 * bbox_width, bbox[3] - 0.2 * bbox_height, "Brunei\nDarussalam", fontsize=11, ha='right', zorder=6, path_effects=[PathEffects.withStroke(linewidth=3, foreground="white")]) |
|
ax.text(bbox[0] + 0.6 * bbox_width, bbox[3] - 0.1 * bbox_height, "Philippines", fontsize=11, ha='center', zorder=6, path_effects=[PathEffects.withStroke(linewidth=3, foreground="white")]) |
|
ax.text(bbox[0] + 0.95 * bbox_width, bbox[3] - 0.68 * bbox_height, "Papua\nNew\nGuinea", fontsize=11, ha='center', zorder=6, path_effects=[PathEffects.withStroke(linewidth=3, foreground="white")]) |
|
ax.text(bbox[0] + 0.68 * bbox_width, bbox[3] - 0.78 * bbox_height, "Timor-Leste", fontsize=11, ha='center', zorder=6, path_effects=[PathEffects.withStroke(linewidth=3, foreground="white")]) |
|
ax.text(bbox[0] + 0.76 * bbox_width, bbox[3] - 0.93 * bbox_height, "Australia", fontsize=11, ha='center', zorder=6, path_effects=[PathEffects.withStroke(linewidth=3, foreground="white")]) |
|
|
|
# Add ocean labels |
|
ax.text(bbox[0] + 0.12 * bbox_width, bbox[3] - 0.6 * bbox_height, "Indian Ocean", fontsize=13, ha='center', color='tab:blue', zorder=6, path_effects=[PathEffects.withStroke(linewidth=3, foreground="white")]) |
|
ax.text(bbox[0] + 0.85 * bbox_width, bbox[3] - 0.3 * bbox_height, "Pacific Ocean", fontsize=13, ha='center', color='tab:blue', zorder=6, path_effects=[PathEffects.withStroke(linewidth=3, foreground="white")]) |
|
|
|
# Add red dot with white outline, and the label |
|
ax.text(bbox[0] + 0.33 * bbox_width, bbox[3] - 0.61 * bbox_height, "Jakarta", fontsize=9, ha='center', zorder=6, path_effects=[PathEffects.withStroke(linewidth=3, foreground="white")]) |
|
dot_x = bbox[0] + 0.295 * bbox_width |
|
dot_y = bbox[3] - 0.63 * bbox_height |
|
ax.plot(dot_x, dot_y, 'o', markersize=8, markeredgewidth=0.5, color='red', markeredgecolor='white', zorder=7) |
|
|
|
# Show the plot |
|
plt.show() |