Py.Cafe

banana0000/

US Hurricanes Analysis

US Hurricanes

DocsPricing
  • app.py
  • requirements.txt
app.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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
from dash import Dash, dcc, html, Input, Output
import plotly.express as px
import pandas as pd
import dash_bootstrap_components as dbc

# Load the data
df = pd.read_csv('https://raw.githubusercontent.com/plotly/Figure-Friday/refs/heads/main/2025/week-11/us-hurricanes.csv')

# Convert the row value of `TS` under the `category` column to a NaN
df['category'] = df['category'].replace('TS', pd.NA)

# Create year ranges for temporal analysis
df['decade'] = (df['year'] // 10) * 10
df['decade'] = df['decade'].astype(str) + 's'

# Create a more detailed dataframe for the bar chart
yearly_data = df.groupby('year').agg({
    'max-wind-(kt)': 'mean',
    'central-pressure-(mb)': 'mean',
    'name': lambda x: ', '.join(set(x.dropna()))  # Get unique names
}).reset_index()

# Count hurricanes per year
yearly_count = df.groupby('year').size().reset_index(name='count')

# Merge the data
yearly_data = pd.merge(yearly_data, yearly_count, on='year')

# Create a bar chart with enhanced tooltip
year_count_fig = px.bar(
    yearly_data,
    x='year',
    y='count',
    title='',
    height=500,
    hover_data={ 
        'year': True,
        'count': True,
        'max-wind-(kt)': ':.1f',
        'central-pressure-(mb)': ':.1f',
        'name': True
    },
    labels={ 
        'year': 'Year',
        'count': 'Number of Hurricanes',
        'max-wind-(kt)': 'Avg. Wind Speed (kt)',
        'central-pressure-(mb)': 'Avg. Central Pressure (mb)',
        'name': 'Hurricane Names'
    }
)

# Set the background color to dark grey for the bar chart
year_count_fig.update_layout(
    plot_bgcolor='#2E2E2E',  # Dark grey background
    xaxis_title='',
    yaxis_title='Number of Hurricanes',
    hovermode='closest',
    hoverlabel=dict(
        bgcolor='black',
        font_size=12
    ),
    xaxis=dict(showgrid=False),  # Remove gridlines on x-axis
    yaxis=dict(showgrid=False),   # Remove gridlines on y-axis
    autosize=True,  # Fontos: Hozzáadtuk az autosize paramétert
    margin=dict(l=20, r=20, t=20, b=20)  # Csökkentett margók
)

year_count_fig.update_traces(marker=dict(color='rgb(0, 115, 230)'))

# Create a heatmap of hurricanes by decade and category
heatmap_data = df.dropna(subset=['category']).groupby(['decade', 'category']).size().reset_index(name='count')

# Initial heatmap figure with color scale
initial_color_scale = px.colors.sequential.Bluered
heatmap_fig = px.density_heatmap(
    heatmap_data,
    x='decade',
    y='category',
    z='count',
    color_continuous_scale=initial_color_scale,
    title='',
    height=400
)

# Set background color to dark grey for the heatmap
heatmap_fig.update_layout(
    plot_bgcolor='#2E2E2E',  # Dark grey background
    xaxis_title='',
    yaxis_title='Hurricane Category',
    coloraxis_colorbar_title='Count of Categories',
    xaxis=dict(showgrid=False),  # Remove gridlines on x-axis
    yaxis=dict(showgrid=False),   # Remove gridlines on y-axis
    autosize=True,  # Autosize engedélyezése
    margin=dict(l=20, r=20, t=20, b=20)  # Csökkentett margók
)

# Create a dashboard with the 2 visualizations using Bootstrap
app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])

