This repository has been archived by the owner on Dec 27, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
map.py
119 lines (106 loc) · 4.68 KB
/
map.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
from dash import html, dcc, Input, Output
import pandas as pd
import plotly.graph_objects as go
df = pd.read_json('data.json')
mapbox_access_token = "pk.eyJ1IjoicGFibG9zYXZpbmEiLCJhIjoiY2xwbXVreXo4MGN5bTJscXk3YjJwY291ciJ9.Kyrlg9CR1Rdo7wAzD3IAVQ"
# Function to transform a date from the format in the json file (yyyy/mm/dd) to a number
def date2num(date):
broken = date.split("-")
numeric = int(broken[0]) * 10000 + int(broken[1]) * 100 + int(broken[2])
return numeric
# Function to transform a month into a number. Note how we only consider concerts in 2024
def month2num(date):
numeric = 2024 * 10000 + date * 100
return numeric
# Function to create the map depending on the data coming from the timeline
def update_map_info(selection):
# Initial and final month, coming from the timeline
initial = selection[0]
final = selection[1]
# Lists used to then create markers in the map
latitudes = []
longitudes = []
artists = []
# We access all of the available concerts, and check if their date is the interval selected in the timeline
# If it is, we store its latitude, longitude, and artist+date
for artist in df.loc["Concerts"].index:
for concert in df.loc["Concerts"][artist]:
if date2num(concert["Date"]) > month2num(initial) and date2num(concert["Date"]) < month2num(final):
latitude = concert["Latitude"]
longitude = concert["Longitude"]
# If there are multiple concerts in the same location, we place them in slightly different locations
while latitude in latitudes:
latitude = str(float(latitude) + 0.005)
longitude = str(float(longitude) + 0.005)
latitudes.append(latitude)
longitudes.append(longitude)
artists.append(artist + "*" + concert["Date"])
# We create a map, feeding it the data gathered. We also specify the marker style
map = go.Figure()
map.add_trace(go.Scattermapbox(
mode='markers',
lat = latitudes,
lon = longitudes,
marker = {"size" : 12, "symbol" : ["marker"] * len(latitudes), "color" : "rgb(255, 150, 102)"},
text=artists,
hoverinfo='text',
))
# We set some additional visualization properties for the map
map.update_layout(
autosize=True,
hovermode='closest',
paper_bgcolor = '#19323C',
mapbox=dict(
accesstoken=mapbox_access_token,
bearing=0,
center=dict(
lat=39.833333,
lon=-98.583333
),
pitch=0,
zoom=2,
style = "dark",
),
)
return map
# Function to create the timeline
def create_map_timeline() -> html.Div:
return html.Div(
[
# The range slider is created with the months of the year
dcc.RangeSlider
(
min=1,
max=12,
step=None,
marks = {
1: {'label': "January", 'style': {'fontSize': '30px', 'color': '#FF9666'}},
2: {'label': "February", 'style': {'fontSize': '30px', 'color': '#FF9666'}},
3: {'label': "March", 'style': {'fontSize': '30px', 'color': '#FF9666'}},
4: {'label': "April", 'style': {'fontSize': '30px', 'color': '#FF9666'}},
5: {'label': "May", 'style': {'fontSize': '30px', 'color': '#FF9666'}},
6: {'label': "June", 'style': {'fontSize': '30px', 'color': '#FF9666'}},
7: {'label': "July", 'style': {'fontSize': '30px', 'color': '#FF9666'}},
8: {'label': "August", 'style': {'fontSize': '30px', 'color': '#FF9666'}},
9: {'label': "September", 'style': {'fontSize': '30px', 'color': '#FF9666'}},
10: {'label': "October", 'style': {'fontSize': '30px', 'color': '#FF9666'}},
11: {'label': "November", 'style': {'fontSize': '30px', 'color': '#FF9666'}},
12: {'label': "December", 'style': {'fontSize': '30px', 'color': '#FF9666'}}
},
value=[1, 12],
allowCross = False,
id="date-selector"
)
],
id= 'date-slider'
)
def configure_callbacks_map(app) -> None:
"""
Configures the callbacks for the app.
This is a workaround for circular imports.
:param app: The Dash app.
"""
app.callback(
Output(component_id='map', component_property='figure'),
Input(component_id='date-selector', component_property='value')
)(update_map_info)