Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
.venv/
__pycache__/
.DS_Storegit
.DS_Storegit
.DS_Store

# Virtual environment
venv/
env/
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,34 @@
## Introduction
This repository contains the scripts and results used in the **Geographical Decentralization in Blockchains** paper.


Run the below command before use
```bash
export PYTHONPATH="/Users/namangarg/code/geo-analysis:$PYTHONPATH"
```

## Setting up the Virtual Environment

To set up a virtual environment and install the required dependencies, follow these steps:

1. Create a virtual environment:
```bash
python3 -m venv venv
```

2. Activate the virtual environment:
- On macOS and Linux:
```bash
source venv/bin/activate
```
- On Windows:
```bash
.\venv\Scripts\activate
```

3. Install the required packages:
```bash
pip install -r requirements.txt
```

Now your virtual environment is set up and the necessary packages are installed.
85 changes: 85 additions & 0 deletions analysis/results_tests/gini_improvement.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import numpy as np
import pandas as pd


def compute_gini_improvement(gini_file_path, output_folder="results"):
"""
Compute Gini improvement percentages per blockchain and overall averages.

:param gini_file_path: Path to the CSV file containing Gini coefficients.
:param output_folder: Folder to save the results.
"""
# Load the Gini coefficient file
gini_df = pd.read_csv(gini_file_path)

# Define old and new Gini columns
old_columns = ["stake_weight"] # Old Gini column (Run 1)
new_columns = [
"stake_weight",
"0.8linear_weight",
"0.6linear_weight",
"0.4linear_weight",
"0.2linear_weight",
"0linear_weight",
]

# Extract old Gini values (Run 1)
old_gini_df = gini_df[["file"] + old_columns].copy()

# Extract new Gini values (Runs 1, 3, 5, 7, 8, 9)
new_gini_df = gini_df[["file"] + new_columns].copy()

# Initialize a list to store average improvement percentages per blockchain
gini_improvement_averages = []

# Calculate improvement percentage for each blockchain
for idx, blockchain in enumerate(old_gini_df["file"]):
# Extract old and new Gini values for the blockchain
old_gini_value = old_gini_df.loc[idx, "stake_weight"]
new_gini_values = new_gini_df.loc[idx, new_columns].values[1:] # Exclude the first value (Run 1)

# Compute improvement percentages: (new Gini - old Gini) / old Gini
improvement_percentages = (old_gini_value - new_gini_values) / old_gini_value

# Take the average improvement percentage across all lambda values
average_improvement = np.mean(improvement_percentages)

# Append the average improvement percentage for the blockchain
gini_improvement_averages.append(average_improvement)

# Calculate the range of the averages
gini_improvement_range = np.max(gini_improvement_averages) - np.min(gini_improvement_averages)

# Calculate the overall average improvement percentage across all blockchains
overall_average_improvement = np.mean(gini_improvement_averages)

# Prepare the result DataFrame
result_df = pd.DataFrame({"file": old_gini_df["file"], "average_improvement": gini_improvement_averages})

# Save the results
result_file_path = f"{output_folder}/gini_improvement_results.csv"
result_df.to_csv(result_file_path, index=False)
print(f"Results saved to {result_file_path}")

# Print the results
print("Gini Improvement Percentages per Blockchain:")
print(result_df)
print("\nRange of Gini Improvement Percentages:", gini_improvement_range)
print("Overall Average Gini Improvement Percentage:", overall_average_improvement)

return result_df, gini_improvement_range, overall_average_improvement


# Usage Example
if __name__ == "__main__":
# Path to the Gini coefficient file
gini_file_path = "results/centrality_measures_wc.csv" # Replace with your file path
output_folder = "results" # Folder to save the outputs

# Create the output folder if it doesn't exist
import os

os.makedirs(output_folder, exist_ok=True)

# Compute Gini improvements
compute_gini_improvement(gini_file_path, output_folder)
90 changes: 50 additions & 40 deletions analysis/results_tests/plot_gini_centrality_wc.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,47 @@
import pandas as pd
import os

import matplotlib.pyplot as plt
import numpy as np
import os
import pandas as pd

# Enable LaTeX and set fonts for better formatting
plt.rcParams['text.usetex'] = True
plt.rcParams['font.family'] = 'serif'
plt.rcParams['font.serif'] = ['Times New Roman'] # LNCS compatible font
plt.rcParams['axes.titlesize'] = 12 # Title size
plt.rcParams['axes.labelsize'] = 10 # Axis labels size
plt.rcParams['xtick.labelsize'] = 20 # X-tick size
plt.rcParams['ytick.labelsize'] = 20 # Y-tick size
plt.rcParams['legend.fontsize'] = 10 # Legend font size
plt.rcParams['figure.titlesize'] = 12 # Figure title size
plt.rcParams["text.usetex"] = True
plt.rcParams["font.family"] = "serif"
plt.rcParams["font.serif"] = ["Times New Roman"] # LNCS compatible font
plt.rcParams["axes.titlesize"] = 12 # Title size
plt.rcParams["axes.labelsize"] = 10 # Axis labels size
plt.rcParams["xtick.labelsize"] = 20 # X-tick size
plt.rcParams["ytick.labelsize"] = 20 # Y-tick size
plt.rcParams["legend.fontsize"] = 10 # Legend font size
plt.rcParams["figure.titlesize"] = 12 # Figure title size

