ouhenio commited on
Commit
e872da8
·
verified ·
1 Parent(s): db58fdb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +222 -110
app.py CHANGED
@@ -1,153 +1,265 @@
1
  import gradio as gr
2
  import random
 
3
  import fastapi
4
  from fastapi import FastAPI
5
 
6
  # Create a FastAPI app
7
  app = FastAPI()
8
 
9
- # Sample data for the plot
10
  def generate_data():
11
- return [
12
- {"name": "Argentina", "value": random.randint(10, 90)},
13
- {"name": "Brazil", "value": random.randint(10, 90)},
14
- {"name": "Chile", "value": random.randint(10, 90)},
15
- {"name": "Colombia", "value": random.randint(10, 90)},
16
- {"name": "Mexico", "value": random.randint(10, 90)},
17
- {"name": "Peru", "value": random.randint(10, 90)},
18
- {"name": "Spain", "value": random.randint(10, 90)},
19
- {"name": "Venezuela", "value": random.randint(10, 90)}
20
- ]
 
 
 
 
 
 
 
 
 
 
 
 
21
 
22
- # Route to serve a D3.js bar chart
23
- @app.get("/d3-plot")
24
- async def serve_plot():
25
- # Generate random data for the plot
26
- data = generate_data()
27
 
28
- # Convert the data to a JavaScript string
29
- data_str = str(data).replace("'", '"')
30
 
