# Libraries
# ===================================================
import requests
import pandas as pd
import numpy as np
import plotly.graph_objects as go
# Extract Data (Countries)
# ===================================================
# Extract JSON and bring data to a dataframe
url = 'https://raw.githubusercontent.com/guillemmaya92/world_map/main/Dim_Country.json'
response = requests.get(url)
data = response.json()
df = pd.DataFrame(data)
df = pd.DataFrame.from_dict(data, orient='index').reset_index()
df_countries = df.rename(columns={'index': 'ISO3'})
# Extract Data (WID)
# ===================================================
# URL del archivo Parquet en GitHub
url = "https://raw.githubusercontent.com/guillemmaya92/Analytics/master/Data/WID_Values.parquet"
df = pd.read_parquet(url, engine="pyarrow")
df = df[df['year'].isin([1980, 2023])]
# Transform Data
# ===================================================
df['tincome'] = df['tincome2'] / df['xusd'] / 1000
df['twealth'] = df['twealth2'] / df['xusd'] / 1000
df['gdptotal'] = df['gdptotal'] / df['xusd']
df['tincomeVAR'] = (df['tincome'] / df.groupby('country')['tincome'].shift(1) -1) * 100
df['twealthVAR'] = (df['twealth'] / df.groupby('country')['twealth'].shift(1) -1) * 100
df['wiratioVAR'] = (df['wiratio'] - df.groupby('country')['wiratio'].shift(1))
df = df[df['year'] == 2023]
df = df[df['wiratio'].notna() & df['tincome'].notna()]
df = pd.merge(df, df_countries, left_on='country', right_on='ISO2', how='inner')
df = df[['year', 'country', 'Country_Abr', 'gdptotal', 'tincome', 'twealth', 'wiratio', 'tincomeVAR', 'twealthVAR', 'wiratioVAR']]
df = df[(df['tincome'] >= 0) & (df['tincome'] <= 120000)]
df = df.sort_values(by='gdptotal', ascending=True)
df = df.rename(
columns={
'year': 'year',
'Country_Abr': 'country_name',
'gdptotal': 'total_income',
'tincome': 'incomeCY',
'twealth': 'wealthCY',
'wiratio': 'betaCY',
'tincomeVAR': 'incomeVAR',
'twealthVAR': 'wealthVAR',
'wiratioVAR': 'betaVAR'
}
)
print(df)
# Data Visualization
# ===================================================
# Crea la figura
fig = go.Figure()
# Marker size y line width calculados
marker_size = np.sqrt(df["total_income"] / df["total_income"].max()) * 100 + 3
line_width = np.sqrt(df["total_income"] / df["total_income"].max()) * 4 + 0.5
# Primero agregamos los puntos del scatter
fig.add_trace(go.Scatter(
x=df["betaCY"],
y=df["incomeCY"],
mode='markers',
text=df["country_name"],
customdata=np.vstack((df["incomeCY"], df["wealthCY"], df["incomeVAR"], df["wealthVAR"], df["betaCY"], df["betaVAR"])).T,
marker=dict(
size=marker_size,
color="rgba(0,0,0,0)",
line=dict(
width=line_width,
color='black'
)
),
hovertemplate="<b>Country:</b> %{text}<br>" +
"<b>Income Avg ($):</b> %{y:.0f}k | <b>Var. 1980:</b> %{customdata[2]:.2f}%<br>" +
"<b>Wealth Avg ($):</b> %{customdata[1]:.0f}k | <b>Var. 1980:</b> %{customdata[3]:.2f}%<br>" +
"<b>Ratio:</b> %{customdata[4]:.2f} | <b>Var. 1980:</b> %{customdata[5]:.2f}pp<extra></extra>",
showlegend=False
))
# Ahora agregamos las imágenes de las banderas
for i, row in df.iterrows():
country_iso = row["country"]
# Calcular tamaño de la imagen
image_size = marker_size[i] * 0.205
# Añadir la imagen de la bandera, asegurándose de que el orden es correcto
fig.add_layout_image(
dict(
source=f"https://raw.githubusercontent.com/guillemmaya92/world_flags_round/refs/heads/master/flags/{country_iso}.png",
xref="x",
yref="y",
xanchor="center",
yanchor="middle",
x=row["betaCY"],
y=row["incomeCY"],
sizex=image_size,
sizey=image_size,
sizing="contain",
opacity=0.8
)
)
# Add red and green shapes
fig.add_shape(
type="rect",
xref="x", yref="paper",
x0=0, x1=6,
y0=0, y1=1,
fillcolor="green",
opacity=0.04,
layer="below",
line_width=0
)
fig.add_shape(
type="rect",
xref="x", yref="paper",
x0=6, x1=12,
y0=0, y1=1,
fillcolor="red",
opacity=0.04,
layer="below",
line_width=0
)
# Configuration plot
fig.update_layout(
title="<b>Wealth-Income Ratio</b>",
title_x=0.11,
title_y=0.93,
title_font=dict(size=16),
annotations=[
dict(
text="Global Patterns in Wealth-Income Ratios and Average Income per Capita",
xref="paper",
yref="paper",
x=0,
y=1.06,
showarrow=False,
font=dict(size=11)
),
dict(
text="<b>Data Source:</b> World Inequality Database (WID)",
xref="paper",
yref="paper",
x=0,
y=-0.12,
showarrow=False,
font=dict(size=10),
align="left"
),
dict(
text=f"<b>Currency:</b> Official exchange rate {df["year"].max()} of the local currency to USD.",
xref="paper",
yref="paper",
x=0,
y=-0.14,
showarrow=False,
font=dict(size=10),
align="left"
),
dict(
text=f"<i>@guillemmaya</i>",
xref="paper",
yref="paper",
x=1,
y=-0.14,
showarrow=False,
font=dict(size=11),
align="right"
),
dict(
text=str(df["year"].max()),
xref="paper",
yref="paper",
x=1,
y=1.08,
showarrow=False,
font=dict(size=22, color='lightgray', weight='bold'),
align="right"
)
],
xaxis=dict(
title="<b>Wealth-Income Ratio</b>",
range=[0, 12],
tickvals=[i * 4 / 2 for i in range(7)],
ticktext=[f"{int(i * 4 / 2)}" for i in range(7)],
showline=True,
linewidth=1,
linecolor="black",
gridcolor="#ebebeb"
),
yaxis=dict(
title="<b>Average Income per Capita ($US)</b>",
range=[0, 120],
tickvals=[i * 120 / 6 for i in range(7)],
ticktext=[f"{int(i * 120 / 6)}k" for i in range(7)],
showline=True,
linewidth=1,
linecolor="black",
gridcolor="#ebebeb"
),
height=750,
width=750,
plot_bgcolor="white",
paper_bgcolor="white"
)
# Add a custom legend
size_legend = ['Smaller', 'Middle', 'Bigger']
size_values = [5, 10, 20]
for label, size in zip(size_legend, size_values):
fig.add_trace(go.Scatter(
x=[None],
y=[None],
mode='markers',
marker=dict(
size=size,
color="rgba(0,0,0,0)",
line=dict(
width=1,
color='black'
)
),
legendgroup='size',
showlegend=True,
name=f'{label}'
))
fig.update_layout(
legend=dict(
title=dict(text='<b> Total Income</b>'),
font=dict(size=11),
x=0.025,
y=0.95,
xanchor='left',
bgcolor='white',
bordercolor='black',
borderwidth=1
)
)
# Save as HTML file!
fig.write_html("C:/Users/guill/Desktop/FIG_WID_CapitalisBack_Flag.html")
fig.write_image("C:/Users/guill/Desktop/FIG_WID_CapitalisBack_Flag.png")
# Show the plot!
fig.show()