Auto-update: Fri Nov 15 13:14:54 PST 2024
This commit is contained in:
parent
4c51798a78
commit
3cfebd7fff
1 changed files with 19 additions and 50 deletions
|
@ -8,9 +8,8 @@ from fastapi.responses import HTMLResponse, JSONResponse
|
||||||
import random
|
import random
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import traceback
|
import traceback
|
||||||
import matplotlib.pyplot as plt
|
from staticmap import StaticMap, CircleMarker
|
||||||
import contextily as ctx
|
from io import BytesIO
|
||||||
import numpy as np
|
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from typing import Union, List
|
from typing import Union, List
|
||||||
import folium
|
import folium
|
||||||
|
@ -125,11 +124,12 @@ async def get_last_location() -> Optional[Location]:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async def generate_and_save_heatmap(
|
async def generate_and_save_heatmap(
|
||||||
start_date: Union[str, int, datetime],
|
start_date: Union[str, int, datetime],
|
||||||
end_date: Optional[Union[str, int, datetime]] = None,
|
end_date: Optional[Union[str, int, datetime]] = None,
|
||||||
output_path: Optional[Path] = None
|
output_path: Optional[Path] = None
|
||||||
) -> Path:
|
) -> Path:
|
||||||
"""
|
"""
|
||||||
Generate a heatmap for the given date range and save it as a PNG file.
|
Generate a heatmap for the given date range and save it as a PNG file.
|
||||||
|
|
||||||
|
@ -139,7 +139,6 @@ Generate a heatmap for the given date range and save it as a PNG file.
|
||||||
:return: The path where the PNG file was saved
|
:return: The path where the PNG file was saved
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
|
|
||||||
start_date = await dt(start_date)
|
start_date = await dt(start_date)
|
||||||
if end_date:
|
if end_date:
|
||||||
end_date = await dt(end_date)
|
end_date = await dt(end_date)
|
||||||
|
@ -150,53 +149,22 @@ Generate a heatmap for the given date range and save it as a PNG file.
|
||||||
if not locations:
|
if not locations:
|
||||||
raise ValueError("No locations found for the given date range")
|
raise ValueError("No locations found for the given date range")
|
||||||
|
|
||||||
lats = np.array([loc.latitude for loc in locations])
|
# Create map
|
||||||
lons = np.array([loc.longitude for loc in locations])
|
m = StaticMap(640, 360, url_template='https://cartodb-basemaps-{s}.global.ssl.fastly.net/dark_all/{z}/{x}/{y}.png')
|
||||||
|
|
||||||
# Calculate bounds with 5% buffer
|
# Add markers with heat effect
|
||||||
lat_range = max(lats) - min(lats)
|
for loc in locations:
|
||||||
lon_range = max(lons) - min(lons)
|
marker = CircleMarker((loc.longitude, loc.latitude), 'red', 12)
|
||||||
buffer = max(lat_range, lon_range) * 0.05
|
m.add_marker(marker)
|
||||||
|
|
||||||
# Enforce minimum zoom
|
# Render the image
|
||||||
MIN_RANGE = 0.05
|
image = m.render()
|
||||||
lat_range = max(lat_range, MIN_RANGE)
|
|
||||||
lon_range = max(lon_range, MIN_RANGE)
|
|
||||||
|
|
||||||
# Create figure with fixed size
|
|
||||||
fig, ax = plt.subplots(figsize=(6.4, 3.6), dpi=100)
|
|
||||||
|
|
||||||
# Set map extent
|
|
||||||
ax.set_xlim(min(lons) - buffer, max(lons) + buffer)
|
|
||||||
ax.set_ylim(min(lats) - buffer, max(lats) + buffer)
|
|
||||||
|
|
||||||
# Create heatmap overlay
|
|
||||||
heatmap = ax.hexbin(
|
|
||||||
lons, lats,
|
|
||||||
gridsize=25,
|
|
||||||
cmap='hot',
|
|
||||||
alpha=0.6,
|
|
||||||
zorder=2
|
|
||||||
)
|
|
||||||
|
|
||||||
# Add dark basemap
|
|
||||||
ctx.add_basemap(
|
|
||||||
ax,
|
|
||||||
source=ctx.providers.CartoDB.DarkMatter,
|
|
||||||
zoom='auto'
|
|
||||||
)
|
|
||||||
|
|
||||||
# Remove axes and margins
|
|
||||||
ax.set_axis_off()
|
|
||||||
plt.subplots_adjust(left=0, right=1, top=1, bottom=0)
|
|
||||||
|
|
||||||
if output_path is None:
|
if output_path is None:
|
||||||
output_path, relative_path = assemble_journal_path(end_date, filename="map", extension=".png", no_timestamp=True)
|
output_path, relative_path = assemble_journal_path(end_date, filename="map", extension=".png", no_timestamp=True)
|
||||||
|
|
||||||
plt.savefig(output_path, bbox_inches='tight', pad_inches=0, dpi=100)
|
# Save the image
|
||||||
plt.close()
|
image.save(output_path)
|
||||||
|
|
||||||
l.info(f"Heatmap saved as PNG: {output_path}")
|
|
||||||
return output_path
|
return output_path
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -205,6 +173,7 @@ Generate a heatmap for the given date range and save it as a PNG file.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async def generate_map(start_date: datetime, end_date: datetime, max_points: int):
|
async def generate_map(start_date: datetime, end_date: datetime, max_points: int):
|
||||||
locations = await fetch_locations(start_date, end_date)
|
locations = await fetch_locations(start_date, end_date)
|
||||||
if not locations:
|
if not locations:
|
||||||
|
|
Loading…
Reference in a new issue