31
  html_content = f"""
32
  <!DOCTYPE html>
33
  <html>
34
  <head>
35
  <meta charset="utf-8">
36
- <title>D3.js Simple Plot</title>
37
  <script src="https://d3js.org/d3.v7.min.js"></script>
38
  <style>
39
  body {{
40
- font-family: sans-serif;
41
  padding: 20px;
42
  background-color: #111;
43
  color: #fff;
 
44
  }}
45
- .bar {{
46
- fill: #f32b7b;
47
- transition: fill 0.3s;
48
- }}
49
- .bar:hover {{
50
- fill: #4a1942;
51
- }}
52
- .axis text {{
53
- fill: #ccc;
54
  }}
55
- .axis path,
56
- .axis line {{
57
- stroke: #666;
 
58
  }}
59
- .axis-title {{
60
- fill: #fff;
 
 
 
 
61
  font-size: 12px;
 
 
 
 
 
62
  }}
63
  </style>
64
  </head>
65
  <body>
66
- <h1>Latin America & Spain Progress</h1>
67
- <div id="chart"></div>
 
68
 
69
  <script>
70
- // The data from Python
71
- const data = {data_str};
72
 
73
  document.addEventListener('DOMContentLoaded', function() {{
74
  // Set up dimensions
75
- const margin = {{top: 30, right: 30, bottom: 70, left: 60}};
76
- const width = 800 - margin.left - margin.right;
77
- const height = 400 - margin.top - margin.bottom;
78
 
79
  // Create SVG
80
- const svg = d3.select("#chart")
81
- .append("svg")
82
- .attr("width", width + margin.left + margin.right)
83
- .attr("height", height + margin.top + margin.bottom)
84
- .append("g")
85
- .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
86
 
87
- // X axis
88
- const x = d3.scaleBand()
89
- .range([0, width])
90
- .domain(data.map(function(d) {{ return d.name; }}))
91
- .padding(0.2);
92
-
93
- svg.append("g")
94
- .attr("class", "axis")
95
- .attr("transform", "translate(0," + height + ")")
96
- .call(d3.axisBottom(x))
97
- .selectAll("text")
98
- .attr("transform", "translate(-10,0)rotate(-45)")
99
- .style("text-anchor", "end");
100
-
101
- // Add X axis title
102
- svg.append("text")
103
- .attr("class", "axis-title")
104
- .attr("text-anchor", "middle")
105
- .attr("x", width / 2)
106
- .attr("y", height + margin.bottom - 5)
107
- .text("Country");
108
-
109
- // Y axis
110
- const y = d3.scaleLinear()
111
  .domain([0, 100])
112
- .range([height, 0]);
113
 
114
- svg.append("g")
115
- .attr("class", "axis")
116
- .call(d3.axisLeft(y));
117
-
118
- // Add Y axis title
119
- svg.append("text")
120
- .attr("class", "axis-title")
121
- .attr("text-anchor", "middle")
122
- .attr("transform", "rotate(-90)")
123
- .attr("x", -height / 2)
124
- .attr("y", -margin.left + 15)
125
- .text("Progress (%)");
126
 
127
- // Bars
128
- svg.selectAll("rect")
129
- .data(data)
130
- .enter()
131
- .append("rect")
132
- .attr("class", "bar")
133
- .attr("x", function(d) {{ return x(d.name); }})
134
- .attr("y", function(d) {{ return y(d.value); }})
135
- .attr("width", x.bandwidth())
136
- .attr("height", function(d) {{ return height - y(d.value); }})
137
- .append("title")
138
- .text(function(d) {{ return d.name + ": " + d.value + "%"; }});
139
 
140
- // Value labels on top of bars
141
- svg.selectAll(".label")
142
- .data(data)
143
- .enter()
144
- .append("text")
145
- .attr("class", "label")
146
- .attr("text-anchor", "middle")
147
- .attr("x", function(d) {{ return x(d.name) + x.bandwidth() / 2; }})
148
- .attr("y", function(d) {{ return y(d.value) - 5; }})
149
- .text(function(d) {{ return d.value + "%"; }})
150
- .attr("fill", "white");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
  }});
152
  </script>
153
  </body>
@@ -156,15 +268,15 @@ async def serve_plot():
156
 
157
  return fastapi.responses.HTMLResponse(content=html_content)
158
 
159
- # Create a simple Gradio interface with an iframe to display the plot
160
  def create_iframe():
161
  # Add a random parameter to force reload
162
  random_param = random.randint(1, 10000)
163
- return f'<iframe src="/d3-plot?t={random_param}" style="width:100%; height:500px; border:none;"></iframe>'
164
 
165
  # Create the Gradio blocks
166
  with gr.Blocks(theme=gr.themes.Soft(primary_hue="pink", secondary_hue="purple")) as demo:
167
- gr.Markdown("# Latin America & Spain Progress Chart")
168
 
169
  iframe_output = gr.HTML(create_iframe())
170
 
 
1
  import gradio as gr
2
  import random
3
+ import json
4
  import fastapi
5
  from fastapi import FastAPI
6
 
7
  # Create a FastAPI app
8
  app = FastAPI()
9
 
10
+ # Sample country data with random progress percentages
11
  def generate_data():
12
+ return {
13
+ "MX": {"name": "Mexico", "percent": random.randint(10, 90)},
14
+ "AR": {"name": "Argentina", "percent": random.randint(10, 90)},
15
+ "CO": {"name": "Colombia", "percent": random.randint(10, 90)},
16
+ "CL": {"name": "Chile", "percent": random.randint(10, 90)},
17
+ "PE": {"name": "Peru", "percent": random.randint(10, 90)},
18
+ "ES": {"name": "Spain", "percent": random.randint(10, 90)},
19
+ "BR": {"name": "Brazil", "percent": random.randint(10, 90)},
20
+ "VE": {"name": "Venezuela", "percent": random.randint(10, 90)},
21
+ "EC": {"name": "Ecuador", "percent": random.randint(10, 90)},
22
+ "BO": {"name": "Bolivia", "percent": random.randint(10, 90)},
23
+ "PY": {"name": "Paraguay", "percent": random.randint(10, 90)},
24
+ "UY": {"name": "Uruguay", "percent": random.randint(10, 90)},
25
+ "CR": {"name": "Costa Rica", "percent": random.randint(10, 90)},
26
+ "PA": {"name": "Panama", "percent": random.randint(10, 90)},
27
+ "DO": {"name": "Dominican Republic", "percent": random.randint(10, 90)},
28
+ "GT": {"name": "Guatemala", "percent": random.randint(10, 90)},
29
+ "HN": {"name": "Honduras", "percent": random.randint(10, 90)},
30
+ "SV": {"name": "El Salvador", "percent": random.randint(10, 90)},
31
+ "NI": {"name": "Nicaragua", "percent": random.randint(10, 90)},
32
+ "CU": {"name": "Cuba", "percent": random.randint(10, 90)}
33
+ }
34
 
35
+ # Route to serve the map visualization
36
+ @app.get("/d3-map")
37
+ async def serve_map():
38
+ # Generate random data
39
+ country_data = generate_data()
40
 
41
+ # Convert to JSON for JavaScript
42
+ country_data_json = json.dumps(country_data)
43
 
44
  html_content = f"""
45
  <!DOCTYPE html>
