diff --git a/network/static/network/calender.js b/network/static/network/calender.js index a440ca3..d4429d0 100644 --- a/network/static/network/calender.js +++ b/network/static/network/calender.js @@ -36,11 +36,12 @@ fetch(url) container: "map", initialViewState: { altitude: 1.5, - longitude: -27, - latitude: 0, - zoom: 1, + height: 700, + longitude: 80, + latitude: 35, + zoom: 2, pitch: 60, - bearing: 127.511, + // bearing: -1.7 }, controller: true, // onViewStateChange: ({ viewState }) => { @@ -50,9 +51,9 @@ fetch(url) new deck.HexagonLayer({ data: validEvents, getPosition: (d) => [d.longitude, d.latitude], - radius: 100000, - elevationScale: 400, - elevationRange: [0, 10000], + radius: 50000, + elevationScale: 4000, + elevationRange: [0, 100], extruded: true, pickable: true, onHover: ({ object, x, y }) => { @@ -66,7 +67,6 @@ fetch(url) tooltip.style.display = "block"; tooltip.style.left = `${x}px`; tooltip.style.top = `${y}px`; - // tooltip.innerHTML = `
`; tooltip.innerHTML = `${curDate}`; } else { tooltip.style.display = "none"; diff --git a/network/utils.py b/network/utils.py index a2aa805..1d19d41 100644 --- a/network/utils.py +++ b/network/utils.py @@ -1,4 +1,5 @@ import pandas as pd +from datetime import datetime, date def df_to_geojson_vect( @@ -35,3 +36,50 @@ def get_coords(row): return (row["target_lat"], row["target_lng"]) else: return row["source_lat"], row["source_lng"] + + +def iso_to_lat_long(iso_date, start_date="1700-01-01", end_date="1990-12-31"): + """ + Maps an ISO date string or datetime.date to latitude and longitude, ensuring + earlier dates are more south (latitude) and earlier days within a year are more west (longitude). + + Args: + iso_date (str | datetime.date): An ISO-formatted date string (e.g., "2023-01-01") + or a datetime.date object. + start_date (str): Start of the date range in ISO format (default: "1900-01-01"). + end_date (str): End of the date range in ISO format (default: "2100-12-31"). + + Returns: + tuple: A tuple containing latitude and longitude (both as floats). + """ + try: + # Ensure iso_date is a datetime.date object + if isinstance(iso_date, str): + date_obj = datetime.strptime(iso_date, "%Y-%m-%d").date() + elif isinstance(iso_date, date): + date_obj = iso_date + else: + raise ValueError("Invalid input type. Must be a string or datetime.date.") + + # Convert start_date and end_date to datetime.date objects + start_date_obj = datetime.strptime(start_date, "%Y-%m-%d").date() + end_date_obj = datetime.strptime(end_date, "%Y-%m-%d").date() + + # Ensure date_obj is within range + if not (start_date_obj <= date_obj <= end_date_obj): + raise ValueError("Date is out of the specified range.") + + # Latitude: Based on the position of the date within the range (0–90) + total_days = (end_date_obj - start_date_obj).days + date_position = (date_obj - start_date_obj).days / total_days + lat = 90 * date_position + + # Longitude: Inverted position of the day within the year (0–180) + day_of_year = date_obj.timetuple().tm_yday + days_in_year = (date(datetime(date_obj.year, 12, 31).year, 12, 31) - date(datetime(date_obj.year, 1, 1).year, 1, 1)).days + 1 + day_position = (day_of_year - 1) / days_in_year # Normalize day position in the year + lon = 180 * day_position + + return lat, lon + except Exception as e: + raise ValueError(f"Invalid input: {iso_date}") from e diff --git a/network/views.py b/network/views.py index 8fad5c1..b0b6939 100644 --- a/network/views.py +++ b/network/views.py @@ -14,7 +14,7 @@ from network.forms import EdgeFilterFormHelper from network.models import Edge from network.tables import EdgeTable -from network.utils import get_coords, df_to_geojson_vect +from network.utils import get_coords, df_to_geojson_vect, iso_to_lat_long class NetworkView(TemplateView): @@ -63,25 +63,22 @@ class EdgeListViews(GenericListView): def edges_as_calender(request): query_params = request.GET - queryset = Edge.objects.filter().exclude(start_date__isnull=True).exclude(start_date__lte="1677-12-31") + queryset = ( + Edge.objects.filter() + .exclude(start_date__isnull=True) + .exclude(start_date__lte="1500-12-31") + ) values_list = [x.name for x in Edge._meta.get_fields()] qs = EdgeListFilter(request.GET, queryset=queryset).qs items = list(qs.values_list(*values_list)) df = pd.DataFrame(list(items), columns=values_list) - - def map_date_to_lat_lng(date_str): - date = pd.to_datetime(date_str, errors="coerce") - if pd.isnull(date): - return None, None - year = date.year - day_of_year = date.dayofyear - # Map year to latitude (-90 to 90) - latitude = ((year + 90) % 180) - 90 - # Map day of year to longitude (-180 to 180) - longitude = (day_of_year % 360) - 180 - return latitude, longitude - - df["latitude"], df["longitude"] = zip(*df["start_date"].map(map_date_to_lat_lng)) + start_date = str(df["start_date"].min()) + end_date = str(df["start_date"].max()) + df["latitude"], df["longitude"] = zip( + *df["start_date"].map( + lambda date: iso_to_lat_long(date, start_date=start_date, end_date=end_date) + ) + ) df["label"] = df[["source_label", "edge_label", "target_label"]].agg( " ".join, axis=1 )