Skip to content

Commit 180672c

Browse files
committed
Merge branch 'dev' into feature/scatter_plot
2 parents 7adbce0 + e62c89e commit 180672c

File tree

8 files changed

+349
-26
lines changed

8 files changed

+349
-26
lines changed

Procfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
web: gunicorn src.app:server
1+
web: gunicorn src.app:server

README.md

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,48 @@
1-
# Tsunami Events Dashboard (Python)
2-
This app will contain a landing page with three tiles; an interactive geographical map that users can pan across to see the location of each tsunami as well as its strength, a time series graph showing the number of deaths by country, and a table presenting the top 10 strongest tsunamis. All three graphics will be filterable by using the collapsible menu which contains two widgets; a slider to select a range of years and a dropdown menu to filter which countries they would like to see. The geographical map makes use of the latitude and longitude in the data set to identify locations where a tsunami occurred and will have a heat map to represent the magnitude of the tsunami as well as the ability for users to hover over a tsunami to glean more information about a particular tsunami. Similarly, users will also be able to use this feature in the table of strongest tsunamis which will have a dropdown to select the top 5, top 10, or top 20 strongest tsunamis of the chosen period. Lastly, the time series graph will show the number of deaths by country and is filterable by a period and countries.
1+
# Tsunami Events Dashboard (Python)
2+
3+
## Accessing the App via Heroku
4+
5+
Link to Heroku app: [tsunami-events-dashboard](https://dashboard.heroku.com/apps/tsunami-events-dashboard)
6+
7+
## Description of the App Interface
8+
9+
This app contains a landing page with three tiles: an interactive geographical map that users can pan across to see the location of each tsunami as well as its strength, a time series graph showing the number of deaths by country, and a table listing the strongest tsunamis. The tsunami events data underlying the three plots is filtered for using a collapsible menu that contains two widgets: a slider to select a range of years of occurrence, and a drop-down menu to filter for countries impacted. The geographical map makes use of the tsunami latitude and longitude location data, generates a heat map to indicate tsunami magnitude, and allows users to hover over tsunami events plotted on the map to glean more comprehensive event details. Users can also peruse of a table listing the strongest tsunami events per the year and country selection applied, with the option to select from among a display of the top 5, 10 , 20 strongest events. Lastly, the time series graph shows the number of deaths by country per the year and country selection applied.
310

411
## Proposal
5-
Our proposal can be found via this link: [proposal](proposal.md)
12+
13+
Our proposal can be found via this link: [proposal](docs/proposal.md)
614

715
## Dashboard Sketch
16+
817
![dashboard sketch](img/tsunami_sketch.jpg)
18+
19+
## Accessing the App Locally
20+
21+
To run and explore the app locally, clone the git repo and install required dependencies:
22+
23+
git clone https://github.com/UBC-MDS/tsunami-events-dashboard-python.git
24+
25+
pip install -r requirements.txt
26+
27+
Then, run the app:
28+
29+
python src/app.py
30+
31+
## Built with
32+
33+
- [Dash](https://dash.plot.ly/) - Main server and interactive components
34+
- [Altair](https://altair-viz.github.io/index.html) - Used to generate interactive plots, using Python
35+
- [Pandas](https://pandas.pydata.org/) - Used for data wrangling and pre-processing
36+
37+
## Contributing
38+
39+
| Contributors | Github |
40+
|----------------------|-----------------------|
41+
| Gautham Pughazhendhi | \@gauthampughazhendhi |
42+
| Jacqueline Chong | \@Jacq4nn |
43+
| Rowan Sivanandam | \@Rowansiv |
44+
| Vadim Taskaev | \@vtaskaev1 |
45+
46+
## License
47+
48+
[![MIT license](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/UBC-MDS/532-Group21/blob/main/LICENSE)

docs/reflections-milestone2.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Reflections for Milestone 2
2+
3+
*By **DSCI 532 Group 11***
4+
5+
## What we have implemented
6+
In this milestone, we have attempted to create three plots.
7+
First, a map plot highlighting the intensity of earthquakes and the countries that were affected by the tsunami (underwater earthquakes).
8+
Second, a scatter plot to plot the trend of the earthquakes according to its intensity on the Richter Scale.
9+
Third, a bar chart to highlight the top 10 tsunamis with the highest tsunami intensity of a given time period. (This is different from the earthquake intensity on the Richter Scale).
10+
11+
To use this dashboard, the user will be able to toggle the specific years and countries that they will like to examine on the left sidebar.
12+
The default argument for the time period for all three plots will from 1802 to 2022.
13+
The default argument for the countries for the map plot and scatter plot will be all countries.
14+
The scatter plot will highlight the top 10 countries from 1802 to 2022.
15+
16+
The bar chart will only take in the values for the years, and not the countries as it
17+
will display the top 10 most intense tsunamis across the world based on time period specified.
18+
19+
## What could be improved
20+
The structure of the dashboard needs to be improved greatly to make it more streamlined. Moreover, we would like to increase the functionality of the sidebar where users can collapse it,
21+
such that the plot is rendered larger. Moreover, we would like to add a buttom besides the scatter plot and bar chart, to inform readers about how to interpret the 'Richter Scale' and 'Tsunami Intensity'.
22+
23+
The convention of the naming of the functions within each component can also be improved, to allow future collaborators to understand our code with ease.

requirements.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
pandas
2-
gunicorn
31
altair
2+
gunicorn
43
dash
54
dash_bootstrap_components
65
plotly
7-
vega_datasets
6+
vega_datasets
7+
pandas

src/app.py

Lines changed: 205 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,209 @@
1-
from dash import Dash, html
1+
import dash
2+
from dash import Dash, html, dcc, State, Input, Output
3+
from components.map_plot import create_map_plot
4+
from components.scatter_plot import create_scatter_plot
5+
from components.dropdown import create_bar_plot
6+
7+
import dash_bootstrap_components as dbc
8+
import pandas as pd
9+
10+
# Read in data
11+
tsunami_df = pd.read_csv('data/processed/tsunami-events.csv')
12+
13+
years = tsunami_df['year'].dropna().unique() # need to add start and end year
14+
countries = tsunami_df['country'].dropna().unique()
15+
country_list = sorted(list(countries)) # countries are listed alphabetically
16+
17+
app = dash.Dash(
18+
__name__, title = "Tsunami History", external_stylesheets=[dbc.themes.QUARTZ]
19+
)
220

3-
app = Dash()
421
server = app.server
522

6-
app.layout = html.Div("Hello world!")
23+
# Creating style for both sidebar and plots
24+
SIDEBAR_STYLE = {
25+
"position": "fixed",
26+
"top": '62px',
27+
"left": 0,
28+
"bottom": 0,
29+
"width": "20rem",
30+
"padding": "2rem 1rem",
31+
"z-index": 4000000,
32+
'background-color': 'rgba(255,255,255,.25)'
33+
34+
}
35+
36+
CONTENT_STYLE = {
37+
"margin-left": "20rem",
38+
"margin-right": "2rem",
39+
"z-index": -1,
40+
}
41+
# Structure of app, including selection criteria components
42+
43+
# Formatting NavBar
44+
navbar = dbc.Navbar(
45+
dbc.Container(
46+
[
47+
html.A(
48+
# Use row and col to control vertical alignment of logo / brand
49+
dbc.Row(
50+
[
51+
# dbc.Col(html.Img(src=PLOTLY_LOGO, height="30px")),
52+
dbc.Col(dbc.NavbarBrand("Tsunami Events Dashboard", className="ms-2")),
53+
],
54+
align="center",
55+
className="g-0",
56+
),
57+
# href="https://plotly.com",
58+
# style={"textDecoration": "none"},
59+
),
60+
dbc.NavbarToggler(id="navbar-toggler", n_clicks=0),
61+
dbc.Collapse(
62+
# search_bar,
63+
id="navbar-collapse",
64+
is_open=False,
65+
navbar=True,
66+
),
67+
],
68+
style = {
69+
'margin-left': '15px',
70+
'font-weight': "600"}
71+
),
72+
color="dark",
73+
dark=True,
74+
)
75+
76+
world_plot_card = dbc.Card(
77+
dbc.CardBody(
78+
[html.H6('Total Tsunami Hits by Country with Origin Points', className = 'card-title',
79+
style = {'margin-bottom': '0px'}),
80+
html.Iframe(
81+
id='map_plot',
82+
style={'border-width': '0', 'height': '380px', 'width': '100%'},
83+
srcDoc=create_map_plot(year_start=1800, year_end=2022, countries=[]))
84+
], style = {'padding': '15px', 'padding-bottom': '0px'}
85+
),
86+
style = {'padding': 0}
87+
)
88+
89+
scatter_plot_card = dbc.Card(
90+
dbc.CardBody(
91+
[html.H6('Total Deaths by Earthquake Magnitude', className = 'card-title',
92+
style = {'margin-bottom': '0px'}),
93+
html.Iframe(
94+
id = 'scatter_plot',
95+
style={'border-width': '0', 'height': '220px','width': '100%'},
96+
srcDoc=create_scatter_plot(year_start=1800, year_end=2022, countries=[])
97+
)], style = {'padding': '15px', 'padding-bottom': '0px'}
98+
),
99+
style = {'padding':0}
100+
)
101+
102+
bar_chart_card = dbc.Card(
103+
dbc.CardBody(
104+
[html.H6('Top 10 most intense tsunami in given years', className = 'card-title',
105+
style = {'margin-bottom': '0px'}),
106+
html.Iframe(
107+
id = 'bar_plot',
108+
style={'border-width': '0', 'height': '220px','width': '100%'},
109+
srcDoc=create_bar_plot(year_start=1800, year_end=2022)
110+
)], style = {'padding': '15px', 'padding-bottom': '0px'}
111+
),
112+
style = {'padding':0}
113+
)
114+
115+
app.layout = dbc.Container([
116+
navbar,
117+
dbc.Row([
118+
dbc.Col([
119+
html.H5('Years and Countries Selection', className = 'form-label'),
120+
html.Hr(),
121+
html.H6('Years of Interest (1800 - 2022)', className = 'form-label'),
122+
dcc.RangeSlider(
123+
min = 1800,
124+
max = 2022,
125+
value = [tsunami_df['year'].min(), tsunami_df['year'].max()],
126+
marks = None,
127+
id='year_slider',
128+
allowCross = False, # Prevent handles from crossing each other
129+
tooltip = {'placement': 'bottom',
130+
'always_visible': True}),
131+
html.Br(),
132+
html.Br(),
133+
html.H6('Countries of Interest', className = 'form-label'),
134+
dcc.Dropdown(
135+
id='country_select',
136+
multi = True,
137+
value = [],
138+
options = [{'label': country, 'value': country} for country in country_list],
139+
className = 'text-dark'),
140+
html.Hr(),
141+
html.P(
142+
"A data visualisation app that allows viewers to observe the number and intensity of tsunamis based on years and countries",
143+
className = 'form-label'
144+
)
145+
],
146+
style = SIDEBAR_STYLE,
147+
className = "btn btn-secondary"
148+
),
149+
dbc.Col([
150+
dbc.Row([
151+
world_plot_card
152+
], style = {'margin': 'auto', 'width': '800px', 'padding':'0px'}),
153+
html.Br(),
154+
dbc.Row([
155+
dbc.Col([
156+
scatter_plot_card
157+
], style = {'margin': 'auto', 'width': '400px'}),
158+
dbc.Col([
159+
bar_chart_card
160+
], style = {'margin': 'auto', 'width': '400px'})
161+
],style = {'margin': 'auto', 'width': '1020px'})
162+
],
163+
style = CONTENT_STYLE)
164+
])
165+
], fluid = True,
166+
style = {
167+
'backgroundColor': 'black',
168+
'padding': '0px',
169+
'height': '100vh'
170+
})
171+
172+
# App callback for map_plot
173+
@app.callback(
174+
Output('map_plot', 'srcDoc'),
175+
Input('year_slider', 'value'),
176+
Input('country_select', 'value')
177+
)
178+
def update_map_plot(value, value_country):
179+
return create_map_plot(value[0], value[1], value_country)
180+
181+
# App callback for scatter_plot
182+
@app.callback(
183+
Output('scatter_plot', 'srcDoc'),
184+
Input('year_slider', 'value'),
185+
Input('country_select', 'value')
186+
)
187+
def update_scatter_plot(value, value_country):
188+
return create_scatter_plot(value[0], value[1], value_country)
189+
190+
# App callback for bar_plot
191+
@app.callback(
192+
Output('bar_plot', 'srcDoc'),
193+
Input('year_slider', 'value')
194+
)
195+
def update_bar_plot(value):
196+
return create_bar_plot(value[0], value[1])
197+
198+
@app.callback(
199+
Output("navbar-collapse", "is_open"),
200+
[Input("navbar-toggler", "n_clicks")],
201+
[State("navbar-collapse", "is_open")],
202+
)
203+
def toggle_navbar_collapse(n, is_open):
204+
if n:
205+
return not is_open
206+
return is_open
7207

8-
app.run_server()
208+
if __name__ == '__main__':
209+
app.run_server()

src/components/dropdown.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import altair as alt
2+
from dash import Dash, dcc, html, Input, Output
3+
from vega_datasets import data
4+
import pandas as pd
5+
6+
PROCESSED_DATA_PATH = "data/processed/tsunami-events.csv"
7+
8+
def preprocess(year_start, year_end):
9+
"""The function to return the processed dataframe with a new index column
10+
and combination column of the country and year. Also filters the df
11+
based on the callback year slider for tsunamis occurring between
12+
specific dates, then reorders by tsunami intensity.
13+
Parameters
14+
----------
15+
year_start : int
16+
the lower bound of the range of years selected by user
17+
year_end : int
18+
the upper bound of the range of years selected by user
19+
Returns
20+
-------
21+
df:
22+
a processed dataframe with additional columns and filtered
23+
data
24+
"""
25+
df = pd.read_csv(PROCESSED_DATA_PATH)
26+
df['tsunami_instance'] = range(1, len(df) + 1)
27+
df['tsunami_instance'] = df.index
28+
df['combine'] = df['country'].astype(str) + ', ' + df['year'].astype(str)
29+
df = df.query('tsunami_intensity > 0')
30+
df = df.query(f"{year_start} <= year <= {year_end}")
31+
df = df.sort_values(by=['tsunami_intensity'], ascending = False)
32+
df = df[0:10]
33+
return df
34+
35+
def create_bar_plot(year_start, year_end):
36+
"""The function to create a bar graph of the highest intensity
37+
tsunamis between the year_start and year_end.
38+
Parameters
39+
----------
40+
year_start : int
41+
the lower bound of the range of years selected by user
42+
year_end : int
43+
the upper bound of the range of years selected by user
44+
Returns
45+
-------
46+
bar plot object
47+
horizontal bar graph of greatest intensity tsunamis with tooltip
48+
to glean further information when hovering over each bar.
49+
"""
50+
df = preprocess(year_start, year_end)
51+
chart = alt.Chart(df).mark_bar().encode(
52+
x=alt.X('tsunami_intensity:Q', title = 'Tsunami Intensity', scale=alt.Scale(domain=(0, 12))),
53+
y=alt.Y('tsunami_instance:N', sort = '-x', title = 'Country', axis = alt.Axis(labelExpr="datum.country")),
54+
color=alt.Color('country:O'),
55+
tooltip=("country:O", "location_name:O", "tsunami_intensity:Q", "earthquake_magnitude:Q", "year:Q", "month:O")
56+
).properties(width=240, height=160)
57+
tooltip=("country:O", "location_name:O", "tsunami_intensity:Q", "earthquake_magnitude:Q", "year:Q", "month:O"))
58+
59+
text = chart.mark_text(align="left", baseline="middle", dx = 3).encode(
60+
text= 'combine:O')
61+
62+
plot = chart + text
63+
return plot.to_html()

0 commit comments

Comments
 (0)