46
  <html>
47
  <head>
48
  <meta charset="utf-8">
49
+ <title>Latin America & Spain Map</title>
50
  <script src="https://d3js.org/d3.v7.min.js"></script>
51
  <style>
52
  body {{
53
+ margin: 0;
54
  padding: 20px;
55
  background-color: #111;
56
  color: #fff;
57
+ font-family: sans-serif;
58
  }}
59
+ h1 {{
60
+ margin-bottom: 20px;
 
 
 
 
 
 
 
61
  }}
62
+ #map-container {{
63
+ width: 100%;
64
+ height: 600px;
65
+ position: relative;
66
  }}
67
+ #tooltip {{
68
+ position: absolute;
69
+ background-color: rgba(0, 0, 0, 0.8);
70
+ border-radius: 5px;
71
+ padding: 8px;
72
+ color: white;
73
  font-size: 12px;
74
+ pointer-events: none;
75
+ opacity: 0;
76
+ transition: opacity 0.3s;
77
+ border: 1px solid rgba(255, 255, 255, 0.2);
78
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
79
  }}
80
  </style>
81
  </head>
82
  <body>
83
+ <h1>Latin America & Spain Progress Map</h1>
84
+ <div id="map-container"></div>
85
+ <div id="tooltip"></div>
86
 
87
  <script>
88
+ // Country data from Python
89
+ const countryData = {country_data_json};
90
 
