armanddemasson commited on
Commit
3f85f96
·
1 Parent(s): e8d5bc9

feat: created plots for talk to ipcc

Browse files
climateqa/engine/talk_to_data/ipcc/plots.py ADDED
@@ -0,0 +1,193 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Callable
2
+ from plotly.graph_objects import Figure
3
+ import plotly.graph_objects as go
4
+ import pandas as pd
5
+ import geojson
6
+
7
+ from climateqa.engine.talk_to_data.ipcc.config import IPCC_INDICATOR_TO_UNIT, IPCC_SCENARIO
8
+ from climateqa.engine.talk_to_data.ipcc.queries import indicator_for_given_year_query, indicator_per_year_at_location_query
9
+ from climateqa.engine.talk_to_data.objects.plot import Plot
10
+
11
+ def plot_indicator_evolution_at_location_historical_and_projections(
12
+ params: dict,
13
+ ) -> Callable[[pd.DataFrame], Figure]:
14
+ """
15
+ Returns a function that generates a line plot showing the evolution of a climate indicator
16
+ (e.g., temperature, rainfall) over time at a specific location, including both historical data
17
+ and future projections for different climate scenarios.
18
+
19
+ Args:
20
+ params (dict): Dictionary with:
21
+ - indicator_column (str): Name of the climate indicator column to plot.
22
+ - location (str): Location (e.g., country, city) for which to plot the indicator.
23
+
24
+ Returns:
25
+ Callable[[pd.DataFrame], Figure]: Function that takes a DataFrame and returns a Plotly Figure
26
+ showing the indicator's evolution over time, with scenario lines and historical data.
27
+ """
28
+ indicator = params["indicator_column"]
29
+ location = params["location"]
30
+ indicator_label = " ".join(word.capitalize() for word in indicator.split("_"))
31
+ unit = IPCC_INDICATOR_TO_UNIT.get(indicator, "")
32
+
33
+ def plot_data(df: pd.DataFrame) -> Figure:
34
+ df = df.sort_values(by='year')
35
+ years = df['year'].astype(int).tolist()
36
+ indicators = df[indicator].astype(float).tolist()
37
+ scenarios = df['scenario'].astype(str).tolist()
38
+
39
+ # Find last historical value for continuity
40
+ last_historical = [(y, v) for y, v, s in zip(years, indicators, scenarios) if s == 'historical']
41
+ last_historical_year, last_historical_indicator = last_historical[-1] if last_historical else (None, None)
42
+
43
+ fig = go.Figure()
44
+ for scenario in IPCC_SCENARIO:
45
+ x = [y for y, s in zip(years, scenarios) if s == scenario]
46
+ y = [v for v, s in zip(indicators, scenarios) if s == scenario]
47
+ # Connect historical to scenario
48
+ if scenario != 'historical' and last_historical_indicator is not None:
49
+ x = [last_historical_year] + x
50
+ y = [last_historical_indicator] + y
51
+ fig.add_trace(go.Scatter(
52
+ x=x,
53
+ y=y,
54
+ mode='lines',
55
+ name=scenario
56
+ ))
57
+
58
+ fig.update_layout(
59
+ title=f'Yearly Evolution of {indicator_label} in {location} (Historical + SSP Scenarios)',
60
+ xaxis_title='Year',
61
+ yaxis_title=f'{indicator_label} ({unit})',
62
+ legend_title='Scenario',
63
+ height=800,
64
+ )
65
+ return fig
66
+
67
+ return plot_data
68
+
69
+ indicator_evolution_at_location_historical_and_projections: Plot = {
70
+ "name": "Indicator Evolution at Location (Historical + Projections)",
71
+ "description": (
72
+ "Shows how a climate indicator (e.g., rainfall, temperature) changes over time at a specific location, "
73
+ "including historical data and future projections. "
74
+ "Useful for questions about the value or trend of an indicator at a location for any year, "
75
+ "such as 'What will be the total rainfall in China in 2050?' or 'How does rainfall evolve in China over time?'. "
76
+ "Parameters: indicator_column (the climate variable), location (e.g., country, city)."
77
+ ),
78
+ "params": ["indicator_column", "location"],
79
+ "plot_function": plot_indicator_evolution_at_location_historical_and_projections,
80
+ "sql_query": indicator_per_year_at_location_query,
81
+ "short_name": "Indicator Evolution"
82
+ }
83
+
84
+ def plot_choropleth_map_of_country_indicator_for_specific_year(
85
+ params: dict,
86
+ ) -> Callable[[pd.DataFrame], Figure]:
87
+ """
88
+ Returns a function that generates a choropleth map (heatmap) showing the spatial distribution
89
+ of a climate indicator (e.g., temperature, rainfall) across all regions of a country for a specific year.
90
+
91
+ Args:
92
+ params (dict): Dictionary with:
93
+ - indicator_column (str): Name of the climate indicator column to plot.
94
+ - year (str or int, optional): Year for which to plot the indicator (default: 2050).
95
+ - country_name (str): Name of the country.
96
+ - location (str): Location (country or region) for the map.
97
+
98
+ Returns:
99
+ Callable[[pd.DataFrame], Figure]: Function that takes a DataFrame and returns a Plotly Figure
100
+ showing the indicator's spatial distribution as a choropleth map for the specified year.
101
+ """
102
+ indicator = params["indicator_column"]
103
+ year = params.get('year', 2050)
104
+ country_name = params['country_name']
105
+ location = params['location']
106
+ indicator_label = " ".join(word.capitalize() for word in indicator.split("_"))
107
+ unit = IPCC_INDICATOR_TO_UNIT.get(indicator, "")
108
+
109
+ def plot_data(df: pd.DataFrame) -> Figure:
110
+ custom_colorscale = [
111
+ [0.0, "rgb(5, 48, 97)"],
112
+ [0.10, "rgb(33, 102, 172)"],
113
+ [0.20, "rgb(67, 147, 195)"],
114
+ [0.30, "rgb(146, 197, 222)"],
115
+ [0.40, "rgb(209, 229, 240)"],
116
+ [0.50, "rgb(247, 247, 247)"],
117
+ [0.60, "rgb(253, 219, 199)"],
118
+ [0.75, "rgb(244, 165, 130)"],
119
+ [0.85, "rgb(214, 96, 77)"],
120
+ [0.90, "rgb(178, 24, 43)"],
121
+ [1.0, "rgb(103, 0, 31)"]
122
+ ]
123
+
124
+ indicators = df[indicator].astype(float).tolist()
125
+ latitudes = df["latitude"].astype(float).tolist()
126
+ longitudes = df["longitude"].astype(float).tolist()
127
+
128
+ features = [
129
+ geojson.Feature(
130
+ geometry=geojson.Polygon([[
131
+ [lon - 0.5, lat - 0.5],
132
+ [lon + 0.5, lat - 0.5],
133
+ [lon + 0.5, lat + 0.5],
134
+ [lon - 0.5, lat + 0.5],
135
+ [lon - 0.5, lat - 0.5]
136
+ ]]),
137
+ properties={"value": val},
138
+ id=str(idx)
139
+ )
140
+ for idx, (lat, lon, val) in enumerate(zip(latitudes, longitudes, indicators))
141
+ ]
142
+
143
+ geojson_data = geojson.FeatureCollection(features)
144
+
145
+ fig = go.Figure(go.Choroplethmapbox(
146
+ geojson=geojson_data,
147
+ locations=[str(i) for i in range(len(indicators))],
148
+ featureidkey="id",
149
+ z=indicators,
150
+ colorscale=custom_colorscale,
151
+ zmin=min(indicators),
152
+ zmax=max(indicators),
153
+ marker_opacity=0.7,
154
+ marker_line_width=0,
155
+ colorbar_title=f"{indicator_label} ({unit})",
156
+ text=[f"{indicator_label}: {value:.2f} {unit}" for value in indicators], # Add hover text showing the indicator value
157
+ hoverinfo="text"
158
+ ))
159
+
160
+ fig.update_layout(
161
+ mapbox_style="open-street-map",
162
+ mapbox_zoom=3,
163
+ height=800,
164
+ mapbox_center={
165
+ "lat": latitudes[len(latitudes)//2] if latitudes else 0,
166
+ "lon": longitudes[len(longitudes)//2] if longitudes else 0
167
+ },
168
+ coloraxis_colorbar=dict(title=f"{indicator_label} ({unit})"),
169
+ title=f"{indicator_label} in {year} in {location} ({country_name})"
170
+ )
171
+ return fig
172
+
173
+ return plot_data
174
+
175
+ choropleth_map_of_country_indicator_for_specific_year: Plot = {
176
+ "name": "Choropleth Map of a Country's Indicator Distribution for a Specific Year",
177
+ "description": (
178
+ "Displays a map showing the spatial distribution of a climate indicator (e.g., rainfall, temperature) "
179
+ "across all regions of a country for a specific year. "
180
+ "Can answer questions about the value of an indicator in a country or region for a given year, "
181
+ "such as 'What will be the total rainfall in China in 2050?' or 'How is rainfall distributed across China in 2050?'. "
182
+ "Parameters: indicator_column (the climate variable), year, location (country name)."
183
+ ),
184
+ "params": ["indicator_column", "year", "location"],
185
+ "plot_function": plot_choropleth_map_of_country_indicator_for_specific_year,
186
+ "sql_query": indicator_for_given_year_query,
187
+ "short_name": "Choropleth Map"
188
+ }
189
+
190
+ IPCC_PLOTS = [
191
+ indicator_evolution_at_location_historical_and_projections,
192
+ choropleth_map_of_country_indicator_for_specific_year
193
+ ]