diff --git a/policyengine/charts/poverty/__init__.py b/policyengine/charts/poverty/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/policyengine/charts/poverty/deep/__init__.py b/policyengine/charts/poverty/deep/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/policyengine/charts/poverty/deep/by_age.py b/policyengine/charts/poverty/deep/by_age.py
new file mode 100644
index 0000000..fabe5c6
--- /dev/null
+++ b/policyengine/charts/poverty/deep/by_age.py
@@ -0,0 +1,107 @@
+import plotly.graph_objects as go
+from policyengine_core.charts.formatting import *
+
+class DeepPovertyByAgeChart:
+ def __init__(self,country:str, data=None):
+ if data is None:
+ raise ValueError("Data must be provided")
+
+ self.data = data
+
+ def _get_color(self, value):
+ # All bars should be gray
+ return GRAY
+
+ def _get_change_direction(self, value):
+ if value > 0:
+ return "increase"
+ elif value < 0:
+ return "decrease"
+ else:
+ return "no change"
+
+ def ordinal_suffix(self, n):
+ """Return the ordinal suffix for an integer."""
+ if 10 <= n % 100 <= 20:
+ suffix = 'th'
+ else:
+ suffix = {1: 'st', 2: 'nd', 3: 'rd'}.get(n % 10, 'th')
+ return suffix
+
+ def generate_chart_data(self):
+ categories = list(self.data.keys())
+ values = [self.data[cat]['change'] for cat in categories]
+ baselines = [self.data[cat]['baseline'] * 100 for cat in categories]
+ reforms = [self.data[cat]['reform'] * 100 for cat in categories]
+
+ # Generate hover texts with baseline, reform, and percentage change
+ hover_texts = [
+ f"This reform would {self._get_change_direction(val)} the percentage of {category.lower()} in poverty by {abs(val):.1f}% from {baseline:.1f}% to {reform:.1f}%"
+ for category, val, baseline, reform in zip(categories, values, baselines, reforms)
+ ]
+
+ fig = go.Figure()
+
+ values_in_pct = values # Use percentage values
+ colors = [self._get_color(value) for value in values]
+
+ # Add bar chart with percentage values
+ fig.add_trace(go.Bar(
+ x=categories,
+ y=values_in_pct,
+ marker=dict(color=colors, line=dict(width=1)),
+ width=0.6,
+ text=[f"{abs(value):.1f}%" for value in values], # Display values as percentages
+ textposition='outside',
+ hovertemplate="%{x}
%{customdata}", # Hover shows category
+ customdata=hover_texts
+ ))
+
+ # Update layout to reflect percentage values on y-axis
+ fig.update_layout(
+ yaxis=dict(
+ tickformat=",.1f%%", # Format y-axis as percentages with one decimal place
+ title="Percentage Change in Poverty"
+ ),
+ xaxis=dict(
+ title="Category"
+ ),
+ hoverlabel=dict(
+ bgcolor="white",
+ font=dict(color="black", size=16)
+ ),
+ title="Change in Poverty Percentage by Category"
+ )
+
+ format_fig(fig) # Keep the formatting logic from policyengine_core
+ return fig
+
+
+# # Example data
+# data = {
+# 'Child': {
+# 'Baseline': 0.32427219591395395,
+# 'Reform': 0.33392168532001054,
+# 'Change': 3.0
+# },
+# 'Adult': {
+# 'Baseline': 0.17427822561729264,
+# 'Reform': 0.17757158627182623,
+# 'Change': 1.9
+# },
+# 'Senior': {
+# 'Baseline': 0.12817646500651358,
+# 'Reform': 0.1370685860340031,
+# 'Change': 6.9
+# },
+# 'All': {
+# 'Baseline': 0.19913534734369268,
+# 'Reform': 0.20487670454940832,
+# 'Change': 2.9
+# }
+# }
+
+# # Generate chart for all categories
+# chart = OverallChart(data=data)
+# fig = chart.generate_chart_data()
+# fig.show()
diff --git a/policyengine/charts/poverty/deep/by_gender.py b/policyengine/charts/poverty/deep/by_gender.py
new file mode 100644
index 0000000..40e1a61
--- /dev/null
+++ b/policyengine/charts/poverty/deep/by_gender.py
@@ -0,0 +1,103 @@
+import plotly.graph_objects as go
+from policyengine_core.charts.formatting import *
+
+class DeepPovertyByGenderChart:
+ def __init__(self, country:str,data=None):
+ if data is None:
+ raise ValueError("Data must be provided")
+
+ self.data = data
+
+ def _get_color(self, value):
+ # All bars should be gray
+ return GRAY
+
+ def _get_change_direction(self, value):
+ if value > 0:
+ return "increase"
+ elif value < 0:
+ return "decrease"
+ else:
+ return "no change"
+
+ def ordinal_suffix(self, n):
+ """Return the ordinal suffix for an integer."""
+ if 10 <= n % 100 <= 20:
+ suffix = 'th'
+ else:
+ suffix = {1: 'st', 2: 'nd', 3: 'rd'}.get(n % 10, 'th')
+ return suffix
+
+ def generate_chart_data(self):
+ categories = list(self.data.keys())
+ values = [self.data[cat]['change'] for cat in categories]
+ baselines = [self.data[cat]['baseline'] * 100 for cat in categories]
+ reforms = [self.data[cat]['reform'] * 100 for cat in categories]
+
+ # Generate hover texts with baseline, reform, and percentage change
+ hover_texts = [
+ f"This reform would {self._get_change_direction(val)} the percentage of {category.lower()} in poverty by {abs(val):.1f}% from {baseline:.1f}% to {reform:.1f}%"
+ for category, val, baseline, reform in zip(categories, values, baselines, reforms)
+ ]
+
+ fig = go.Figure()
+
+ values_in_pct = values # Use percentage values
+ colors = [self._get_color(value) for value in values]
+
+ # Add bar chart with percentage values
+ fig.add_trace(go.Bar(
+ x=categories,
+ y=values_in_pct,
+ marker=dict(color=colors, line=dict(width=1)),
+ width=0.6,
+ text=[f"{abs(value):.1f}%" for value in values], # Display values as percentages
+ textposition='outside',
+ hovertemplate="Category %{x}
%{customdata}", # Hover shows category
+ customdata=hover_texts
+ ))
+
+ # Update layout to reflect percentage values on y-axis
+ fig.update_layout(
+ yaxis=dict(
+ tickformat=",.1f%%",
+ ticksuffix = "%", # Format y-axis as percentages with one decimal place
+ title="Percentage Change in Poverty"
+ ),
+ xaxis=dict(
+ title="Category"
+ ),
+ hoverlabel=dict(
+ bgcolor="white",
+ font=dict(color="black", size=16)
+ ),
+ title="Change in Poverty Percentage by Category"
+ )
+
+ format_fig(fig) # Keep the formatting logic from policyengine_core
+ return fig
+
+
+# # Example data
+# data = {
+# 'Male': {
+# 'Baseline': 0.18412623468617267,
+# 'Reform': 0.18932591339284738,
+# 'Change': 2.8
+# },
+# 'Female': {
+# 'Baseline': 0.21377616483057263,
+# 'Reform': 0.22004590877186603,
+# 'Change': 2.9
+# },
+# 'All': {
+# 'Baseline': 0.19913534734369268,
+# 'Reform': 0.20487670454940832,
+# 'Change': 2.9
+# }
+# }
+
+# # Generate chart for all categories
+# chart = OverallChart(data=data)
+# fig = chart.generate_chart_data()
+# fig.show()
diff --git a/policyengine/charts/poverty/regular/__init__.py b/policyengine/charts/poverty/regular/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/policyengine/charts/poverty/regular/by_age.py b/policyengine/charts/poverty/regular/by_age.py
new file mode 100644
index 0000000..e60333b
--- /dev/null
+++ b/policyengine/charts/poverty/regular/by_age.py
@@ -0,0 +1,107 @@
+import plotly.graph_objects as go
+from policyengine_core.charts.formatting import *
+
+class RegularPovertyByAgeChart:
+ def __init__(self,country:str, data=None):
+ if data is None:
+ raise ValueError("Data must be provided")
+
+ self.data = data
+
+ def _get_color(self, value):
+ # All bars should be gray
+ return GRAY
+
+ def _get_change_direction(self, value):
+ if value > 0:
+ return "increase"
+ elif value < 0:
+ return "decrease"
+ else:
+ return "no change"
+
+ def ordinal_suffix(self, n):
+ """Return the ordinal suffix for an integer."""
+ if 10 <= n % 100 <= 20:
+ suffix = 'th'
+ else:
+ suffix = {1: 'st', 2: 'nd', 3: 'rd'}.get(n % 10, 'th')
+ return suffix
+
+ def generate_chart_data(self):
+ categories = list(self.data.keys())
+ values = [self.data[cat]['change'] for cat in categories]
+ baselines = [self.data[cat]['baseline'] * 100 for cat in categories]
+ reforms = [self.data[cat]['reform'] * 100 for cat in categories]
+
+ # Generate hover texts with baseline, reform, and percentage change
+ hover_texts = [
+ f"This reform would {self._get_change_direction(val)} the percentage of {category.lower()} in poverty by {abs(val):.1f}% from {baseline:.1f}% to {reform:.1f}%"
+ for category, val, baseline, reform in zip(categories, values, baselines, reforms)
+ ]
+
+ fig = go.Figure()
+
+ values_in_pct = values # Use percentage values
+ colors = [self._get_color(value) for value in values]
+
+ # Add bar chart with percentage values
+ fig.add_trace(go.Bar(
+ x=categories,
+ y=values_in_pct,
+ marker=dict(color=colors, line=dict(width=1)),
+ width=0.6,
+ text=[f"{abs(value):.1f}%" for value in values], # Display values as percentages
+ textposition='outside',
+ hovertemplate="%{x}
%{customdata}", # Hover shows category
+ customdata=hover_texts
+ ))
+
+ # Update layout to reflect percentage values on y-axis
+ fig.update_layout(
+ yaxis=dict(
+ tickformat=",.1f%%", # Format y-axis as percentages with one decimal place
+ title="Percentage Change in Poverty"
+ ),
+ xaxis=dict(
+ title="Category"
+ ),
+ hoverlabel=dict(
+ bgcolor="white",
+ font=dict(color="black", size=16)
+ ),
+ title="Change in Poverty Percentage by Category"
+ )
+
+ format_fig(fig) # Keep the formatting logic from policyengine_core
+ return fig
+
+
+# # Example data
+# data = {
+# 'Child': {
+# 'Baseline': 0.32427219591395395,
+# 'Reform': 0.33392168532001054,
+# 'Change': 3.0
+# },
+# 'Adult': {
+# 'Baseline': 0.17427822561729264,
+# 'Reform': 0.17757158627182623,
+# 'Change': 1.9
+# },
+# 'Senior': {
+# 'Baseline': 0.12817646500651358,
+# 'Reform': 0.1370685860340031,
+# 'Change': 6.9
+# },
+# 'All': {
+# 'Baseline': 0.19913534734369268,
+# 'Reform': 0.20487670454940832,
+# 'Change': 2.9
+# }
+# }
+
+# # Generate chart for all categories
+# chart = OverallChart(data=data)
+# fig = chart.generate_chart_data()
+# fig.show()
diff --git a/policyengine/charts/poverty/regular/by_gender.py b/policyengine/charts/poverty/regular/by_gender.py
new file mode 100644
index 0000000..a393c25
--- /dev/null
+++ b/policyengine/charts/poverty/regular/by_gender.py
@@ -0,0 +1,103 @@
+import plotly.graph_objects as go
+from policyengine_core.charts.formatting import *
+
+class RegularPovertyByGenderChart:
+ def __init__(self, country:str,data=None):
+ if data is None:
+ raise ValueError("Data must be provided")
+
+ self.data = data
+
+ def _get_color(self, value):
+ # All bars should be gray
+ return GRAY
+
+ def _get_change_direction(self, value):
+ if value > 0:
+ return "increase"
+ elif value < 0:
+ return "decrease"
+ else:
+ return "no change"
+
+ def ordinal_suffix(self, n):
+ """Return the ordinal suffix for an integer."""
+ if 10 <= n % 100 <= 20:
+ suffix = 'th'
+ else:
+ suffix = {1: 'st', 2: 'nd', 3: 'rd'}.get(n % 10, 'th')
+ return suffix
+
+ def generate_chart_data(self):
+ categories = list(self.data.keys())
+ values = [self.data[cat]['change'] for cat in categories]
+ baselines = [self.data[cat]['baseline'] * 100 for cat in categories]
+ reforms = [self.data[cat]['reform'] * 100 for cat in categories]
+
+ # Generate hover texts with baseline, reform, and percentage change
+ hover_texts = [
+ f"This reform would {self._get_change_direction(val)} the percentage of {category.lower()} in poverty by {abs(val):.1f}% from {baseline:.1f}% to {reform:.1f}%"
+ for category, val, baseline, reform in zip(categories, values, baselines, reforms)
+ ]
+
+ fig = go.Figure()
+
+ values_in_pct = values # Use percentage values
+ colors = [self._get_color(value) for value in values]
+
+ # Add bar chart with percentage values
+ fig.add_trace(go.Bar(
+ x=categories,
+ y=values_in_pct,
+ marker=dict(color=colors, line=dict(width=1)),
+ width=0.6,
+ text=[f"{abs(value):.1f}%" for value in values], # Display values as percentages
+ textposition='outside',
+ hovertemplate="Category %{x}
%{customdata}", # Hover shows category
+ customdata=hover_texts
+ ))
+
+ # Update layout to reflect percentage values on y-axis
+ fig.update_layout(
+ yaxis=dict(
+ tickformat=",.1f%%",
+ ticksuffix = "%", # Format y-axis as percentages with one decimal place
+ title="Percentage Change in Poverty"
+ ),
+ xaxis=dict(
+ title="Category"
+ ),
+ hoverlabel=dict(
+ bgcolor="white",
+ font=dict(color="black", size=16)
+ ),
+ title="Change in Poverty Percentage by Category"
+ )
+
+ format_fig(fig) # Keep the formatting logic from policyengine_core
+ return fig
+
+
+# # Example data
+# data = {
+# 'Male': {
+# 'Baseline': 0.18412623468617267,
+# 'Reform': 0.18932591339284738,
+# 'Change': 2.8
+# },
+# 'Female': {
+# 'Baseline': 0.21377616483057263,
+# 'Reform': 0.22004590877186603,
+# 'Change': 2.9
+# },
+# 'All': {
+# 'Baseline': 0.19913534734369268,
+# 'Reform': 0.20487670454940832,
+# 'Change': 2.9
+# }
+# }
+
+# # Generate chart for all categories
+# chart = OverallChart(data=data)
+# fig = chart.generate_chart_data()
+# fig.show()
diff --git a/policyengine/economic_impact/economic_impact.py b/policyengine/economic_impact/economic_impact.py
index c913e96..49b914b 100644
--- a/policyengine/economic_impact/economic_impact.py
+++ b/policyengine/economic_impact/economic_impact.py
@@ -79,6 +79,10 @@
from typing import Dict, Type, Union
from policyengine.charts.inequality import InequalityImpactChart
+from policyengine.charts.poverty.regular.by_age import RegularPovertyByAgeChart
+from policyengine.charts.poverty.deep.by_age import DeepPovertyByAgeChart
+from policyengine.charts.poverty.regular.by_gender import RegularPovertyByGenderChart
+from policyengine.charts.poverty.deep.by_gender import DeepPovertyByGenderChart
class EconomicImpact:
@@ -176,6 +180,10 @@ def __init__(self, reform: dict, country: str, dataset: str = None) -> None:
self.chart_generators: Dict[str, Type] = {
"inequality": InequalityImpactChart,
+ "poverty/regular/by_age": RegularPovertyByAgeChart,
+ "poverty/regular/by_gender": RegularPovertyByGenderChart,
+ "poverty/deep/by_age": DeepPovertyByAgeChart,
+ "poverty/deep/by_gender": DeepPovertyByGenderChart,
}
self.composite_metrics: Dict[str, Dict[str, str]] = {
@@ -183,6 +191,28 @@ def __init__(self, reform: dict, country: str, dataset: str = None) -> None:
"Gini index": "inequality/gini",
"Top 1% share": "inequality/top_1_pct_share",
"Top 10% share": "inequality/top_10_pct_share",
+ },
+ "poverty/regular/by_age": {
+ "Child": "poverty/regular/child",
+ "Adult": "poverty/regular/adult",
+ "Senior":"poverty/regular/senior",
+ "All": "poverty/regular/age/all"
+ },
+ "poverty/regular/by_gender": {
+ "Male": "poverty/regular/male",
+ "Female": "poverty/regular/female",
+ "All": "poverty/regular/gender/all"
+ },
+ "poverty/deep/by_age": {
+ "Child": "poverty/deep/child",
+ "Adult": "poverty/deep/adult",
+ "Senior":"poverty/deep/senior",
+ "All": "poverty/deep/age/all"
+ },
+ "poverty/deep/by_gender": {
+ "Male": "poverty/deep/male",
+ "Female": "poverty/deep/female",
+ "All": "poverty/deep/gender/all"
}
}
@@ -250,7 +280,7 @@ def chart(self, metric: str) -> dict:
if not chart_generator:
raise ValueError(f"No chart generator found for metric: {metric}")
- return chart_generator(data=data).generate_chart_data()
+ return chart_generator(self.country,data=data).generate_chart_data()
def add_metric(self, metric: str, calculator: object, chart_generator: Type = None):
self.metric_calculators[metric] = calculator