91
  document.addEventListener('DOMContentLoaded', function() {{
92
  // Set up dimensions
93
+ const container = document.getElementById('map-container');
94
+ const width = container.clientWidth;
95
+ const height = container.clientHeight;
96
 
97
  // Create SVG
98
+ const svg = d3.select('#map-container')
99
+ .append('svg')
100
+ .attr('width', width)
101
+ .attr('height', height)
102
+ .attr('viewBox', `0 0 ${{width}} ${{height}}`);
 
103
 
104
+ // Create color scale
105
+ const colorScale = d3.scaleLinear()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
  .domain([0, 100])
107
+ .range(['#4a1942', '#f32b7b']);
108
 
109
+ // Set up projection focused on Latin America and Spain
110
+ const projection = d3.geoMercator()
111
+ .center([-60, 0])
112
+ .scale(width / 5)
113
+ .translate([width / 2, height / 2]);
114
+
115
+ const path = d3.geoPath().projection(projection);
 
 
 
 
 
116
 
117
+ // Tooltip setup
118
+ const tooltip = d3.select('#tooltip');
 
 
 
 
 
 
 
 
 
 
119
 
120
+ // Load GeoJSON data
121
+ d3.json('https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/world.geojson')
122
+ .then(function(data) {{
123
+ // Draw countries
124
+ svg.selectAll('path')
125
+ .data(data.features)
126
+ .enter()
127
+ .append('path')
128
+ .attr('d', path)
129
+ .attr('stroke', '#f32b7b')
130
+ .attr('stroke-width', 1)
131
+ .attr('fill', d => {{
132
+ // Get the ISO code from the properties
133
+ const iso = d.properties.iso_a2;
134
+
135
+ if (countryData[iso]) {{
136
+ return colorScale(countryData[iso].percent);
137
+ }}
138
+ return '#2d3748'; // Default gray for other countries
139
+ }})
140
+ .on('mouseover', function(event, d) {{
141
+ const iso = d.properties.iso_a2;
142
+
143
+ d3.select(this)
144
+ .attr('stroke', '#4a1942')
145
+ .attr('stroke-width', 2);
146
+
147
+ if (countryData[iso]) {{
148
+ tooltip.style('opacity', 1)
149
+ .style('left', (event.pageX + 15) + 'px')
150
+ .style('top', (event.pageY + 15) + 'px')
151
+ .html(`
152
+ <strong>${{countryData[iso].name}}</strong><br/>
153
+ Progress: ${{countryData[iso].percent}}%
154
+ `);
155
+ }}
156
+ }})
157
+ .on('mousemove', function(event) {{
158
+ tooltip.style('left', (event.pageX + 15) + 'px')
159
+ .style('top', (event.pageY + 15) + 'px');
160
+ }})
161
+ .on('mouseout', function() {{
162
+ d3.select(this)
163
+ .attr('stroke', '#f32b7b')
164
+ .attr('stroke-width', 1);
165
+
166
+ tooltip.style('opacity', 0);
167
+ }});
168
+
169
+ // Add a legend
170
+ const legendWidth = Math.min(width - 40, 200);
171
+ const legendHeight = 15;
172
+ const legendX = width - legendWidth - 20;
173
+
174
+ const legend = svg.append('g')
175
+ .attr('transform', `translate(${{legendX}}, 30)`);
176
+
177
+ // Create gradient for legend
178
+ const defs = svg.append('defs');
179
+ const gradient = defs.append('linearGradient')
180
+ .attr('id', 'dataGradient')
181
+ .attr('x1', '0%')
182
+ .attr('y1', '0%')
183
+ .attr('x2', '100%')
184
+ .attr('y2', '0%');
185
+
186
+ gradient.append('stop')
187
+ .attr('offset', '0%')
188
+ .attr('stop-color', '#4a1942');
189
+
190
+ gradient.append('stop')
191
+ .attr('offset', '100%')
192
+ .attr('stop-color', '#f32b7b');
193
+
194
+ // Add legend title
195
+ legend.append('text')
196
+ .attr('x', legendWidth / 2)
197
+ .attr('y', -10)
198
+ .attr('text-anchor', 'middle')
199
+ .attr('font-size', '12px')
200
+ .attr('fill', '#f1f5f9')
201
+ .text('Progress');
202
+
203
+ // Add legend rectangle
204
+ legend.append('rect')
205
+ .attr('width', legendWidth)
206
+ .attr('height', legendHeight)
207
+ .attr('rx', 2)
208
+ .attr('ry', 2)
209
+ .style('fill', 'url(#dataGradient)');
210
+
211
+ // Add legend labels
212
+ legend.append('text')
213
+ .attr('x', 0)
214
+ .attr('y', legendHeight + 15)
215
+ .attr('text-anchor', 'start')
216
+ .attr('font-size', '10px')
217
+ .attr('fill', '#94a3b8')
218
+ .text('0%');
219
+
220
+ legend.append('text')
221
+ .attr('x', legendWidth / 2)
222
+ .attr('y', legendHeight + 15)
223
+ .attr('text-anchor', 'middle')
224
+ .attr('font-size', '10px')
225
+ .attr('fill', '#94a3b8')
226
+ .text('50%');
227
+
228
+ legend.append('text')
229
+ .attr('x', legendWidth)
230
+ .attr('y', legendHeight + 15)
231
+ .attr('text-anchor', 'end')
232
+ .attr('font-size', '10px')
233
+ .attr('fill', '#94a3b8')
234
+ .text('100%');
235
+ })
236
+ .catch(function(error) {{
237
+ console.error('Error loading or rendering the map:', error);
238
+ container.innerHTML = `<div style="color: white; text-align: center;">Error loading map: ${{error.message}}</div>`;
239
+ }});
240
+
241
+ // Handle window resize
242
+ window.addEventListener('resize', function() {{
243
+ const width = container.clientWidth;
244
+
245
+ // Update SVG dimensions
246
+ d3.select('svg')
247
+ .attr('width', width)
248
+ .attr('viewBox', `0 0 ${{width}} ${{height}}`);
249
+
250
+ // Update projection
251
+ projection.scale(width / 5)
252
+ .translate([width / 2, height / 2]);
253
+
254
+ // Update paths
255
+ d3.selectAll('path').attr('d', path);
256
+
257
+ // Update legend position
258
+ const legendWidth = Math.min(width - 40, 200);
259
+ const legendX = width - legendWidth - 20;
260
+
261
+ d3.select('g').attr('transform', `translate(${{legendX}}, 30)`);
262
+ }});
263
  }});
264
  </script>
265
  </body>
 
268
 
269
  return fastapi.responses.HTMLResponse(content=html_content)
270
 
271
+ # Create a simple Gradio interface with an iframe
272
  def create_iframe():
273
  # Add a random parameter to force reload
274
  random_param = random.randint(1, 10000)
275
+ return f'<iframe src="/d3-map?t={random_param}" style="width:100%; height:650px; border:none;"></iframe>'
276
 
277
  # Create the Gradio blocks
278
  with gr.Blocks(theme=gr.themes.Soft(primary_hue="pink", secondary_hue="purple")) as demo:
279
+ gr.Markdown("# Latin America & Spain Progress Map")
280
 
281
  iframe_output = gr.HTML(create_iframe())
282