Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

286 visualize start end as arcs #287

Merged
merged 2 commits into from
Jan 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions apis_core/apis_entities/arc_views.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import pandas as pd
from django.views.generic import TemplateView
from django.http import JsonResponse
from apis_core.apis_entities.models import Person
from apis_core.apis_entities.list_view_person import PersonListFilter

from network.utils import iso_to_lat_long


class ArcsView(TemplateView):
template_name = "apis_entities/arcs.html"


def get_arcs_data(request):
values_list = ["id", "name", "first_name", "start_date", "end_date"]
query_params = request.GET
Expand All @@ -21,12 +26,12 @@ def get_arcs_data(request):
end_date = str(df["end_date"].max())
df["latitude_start"], df["longitude_start"] = zip(
*df["start_date"].map(
lambda date: iso_to_lat_long(date, start_date=start_date, end_date=end_date)
lambda date: iso_to_lat_long(date, start_date=start_date, end_date=end_date, max_width=3)
)
)
df["latitude_end"], df["longitude_end"] = zip(
*df["end_date"].map(
lambda date: iso_to_lat_long(date, start_date=start_date, end_date=end_date)
lambda date: iso_to_lat_long(date, start_date=start_date, end_date=end_date, max_width=3)
)
)
df = df.sort_values(by="start_date")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ <h2 class="text-center">
</a>
</h2>
{% endif %}{% endif %}
{% if entity == "person" %}
<!-- {% if entity == "person" %}
<div class="row">
<div class="btn-group" role="group" class="text-end">
<a type="button" class="btn btn-outline-primary" href="{% url 'apis_core:apis_entities:arcs_data' %}{% querystring %}">Timespan-Data</a>
<a type="button" class="btn btn-outline-primary" href="{% url 'apis_core:apis_entities:arcs_data' %}{% querystring %}">Timespan-Visualisation</a>
<a type="button" class="btn btn-outline-primary" href="{% url 'apis_core:apis_entities:arcs_data' %}{% querystring %}">Zeitspannen (Daten)</a>
<a type="button" class="btn btn-outline-primary" href="{% url 'apis_core:apis_entities:arcs' %}{% querystring %}">Zeitspannen (Visualisierung)</a>
</div>
</div>
{% endif %}
{% endif %} -->

<div class="row pt-4">
<div class="col-md-4" id="searchpane">
Expand Down
7 changes: 6 additions & 1 deletion apis_core/apis_entities/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from .list_view_person import PersonListView
from .list_view_place import PlaceListView
from .list_view_work import WorkListView
from .arc_views import get_arcs_data
from .arc_views import get_arcs_data, ArcsView

app_name = "apis_entities"

Expand All @@ -17,6 +17,11 @@
get_arcs_data,
name="arcs_data",
),
path(
"arcs",
ArcsView.as_view(),
name="arcs",
),
path(
"entity/<entity>/<int:pk>/edit",
views.GenericEntitiesEditView.as_view(),
Expand Down
117 changes: 45 additions & 72 deletions network/static/network/arcs.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,34 @@
const url = document.getElementById("url").textContent;

function showModal(object) {
const options = {focus: true, keyboard: true, backdrop: true, dismiss: true};
const eventLabels = object.points.map((p) => p.source.label);
const curDate = object.points[0].source.date;
const listItems = eventLabels.map((label) => `<li>${label}</li>`).join("");
const urlParams = new URLSearchParams(window.location.search);
urlParams.set("start_date", curDate);
const newUrl = `/network/edges/?${urlParams.toString()}`;
document.getElementById("staticBackdropLabel").innerHTML = `<a href="${newUrl}">${curDate}</a>`;
document.getElementById("modal-body").innerHTML = `<ul>${listItems}</ul>`;
const myModal = new bootstrap.Modal(document.getElementById('staticBackdrop'), options);
const options = {
focus: true,
keyboard: true,
backdrop: true,
dismiss: true,
};
// const eventLabels = object.points.map((p) => p.source.label);
// const curDate = object.points[0].source.date;
// const listItems = eventLabels.map((label) => `<li>${label}</li>`).join("");
// const urlParams = new URLSearchParams(window.location.search);
// urlParams.set("start_date", curDate);
const newUrl = `/entity/${object.id}`;
const label = object.label;
document.getElementById("staticBackdropLabel").innerHTML = `<a href="${newUrl}">${label}</a>`;
// document.getElementById("modal-body").innerHTML = `<ul>${listItems}</ul>`;
const myModal = new bootstrap.Modal(
document.getElementById("staticBackdrop"),
options
);
myModal.toggle();
}

console.log("fetching data");
document.getElementById("loading-spinner").style.display = "block";
console.log("fetching data hansi");
document.getElementById("loading-spinner").style.display = "block";
fetch(url)
.then((response) => {
if (!response.ok) {
throw new Error("Calender data response was not ok");
throw new Error("Timespan data response was not ok");
}
return response.json();
})
Expand All @@ -40,53 +49,36 @@ fetch(url)
}
});

