Spaces:
Sleeping
Sleeping
Upload app.py
Browse files
app.py
ADDED
|
@@ -0,0 +1,316 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
import pandas as pd
|
| 3 |
+
import numpy as np
|
| 4 |
+
import matplotlib.pyplot as plt
|
| 5 |
+
import seaborn as sns
|
| 6 |
+
import altair as alt
|
| 7 |
+
import plotly.express as px
|
| 8 |
+
|
| 9 |
+
# Cache the data loading function using st.cache_data
|
| 10 |
+
@st.cache
|
| 11 |
+
def load_data():
|
| 12 |
+
data = pd.read_csv('data_cleaned.csv')
|
| 13 |
+
return data
|
| 14 |
+
|
| 15 |
+
# Load the data
|
| 16 |
+
data = load_data()
|
| 17 |
+
|
| 18 |
+
# Sidebar for selecting sections
|
| 19 |
+
st.sidebar.title("Explore Financial Insights")
|
| 20 |
+
option = st.sidebar.radio(
|
| 21 |
+
"Select an analysis section:",
|
| 22 |
+
("Home", 'Description of Variables', "Regional-Based Analysis", "Income-Based Analysis", "Gender-Based Analysis")
|
| 23 |
+
)
|
| 24 |
+
|
| 25 |
+
# Add a summary of Findex at the bottom of the sidebar
|
| 26 |
+
st.sidebar.markdown("### What is Findex?")
|
| 27 |
+
st.sidebar.write("""
|
| 28 |
+
The Global Findex database provides comprehensive data on how adults worldwide save, borrow, make payments, and manage risk.
|
| 29 |
+
Launched with support from the Bill & Melinda Gates Foundation, the database is updated every three years and is the world’s most
|
| 30 |
+
detailed dataset on how adults use formal and informal financial services. It offers insights into the financial behaviors and
|
| 31 |
+
access to financial systems globally.
|
| 32 |
+
|
| 33 |
+
For more information, visit the [Global Findex website](https://www.worldbank.org/en/publication/globalfindex).
|
| 34 |
+
""")
|
| 35 |
+
|
| 36 |
+
# Main section logic
|
| 37 |
+
if option == "Home":
|
| 38 |
+
# First display the Plotly globe with the title
|
| 39 |
+
# Create the globe visualization
|
| 40 |
+
economy_data = data['economy'].value_counts(normalize=True) * 100
|
| 41 |
+
economy_df = economy_data.reset_index()
|
| 42 |
+
economy_df.columns = ['economy', 'percentage']
|
| 43 |
+
|
| 44 |
+
# Round the percentage to 2 decimal places for display
|
| 45 |
+
economy_df['percentage'] = economy_df['percentage'].round(2)
|
| 46 |
+
|
| 47 |
+
# Create a choropleth map using Plotly with a green color scheme
|
| 48 |
+
fig = px.choropleth(
|
| 49 |
+
economy_df,
|
| 50 |
+
locations='economy',
|
| 51 |
+
locationmode='country names',
|
| 52 |
+
color='percentage',
|
| 53 |
+
hover_name='economy',
|
| 54 |
+
hover_data={'percentage': ':.2f'}, # Format hover data to 2 decimal places
|
| 55 |
+
color_continuous_scale='Greens',
|
| 56 |
+
)
|
| 57 |
+
|
| 58 |
+
# Update hover text to add the percentage sign
|
| 59 |
+
fig.update_traces(
|
| 60 |
+
hovertemplate="<b>%{hovertext}</b><br>" +
|
| 61 |
+
"percentage=%{z:.2f}%<extra></extra>",
|
| 62 |
+
hovertext=economy_df['economy']
|
| 63 |
+
)
|
| 64 |
+
|
| 65 |
+
# Add the title to the Plotly chart itself, making it bold and larger
|
| 66 |
+
fig.update_layout(
|
| 67 |
+
title=dict(
|
| 68 |
+
text="FINDEX 2021 Data Visualizer", # Title text
|
| 69 |
+
font=dict(size=49, color='black', family="Raleway, sans-serif"), # Stylish font and bigger size
|
| 70 |
+
x=0.5, # Center the title
|
| 71 |
+
xanchor='center',
|
| 72 |
+
y=0.95, # Adjust positioning
|
| 73 |
+
yanchor='top',
|
| 74 |
+
pad=dict(t=20), # Add padding to reduce space
|
| 75 |
+
),
|
| 76 |
+
geo=dict(
|
| 77 |
+
showframe=True, # Show a frame around the map
|
| 78 |
+
framecolor="black", # Frame color
|
| 79 |
+
showcoastlines=True, # Keep coastlines visible
|
| 80 |
+
coastlinecolor="Black", # Set coastlines color to black
|
| 81 |
+
projection_type='orthographic', # Change projection to orthographic for a globe effect
|
| 82 |
+
projection_scale=0.85, # Zoom out more by reducing the scale
|
| 83 |
+
center=dict(lat=10, lon=0), # Center the globe around the equator
|
| 84 |
+
lataxis_range=[-85, 85], # Strictly limit the vertical dragging
|
| 85 |
+
lonaxis_range=[-180, 180], # Strictly limit the horizontal dragging
|
| 86 |
+
oceancolor='lightblue', # Set the color of the oceans
|
| 87 |
+
showocean=True, # Ensure oceans are displayed
|
| 88 |
+
),
|
| 89 |
+
coloraxis_colorbar=dict(
|
| 90 |
+
title="Participation (%)",
|
| 91 |
+
len=0.5,
|
| 92 |
+
thickness=15,
|
| 93 |
+
tickvals=[0.5, 1, 1.5, 2],
|
| 94 |
+
ticks="outside",
|
| 95 |
+
),
|
| 96 |
+
width=1000,
|
| 97 |
+
height=800,
|
| 98 |
+
margin={"r":50,"t":50,"l":0,"b":0}
|
| 99 |
+
)
|
| 100 |
+
|
| 101 |
+
# Display the Plotly chart first
|
| 102 |
+
st.plotly_chart(fig, use_container_width=True, config={'displayModeBar': False})
|
| 103 |
+
|
| 104 |
+
# Now display the Financial Inclusion and Behaviour description
|
| 105 |
+
st.markdown("""
|
| 106 |
+
This application leverages the Global Findex 2021 dataset with over 140,000 participants to explore financial inclusion and behavior across various economies worldwide.
|
| 107 |
+
|
| 108 |
+
Key features of this application include:
|
| 109 |
+
- **Quick Visualization**: Instantly visualize the percentage of respondents from each country who participate in various financial services.
|
| 110 |
+
- **Regional Analysis**: Explore financial trends and behaviors by country and region, identifying disparities in access to financial systems.
|
| 111 |
+
- **Income-Based Analysis**: Analyze financial behaviors like savings, borrowing, and digital payments across different income levels.
|
| 112 |
+
- **Gender-Based Analysis**: Compare financial inclusion patterns between genders, looking into variables such as account ownership, borrowing, and savings behavior.
|
| 113 |
+
""")
|
| 114 |
+
|
| 115 |
+
elif option == "Description of Variables":
|
| 116 |
+
st.markdown("<h2 style='text-align: center;'>Descripton of Variables</h2>", unsafe_allow_html=True)
|
| 117 |
+
st.markdown("""
|
| 118 |
+
- **economy**: The name of the country or economy.
|
| 119 |
+
- **economycode**: ISO 3-digit code representing each economy.
|
| 120 |
+
- **regionwb**: World Bank region classification (e.g., Sub-Saharan Africa, East Asia, etc.).
|
| 121 |
+
- **pop_adult**: The population of adults (aged 15+) in the economy.
|
| 122 |
+
- **wpid_random**: A unique identifier for each respondent in the dataset.
|
| 123 |
+
- **wgt**: Survey weight for each respondent, used to make the sample representative of the population.
|
| 124 |
+
- **female**: Gender of the respondent (1 if female, 2 if male).
|
| 125 |
+
- **age**: Age of the respondent.
|
| 126 |
+
- **educ**: Respondent’s education level from level 1 to 3.
|
| 127 |
+
- **inc_q**: Income quintile of the respondent’s household.
|
| 128 |
+
- **emp_in**: Employment status of the respondent.
|
| 129 |
+
- **account**: Whether the respondent has an account at a financial institution or with a mobile money service provider.
|
| 130 |
+
- **account_fin**: Whether the respondent has an account at a formal financial institution.
|
| 131 |
+
- **fin2**: Has a debit card.
|
| 132 |
+
- **fin14_1**: Whether the respondent used mobile money.
|
| 133 |
+
- **fin14a**: Made bill payments online using the Internet.
|
| 134 |
+
- **fin14a1**: Sent money to a relative or friend online using the Internet.
|
| 135 |
+
- **fin14b**: Bought something online using the Internet.
|
| 136 |
+
- **fin16**: Saved for old age.
|
| 137 |
+
- **fin17a**: Saved using an account at a financial institution.
|
| 138 |
+
- **fin20**: Borrowed for medical purposes.
|
| 139 |
+
- **fin22a**: Borrowed from a financial institution.
|
| 140 |
+
- **fin22b**: Borrowed from family or friends.
|
| 141 |
+
- **fin24**: Main source of emergency funds in 30 days.
|
| 142 |
+
- **fin30**: Paid a utility bill.
|
| 143 |
+
- **fin32**: Received wage payments.
|
| 144 |
+
- **fin37**: Received a government transfer.
|
| 145 |
+
- **fin38**: Received a government pension.
|
| 146 |
+
- **fin44a**: Financially worried: old age.
|
| 147 |
+
- **fin44b**: Financially worried: medical cost.
|
| 148 |
+
- **fin44c**: Financially worried: bills.
|
| 149 |
+
- **fin44d**: Financially worried: education.
|
| 150 |
+
- **saved**: Saved money in the past 12 months.
|
| 151 |
+
- **borrowed**: Borrowed money in the past 12 months.
|
| 152 |
+
- **receive_wages**: Received a wage payment and method.
|
| 153 |
+
- **receive_transfers**: Received government transfers or aid payments and method.
|
| 154 |
+
- **receive_pension**: Received government pension payments and method.
|
| 155 |
+
- **pay_utilities**: Paid utility bills and method.
|
| 156 |
+
- **mobileowner**: Whether the respondent owns a mobile phone.
|
| 157 |
+
- **internetaccess**: Whether the respondent has access to the internet.
|
| 158 |
+
- **anydigpayment**: Whether the respondent made any digital payment.
|
| 159 |
+
- **year**: The year of the data collection.
|
| 160 |
+
""")
|
| 161 |
+
|
| 162 |
+
|
| 163 |
+
# Main section logic for each page
|
| 164 |
+
if option == "Regional-Based Analysis":
|
| 165 |
+
st.markdown("<h2 style='text-align: center;'>Regional Analysis</h2>", unsafe_allow_html=True)
|
| 166 |
+
st.write("This section allows you to explore financial trends and behaviors, including savings, borrowing, and digital payments, across various regions. You can compare how access to financial systems differs between regions and examine disparities in financial inclusion globally.")
|
| 167 |
+
|
| 168 |
+
|
| 169 |
+
# List of regions from your dataset (assuming 'regionwb' column holds this data)
|
| 170 |
+
regions = data['regionwb'].unique()
|
| 171 |
+
|
| 172 |
+
# Multiselect for region selection
|
| 173 |
+
selected_regions = st.multiselect("Select regions to compare", options=regions, default=regions[0])
|
| 174 |
+
|
| 175 |
+
# Filter data based on selected regions
|
| 176 |
+
regional_data = data[data['regionwb'].isin(selected_regions)]
|
| 177 |
+
|
| 178 |
+
# Allow user to choose which variable they want to analyze
|
| 179 |
+
variable_to_compare = st.selectbox("Select variable to analyze:", options=[
|
| 180 |
+
'account', 'saved', 'borrowed', 'fin14a', 'fin44a', 'mobileowner', 'internetaccess', 'anydigpayment'
|
| 181 |
+
])
|
| 182 |
+
|
| 183 |
+
|
| 184 |
+
# Summarize the data for the selected regions and variable
|
| 185 |
+
summary = regional_data.groupby('regionwb')[variable_to_compare].mean().reset_index()
|
| 186 |
+
summary.columns = ['regionwb', f'Average {variable_to_compare}']
|
| 187 |
+
|
| 188 |
+
# Create an interactive Plotly bar chart to compare the regions
|
| 189 |
+
fig = px.bar(summary, x='regionwb', y=f'Average {variable_to_compare}',
|
| 190 |
+
title=f"Comparison of {variable_to_compare} Across Selected Regions",
|
| 191 |
+
labels={'regionwb': 'Region', f'Average {variable_to_compare}': f'Average {variable_to_compare}'},
|
| 192 |
+
color='regionwb')
|
| 193 |
+
|
| 194 |
+
# Update layout for better aesthetics
|
| 195 |
+
fig.update_layout(
|
| 196 |
+
xaxis_title="Region",
|
| 197 |
+
yaxis_title=f"Average {variable_to_compare}",
|
| 198 |
+
showlegend=False,
|
| 199 |
+
width=800,
|
| 200 |
+
height=500,
|
| 201 |
+
margin={"r":0,"t":50,"l":0,"b":50},
|
| 202 |
+
)
|
| 203 |
+
|
| 204 |
+
# Show the chart in Streamlit
|
| 205 |
+
st.plotly_chart(fig)
|
| 206 |
+
|
| 207 |
+
|
| 208 |
+
elif option == "Income-Based Analysis":
|
| 209 |
+
st.markdown("<h2 style='text-align: center;'>Income-Based Analysis</h2>", unsafe_allow_html=True)
|
| 210 |
+
st.write("This section allows you to analyze financial behaviors such as savings, borrowing, and digital payments across different income levels.")
|
| 211 |
+
|
| 212 |
+
# Select Income Quintile
|
| 213 |
+
income_quintile = st.selectbox("Select Income Quintile:", data['inc_q'].unique())
|
| 214 |
+
|
| 215 |
+
# Filter the data based on the selected income quintile
|
| 216 |
+
filtered_data_income = data[data['inc_q'] == income_quintile]
|
| 217 |
+
|
| 218 |
+
# Multi-select for financial indicators
|
| 219 |
+
selected_indicators_income = st.multiselect(
|
| 220 |
+
"Select Financial Indicators to Analyze:",
|
| 221 |
+
['account', 'saved', 'borrowed', 'anydigpayment'],
|
| 222 |
+
default=['account'] # Default is financial account ownership
|
| 223 |
+
)
|
| 224 |
+
|
| 225 |
+
st.markdown(f"### Analysis for Income Quintile {income_quintile}")
|
| 226 |
+
|
| 227 |
+
# Initialize a dictionary to store the summary for income analysis
|
| 228 |
+
income_summary_dict = {}
|
| 229 |
+
|
| 230 |
+
# Loop through selected indicators and create a chart for each
|
| 231 |
+
for indicator in selected_indicators_income:
|
| 232 |
+
# Normalize and calculate the percentage for the selected indicator
|
| 233 |
+
income_indicator_chart = filtered_data_income[indicator].value_counts(normalize=True).mul(100).reset_index()
|
| 234 |
+
income_indicator_chart.columns = [indicator, 'Percentage']
|
| 235 |
+
|
| 236 |
+
# Get the percentage of people with the selected financial indicator
|
| 237 |
+
has_indicator_income = income_indicator_chart[income_indicator_chart[indicator] == 1]['Percentage'].values[0] if 1 in income_indicator_chart[indicator].values else 0
|
| 238 |
+
income_summary_dict[indicator] = has_indicator_income
|
| 239 |
+
|
| 240 |
+
# Create a bar chart for each selected indicator
|
| 241 |
+
fig_income = px.bar(
|
| 242 |
+
income_indicator_chart,
|
| 243 |
+
x=indicator,
|
| 244 |
+
y='Percentage',
|
| 245 |
+
title=f"{indicator.capitalize()} for Income Quintile {income_quintile}",
|
| 246 |
+
labels={indicator: indicator.replace('_', ' ').capitalize()},
|
| 247 |
+
color=indicator,
|
| 248 |
+
color_continuous_scale='Blues'
|
| 249 |
+
)
|
| 250 |
+
|
| 251 |
+
st.plotly_chart(fig_income)
|
| 252 |
+
|
| 253 |
+
# Print out the summary text at the bottom for income analysis
|
| 254 |
+
st.markdown("### Summary")
|
| 255 |
+
for indicator, percentage in income_summary_dict.items():
|
| 256 |
+
st.write(f"**{percentage:.1f}% of respondents in Income Quintile {income_quintile} have {indicator.replace('_', ' ')}**.")
|
| 257 |
+
|
| 258 |
+
|
| 259 |
+
|
| 260 |
+
elif option == "Gender-Based Analysis":
|
| 261 |
+
st.markdown("<h2 style='text-align: center;'>Gender-Based Analysis</h2>", unsafe_allow_html=True)
|
| 262 |
+
st.write("Here can analyze financial behaviors such as savings, borrowing, and digital payments for selected gender and age groups.")
|
| 263 |
+
|
| 264 |
+
# Gender selection
|
| 265 |
+
gender = st.radio("Select Gender:", ("Female", "Male"))
|
| 266 |
+
|
| 267 |
+
# Age group selection (assuming 'age_group' column is already in the dataset)
|
| 268 |
+
age_group = st.selectbox("Select Age Group:", data['age_group'].unique())
|
| 269 |
+
|
| 270 |
+
# Convert gender to appropriate coding (assuming female=1, male=2 in the dataset)
|
| 271 |
+
gender_code = 1 if gender == "Female" else 2
|
| 272 |
+
|
| 273 |
+
# Filter the data based on gender and age group
|
| 274 |
+
filtered_data = data[(data['female'] == gender_code) & (data['age_group'] == age_group)]
|
| 275 |
+
|
| 276 |
+
# Multi-select for financial indicators
|
| 277 |
+
selected_indicators = st.multiselect(
|
| 278 |
+
"Select Financial Indicators to Analyze:",
|
| 279 |
+
['account', 'saved', 'borrowed', 'anydigpayment'],
|
| 280 |
+
default=['account'] # Default is financial account ownership
|
| 281 |
+
)
|
| 282 |
+
|
| 283 |
+
st.markdown(f"### Analysis for {gender}s in {age_group} Age Group")
|
| 284 |
+
|
| 285 |
+
# Initialize a dictionary to store the summary
|
| 286 |
+
summary_dict = {}
|
| 287 |
+
|
| 288 |
+
# Loop through selected indicators and create a chart for each
|
| 289 |
+
for indicator in selected_indicators:
|
| 290 |
+
# Normalize and calculate the percentage for the selected indicator
|
| 291 |
+
indicator_chart = filtered_data[indicator].value_counts(normalize=True).mul(100).reset_index()
|
| 292 |
+
indicator_chart.columns = [indicator, 'Percentage']
|
| 293 |
+
|
| 294 |
+
# Get the percentage of people with the selected financial indicator
|
| 295 |
+
has_indicator = indicator_chart[indicator_chart[indicator] == 1]['Percentage'].values[0] if 1 in indicator_chart[indicator].values else 0
|
| 296 |
+
summary_dict[indicator] = has_indicator
|
| 297 |
+
|
| 298 |
+
# Create a bar chart for each selected indicator
|
| 299 |
+
fig = px.bar(
|
| 300 |
+
indicator_chart,
|
| 301 |
+
x=indicator,
|
| 302 |
+
y='Percentage',
|
| 303 |
+
title=f"{indicator.capitalize()} for {gender}s in {age_group} Age Group",
|
| 304 |
+
labels={indicator: indicator.replace('_', ' ').capitalize()},
|
| 305 |
+
color=indicator,
|
| 306 |
+
color_continuous_scale='Viridis'
|
| 307 |
+
)
|
| 308 |
+
|
| 309 |
+
st.plotly_chart(fig)
|
| 310 |
+
|
| 311 |
+
# Print out the summary text at the bottom
|
| 312 |
+
st.markdown("### Summary")
|
| 313 |
+
for indicator, percentage in summary_dict.items():
|
| 314 |
+
st.write(f"**{percentage:.1f}% of {gender}s in the {age_group} age group have {indicator.replace('_', ' ')}**.")
|
| 315 |
+
|
| 316 |
+
|