# Read the data from the CSV file
df = pd.read_csv('results/centrality_measures_wc.csv')
df = pd.read_csv("results/centrality_measures_wc.csv")

# Sort the DataFrame alphabetically by the 'file' column
df = df.sort_values(by='file')
df = df.sort_values(by="file")

# Define the chains and weights to plot
chains = df["file"].str.capitalize().replace({"ethernodes": "Ethereum Nodes"}) # Capitalize and replace
weights = {
"stake_weight": r"$\lambda = 1$ (PoS)",
"0.8linear_weight": r"$\lambda = 0.8$",
"0.6linear_weight": r"$\lambda = 0.6$",
"0.4linear_weight": r"$\lambda = 0.4$",
"0.2linear_weight": r"$\lambda = 0.2$",
"0linear_weight": r"$\lambda = 0$",
}

# Define the chains and the weights to plot
chains = df['file'].str.capitalize().replace({'ethernodes': 'Ethereum Nodes'}) # Capitalize and replace
weights = ['stake_weight', '0.9linear_weight', '0.8linear_weight', '0.7linear_weight', '0.6linear_weight', '0.5linear_weight']
# Filter DataFrame for the desired runs (1, 3, 5, 7, 8, 9)
selected_runs = {
"stake_weight": 1, # Run 1
"0.8linear_weight": 3, # Run 3
"0.6linear_weight": 5, # Run 5
"0.4linear_weight": 7, # Run 7
"0.2linear_weight": 8, # Run 8
"0linear_weight": 9, # Run 9
}
df_filtered = df[[weight for weight in selected_runs.keys()] + ["file"]]

# Set up the bar plot
x = np.arange(len(chains)) # Label locations
Expand All @@ -31,52 +50,43 @@
fig, ax = plt.subplots(figsize=(12, 8))

# Define a more professional, muted color palette
colors = ['#4E79A7', '#F28E2B', '#59A14F', '#EDC948', '#B07AA1', '#76B7B2']

# Map each weight to the corresponding label with the lambda symbol
weight_labels = {
'stake_weight': r'$\lambda = 1 (PoS)$',
'0.9linear_weight': r'$\lambda = 0.9$',
'0.8linear_weight': r'$\lambda = 0.8$',
'0.7linear_weight': r'$\lambda = 0.7$',
'0.6linear_weight': r'$\lambda = 0.6$',
'0.5linear_weight': r'$\lambda = 0.5$'
}
colors = ["#4E79A7", "#F28E2B", "#59A14F", "#EDC948", "#B07AA1", "#76B7B2"]

# Plot each weight's Gini coefficient as a bar with distinct muted colors
for i, weight in enumerate(weights):
ax.bar(x + i * width, df[weight], width, label=weight_labels[weight], color=colors[i])
for i, (weight, label) in enumerate(weights.items()):
ax.bar(x + i * width, df_filtered[weight], width, label=label, color=colors[i])

# Add labels and title
ax.set_ylabel('Gini Coefficient of Eigenvector Centrality Scores', fontsize=20) # Set Y-label fontsize to 20
ax.set_ylabel("Gini Coefficient of Eigenvector Centrality Scores", fontsize=20) # Set Y-label fontsize to 20
ax.set_xticks(x + width * 2.5) # Adjust x-ticks to center
ax.set_xticklabels(chains, fontsize=20)

# Set Y-ticks font size
plt.yticks(fontsize=20)

# Place legend inside the plot area
ax.legend(title='Configuration', loc='upper right', fontsize=20, title_fontsize=24)
ax.legend(title="Configuration", loc="upper right", fontsize=20, title_fontsize=24)

# Plot trendlines for each chain to show the evolution of Gini coefficients across lambda values
for i, chain in enumerate(chains):
# Extract Gini values for this chain
gini_values = df.loc[df['file'] == chain.lower(), weights].values.flatten() # Use lower case for matching

gini_values = df_filtered.loc[
df["file"] == chain.lower(), weights.keys()
].values.flatten() # Use lower case for matching

# Calculate x-coordinates for trendlines (centered across the bars for this chain)
trendline_x = x[i] + np.linspace(0, width * (len(weights) - 1), len(weights))

# Fit a line (linear regression) to show trend and plot it
z = np.polyfit(trendline_x, gini_values, 1)
p = np.poly1d(z)
ax.plot(trendline_x, p(trendline_x), linestyle='--', color='grey', linewidth=1, alpha=0.7)
ax.plot(trendline_x, p(trendline_x), linestyle="--", color="grey", linewidth=1, alpha=0.7)

# Show grid and tight layout
plt.grid(True, which='both', linestyle='--', linewidth=0.5, alpha=0.7)
plt.grid(True, which="both", linestyle="--", linewidth=0.5, alpha=0.7)
plt.tight_layout()


# Save the plot
plot_file_path = os.path.join('results/', f'centrality_measures_wc_gini.pdf') # Save as PDF
plt.savefig(plot_file_path, format='pdf', dpi=300, transparent=True)
plt.close() # Close the plot to free memory
plot_file_path = os.path.join("results/", f"centrality_measures_wc_gini_filtered.pdf") # Save as PDF
plt.savefig(plot_file_path, format="pdf", dpi=300, transparent=True)
plt.close() # Close the plot to free memory
Loading