// Ensure each event has a label property
const validEvents = data.events
.filter((event) => event.latitude && event.longitude)
.map((event) => ({
...event,
label: event.label || "Unknown Event", // Default to 'Unknown Event' if label is missing
}));
const items = data.items;

console.log(validEvents);
const deckgl = new deck.DeckGL({
console.log(items[1]);
new deck.DeckGL({
container: "map",
mapStyle:
"https://basemaps.cartocdn.com/gl/dark-matter-nolabels-gl-style/style.json",
initialViewState: {
altitude: 1.5,
height: 700,
longitude: 80,
latitude: 35,
zoom: 2,
pitch: 60,
// bearing: -1.7
longitude: 10.4356549,
latitude: 48.9833712,
zoom: 5,
minZoom: 1,
maxZoom: 15,
pitch: 45,
},
onViewStateChange: ({ viewState }) => {
console.log("Current view state:", viewState);
},
controller: true,
// onViewStateChange: ({ viewState }) => {
// console.log("Current view state:", viewState);
// },
layers: [
new deck.HexagonLayer({
data: validEvents,
getPosition: (d) => [d.longitude, d.latitude],
radius: 50000,
elevationScale: 4000,
elevationRange: [0, 50],
extruded: true,
new deck.ArcLayer({
id: "arc-layer",
data: items,
getSourcePosition: (d) => d.from,
getTargetPosition: (d) => d.to,
getSourceColor: [0, 0, 0],
getTargetColor: [255, 0, 0],
getWidth: 4,
pickable: true,
onClick: (object) => showModal(object.object),
onHover: ({ object, x, y }) => {
const tooltip = document.getElementById("tooltip");
if (object) {
const curDate = object.points[0].source.date;

tooltip.style.display = "block";
tooltip.style.left = `${x}px`;
tooltip.style.top = `${y}px`;
tooltip.innerHTML = `<strong>${curDate}</strong><p>Klicke um mehr zu sehen</p>`;
} else {
tooltip.style.display = "none";
}
},
onClick: (info) => showModal(info.object),
}),
],
});
Expand All @@ -97,22 +89,3 @@ fetch(url)
document.getElementById("loading-spinner").style.display = "none"; // Hide spinner on error
console.error("Something went wrong:", error);
});

// Add this CSS for the tooltip
const style = document.createElement("style");
style.innerHTML = `
#tooltip {
position: absolute;
background: white;
padding: 5px;
border: 1px solid black;
display: none;
pointer-events: none;
}
`;
document.head.appendChild(style);

// Add this HTML for the tooltip
const tooltip = document.createElement("div");
tooltip.id = "tooltip";
document.body.appendChild(tooltip);
11 changes: 9 additions & 2 deletions network/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def get_coords(row):
return row["source_lat"], row["source_lng"]


def iso_to_lat_long(iso_date, start_date="1700-01-01", end_date="1990-12-31"):
def iso_to_lat_long(iso_date, start_date="1700-01-01", end_date="1990-12-31", max_width=180):
"""
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).
Expand All @@ -48,10 +48,17 @@ def iso_to_lat_long(iso_date, start_date="1700-01-01", end_date="1990-12-31"):
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").
max_width (int): Max width of longitute.

Returns:
tuple: A tuple containing latitude and longitude (both as floats).
"""
if max_width > 180:
max_width = 180
elif max_width < 0:
max_width = 1
else:
max_width = max_width
try:
# Ensure iso_date is a datetime.date object
if isinstance(iso_date, str):
Expand Down Expand Up @@ -84,7 +91,7 @@ def iso_to_lat_long(iso_date, start_date="1700-01-01", end_date="1990-12-31"):
day_of_year - 1
) / days_in_year # Normalize day position in the year
lon = 180 * day_position

lon = lon % max_width
return lat, lon
except Exception:
return 1, 1
Loading