# Teljes képernyő (viewport) szélességű konténert használunk
app.layout = dbc.Container([
    dbc.Row([
        dbc.Col([
            html.H1(
                'US Hurricanes Analysis',
                className='text-center mt-4 mb-2',
                style={
                    'color': 'black',
                    'font-family': 'Arial, sans-serif',
                    'font-weight': 'bold',
                    'font-size': '40px',
                    'letter-spacing': '1px',
                }
            ),
            html.Div(
                '1851 - 2023',
                className='text-center mb-4',
                style={
                    'fontSize': '20px',
                    'color': 'black'
                }
            ),
        ], width=12)
    ]),
    
    dbc.Row([
        dbc.Col([
            dbc.Card([
                dbc.CardHeader([
                    html.H3('Number of Hurricanes by Year', className='d-inline me-3'),
                    html.Span(
                        'This chart shows the annual frequency of hurricanes with detailed information available on hover.',
                        className='text-muted fst-italic'
                    )
                ]),
                dbc.CardBody([
                    # Fontos: style tulajdonságot adtunk hozzá a graph-hoz
                    dcc.Graph(
                        id='bar-chart', 
                        figure=year_count_fig,
                        style={'width': '100%', 'height': '500px'},  # Explicit szélesség és magasság
                        config={'responsive': True}  # Responsive beállítás
                    )
                ], style={'padding': '0'})  # Csökkentjük a CardBody padding-jét
            ], className='mb-4', style={'width': '100%'})  # Explicit szélesség a card-nak
        ], width=12, style={'padding': '0 5px'})  # Minimális padding az oszlopnak
    ], className='g-0'),  # Kikapcsoljuk a grid gutter-eket
    
    dbc.Row([
        dbc.Col([
            dbc.Card([
                dbc.CardHeader([
                    html.H3('Hurricane Frequency by Decade and Category', className='d-inline me-3'),
                    html.Span(
                        'This heatmap visualizes the distribution of hurricane categories across different decades.',
                        className='text-muted fst-italic'
                    )
                ]),
                dbc.CardBody([
                    html.Label('Select Color Scale:'),
                    dcc.Slider(
                        id='color-scale-slider',
                        min=0,
                        max=10,
                        marks={i: {'label': scale} for i, scale in enumerate(px.colors.named_colorscales()[:11])},
                        value=0,
                        step=1,
                        tooltip={"placement": "bottom", "always_visible": True},
                        updatemode='drag',
                        className='mb-4'
                    ),
                    # Fontos: style tulajdonságot adtunk hozzá a graph-hoz
                    dcc.Graph(
                        id='heatmap-graph', 
                        figure=heatmap_fig,
                        style={'width': '100%', 'height': '400px'},  # Explicit szélesség és magasság
                        config={'responsive': True}  # Responsive beállítás
                    )
                ], style={'padding': '10px 0'})  # Csökkentjük a CardBody padding-jét
            ], style={'width': '100%'})  # Explicit szélesség a card-nak
        ], width=12, style={'padding': '0 5px'})  # Minimális padding az oszlopnak
    ], className='g-0')  # Kikapcsoljuk a grid gutter-eket
], fluid=True, style={'backgroundColor': '#add8e6', 'padding': '20px', 'maxWidth': '100%'})  # Explicit maxWidth

# Callback to update both the heatmap and bar chart color scale
@app.callback(
    [Output('heatmap-graph', 'figure'),
     Output('bar-chart', 'figure')],
    [Input('color-scale-slider', 'value')]
)
def update_color_scale(slider_value):
    selected_scale = px.colors.named_colorscales()[slider_value]
    
    # Update heatmap
    updated_heatmap = px.density_heatmap(
        heatmap_data,
        x='decade',
        y='category',
        z='count',
        color_continuous_scale=selected_scale,
        title='',
        height=400
    )
    updated_heatmap.update_layout(
        plot_bgcolor='#2E2E2E',
        xaxis_title='',
        yaxis_title='Hurricane Category',
        coloraxis_colorbar_title='Count of Category',
        xaxis=dict(showgrid=False),
        yaxis=dict(showgrid=False),
        autosize=True,  # Autosize engedélyezése
        margin=dict(l=20, r=20, t=20, b=20)  # Csökkentett margók
    )
    
    # Update bar chart with the new selected color scale
    updated_bar_chart = px.bar(
        yearly_data,
        x='year',
        y='count',
        title='',
        height=500,
        hover_data={ 
            'year': True,
            'count': True,
            'max-wind-(kt)': ':.1f',
            'central-pressure-(mb)': ':.1f',
            'name': True
        },
        labels={ 
            'year': 'Year',
            'count': 'Number of Hurricanes',
            'max-wind-(kt)': 'Avg. Wind Speed (kt)',
            'central-pressure-(mb)': 'Avg. Central Pressure (mb)',
            'name': 'Hurricane Names'
        },
        color=yearly_data['count'],
        color_continuous_scale=selected_scale
    )
    
    updated_bar_chart.update_layout(
        plot_bgcolor='#2E2E2E',
        xaxis_title='',
        yaxis_title='Number of Hurricanes',
        hovermode='closest',
        hoverlabel=dict(
            bgcolor='black',
            font_size=12
        ),
        xaxis=dict(showgrid=False),
        yaxis=dict(showgrid=False),
        autosize=True,  # Autosize engedélyezése
        margin=dict(l=20, r=20, t=20, b=20)  # Csökkentett margók
    )
    
    return updated_heatmap, updated_bar_chart

if __name__ == '__main__':
    app.run(debug=False)