ouhenio commited on
Commit
ddd101e
·
verified ·
1 Parent(s): 2ba8eb9

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +242 -222
app.py CHANGED
@@ -1,6 +1,7 @@
1
  import gradio as gr
2
  import json
3
  import random
 
4
 
5
  # Sample country data with random progress percentages
6
  COUNTRY_DATA = {
@@ -20,248 +21,267 @@ COUNTRY_DATA = {
20
  "PA": {"name": "Panama", "percent": random.randint(10, 90)}
21
  }
22
 
23
- # Create the basic HTML container for the map
24
- def create_map_container():
25
  return """
26
- <div id="map-container" style="width:100%; height:600px; position:relative; background-color:#111;">
27
- <div style="display:flex; justify-content:center; align-items:center; height:100%; color:white; font-family:sans-serif;">
28
- Loading map visualization...
29
- </div>
30
- </div>
31
- <div id="tooltip" style="position:absolute; background-color:rgba(0,0,0,0.8); border-radius:5px; padding:8px; color:white; font-size:12px; pointer-events:none; opacity:0; transition:opacity 0.3s;"></div>
32
  """
33
 
34
- # Create a script tag with the D3 code
35
- def create_map_script():
36
- # Convert country data to JSON for JavaScript
37
- country_data_json = json.dumps(COUNTRY_DATA)
38
 
 
 
 
 
 
 
 
 
39
  return f"""
40
- <script>
41
- // Function to load D3.js and create the map
42
- async function createMap() {{
43
- // Load D3.js dynamically
44
- await new Promise((resolve) => {{
45
- const script = document.createElement('script');
46
- script.src = 'https://d3js.org/d3.v7.min.js';
47
- script.onload = resolve;
48
- document.head.appendChild(script);
49
- }});
50
-
51
- console.log('D3 loaded successfully');
52
-
53
- // Country data from Python
54
- const countryData = {country_data_json};
55
-
56
- // Get container dimensions
57
- const container = document.getElementById('map-container');
58
- const width = container.clientWidth;
59
- const height = container.clientHeight;
60
-
61
- // Clear loading message
62
- container.innerHTML = '';
63
-
64
- // Create SVG
65
- const svg = d3.select('#map-container')
66
- .append('svg')
67
- .attr('width', width)
68
- .attr('height', height)
69
- .attr('viewBox', `0 0 ${{width}} ${{height}}`);
70
-
71
- // Create color scale
72
- const colorScale = d3.scaleLinear()
73
- .domain([0, 100])
74
- .range(['#4a1942', '#f32b7b']);
75
-
76
- // Set up projection focused on Latin America
77
- const projection = d3.geoMercator()
78
- .center([-60, 0])
79
- .scale(width / 5)
80
- .translate([width / 2, height / 2]);
81
-
82
- const path = d3.geoPath().projection(projection);
83
-
84
- // Tooltip setup
85
- const tooltip = d3.select('#tooltip');
86
 
87
- // Load GeoJSON data
88
- try {{
89
- const response = await fetch('https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/world.geojson');
90
- const data = await response.json();
91
-
92
- // Draw countries
93
- svg.selectAll('path')
94
- .data(data.features)
95
- .enter()
96
- .append('path')
97
- .attr('d', path)
98
- .attr('stroke', '#f32b7b')
99
- .attr('stroke-width', 1)
100
- .attr('fill', d => {{
101
- // Get the ISO code from the properties
102
- const iso = d.properties.iso_a2;
103
-
104
- if (countryData[iso]) {{
105
- return colorScale(countryData[iso].percent);
106
- }}
107
- return '#2d3748'; // Default gray for other countries
108
- }})
109
- .on('mouseover', function(event, d) {{
110
- const iso = d.properties.iso_a2;
111
-
112
- d3.select(this)
113
- .attr('stroke', '#4a1942')
114
- .attr('stroke-width', 2);
115
-
116
- if (countryData[iso]) {{
117
- tooltip.style('opacity', 1)
118
- .style('left', (event.pageX + 15) + 'px')
119
- .style('top', (event.pageY + 15) + 'px')
120
- .html(`
121
- <strong>${{countryData[iso].name}}</strong><br/>
122
- Progress: ${{countryData[iso].percent}}%
123
- `);
124
- }}
125
- }})
126
- .on('mousemove', function(event) {{
127
- tooltip.style('left', (event.pageX + 15) + 'px')
128
- .style('top', (event.pageY + 15) + 'px');
129
- }})
130
- .on('mouseout', function() {{
131
- d3.select(this)
132
- .attr('stroke', '#f32b7b')
133
- .attr('stroke-width', 1);
134
-
135
- tooltip.style('opacity', 0);
136
- }});
137
-
138
- // Add a legend
139
- const legendWidth = Math.min(width - 40, 200);
140
- const legendHeight = 15;
141
- const legendX = width - legendWidth - 20;
142
-
143
- const legend = svg.append('g')
144
- .attr('transform', `translate(${{legendX}}, 30)`);
145
-
146
- // Create gradient for legend
147
- const defs = svg.append('defs');
148
- const gradient = defs.append('linearGradient')
149
- .attr('id', 'dataGradient')
150
- .attr('x1', '0%')
151
- .attr('y1', '0%')
152
- .attr('x2', '100%')
153
- .attr('y2', '0%');
154
-
155
- gradient.append('stop')
156
- .attr('offset', '0%')
157
- .attr('stop-color', '#4a1942');
158
-
159
- gradient.append('stop')
160
- .attr('offset', '100%')
161
- .attr('stop-color', '#f32b7b');
162
-
163
- // Add legend title
164
- legend.append('text')
165
- .attr('x', legendWidth / 2)
166
- .attr('y', -10)
167
- .attr('text-anchor', 'middle')
168
- .attr('font-size', '12px')
169
- .attr('fill', '#f1f5f9')
170
- .text('Progress');
171
-
172
- // Add legend rectangle
173
- legend.append('rect')
174
- .attr('width', legendWidth)
175
- .attr('height', legendHeight)
176
- .attr('rx', 2)
177
- .attr('ry', 2)
178
- .style('fill', 'url(#dataGradient)');
179
-
180
- // Add legend labels
181
- legend.append('text')
182
- .attr('x', 0)
183
- .attr('y', legendHeight + 15)
184
- .attr('text-anchor', 'start')
185
- .attr('font-size', '10px')
186
- .attr('fill', '#94a3b8')
187
- .text('0%');
188
-
189
- legend.append('text')
190
- .attr('x', legendWidth / 2)
191
- .attr('y', legendHeight + 15)
192
- .attr('text-anchor', 'middle')
193
- .attr('font-size', '10px')
194
- .attr('fill', '#94a3b8')
195
- .text('50%');
196
 
197
- legend.append('text')
198
- .attr('x', legendWidth)
199
- .attr('y', legendHeight + 15)
200
- .attr('text-anchor', 'end')
201
- .attr('font-size', '10px')
202
- .attr('fill', '#94a3b8')
203
- .text('100%');
204
-
205
- // Handle window resize
206
- window.addEventListener('resize', () => {{
207
  const width = container.clientWidth;
 
208
 
209
- // Update SVG dimensions
210
- svg.attr('width', width)
211
- .attr('viewBox', `0 0 ${{width}} ${{height}}`);
 
 
 
212
 
213
- // Update projection
214
- projection.scale(width / 5)
 
 
 
 
 
 
 
215
  .translate([width / 2, height / 2]);
 
 
216
 
217
- // Update paths
218
- svg.selectAll('path').attr('d', path);
219
-
220
- // Update legend position
221
- const legendWidth = Math.min(width - 40, 200);
222
- const legendX = width - legendWidth - 20;
223
 
224
- legend.attr('transform', `translate(${{legendX}}, 30)`);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
225
  }});
226
- }} catch (error) {{
227
- console.error('Error loading or rendering the map:', error);
228
- container.innerHTML = `<div style="color: white; text-align: center;">Error loading map: ${{error.message}}</div>`;
229
- }}
230
- }}
231
-
232
- // Call the function when the DOM is ready
233
- document.addEventListener('DOMContentLoaded', createMap);
234
- </script>
235
  """
 
 
236
 
237
  # Create a simple Gradio interface
238
- with gr.Blocks(theme=gr.themes.Soft(primary_hue="pink", secondary_hue="purple")) as demo:
239
  gr.Markdown("# Latin America & Spain Map")
240
 
241
- # Create a container for the map
242
- map_container = gr.HTML(create_map_container())
243
-
244
- # Create a container for the script
245
- script_container = gr.HTML(create_map_script(), visible=False)
246
 
247
  # Button to generate new random data
248
- def update_data():
249
- # Declare the variable as global first
250
- global COUNTRY_DATA
251
-
252
- # Create new random percentages
253
- new_data = {
254
- code: {"name": data["name"], "percent": random.randint(10, 90)}
255
- for code, data in COUNTRY_DATA.items()
256
- }
257
-
258
- # Update the global variable
259
- COUNTRY_DATA = new_data
260
-
261
- # Return the updated script
262
- return create_map_script()
263
-
264
- gr.Button("Generate New Random Data").click(fn=update_data, outputs=script_container)
265
 
 
266
  if __name__ == "__main__":
267
- demo.launch()
 
1
  import gradio as gr
2
  import json
3
  import random
4
+ import os
5
 
6
  # Sample country data with random progress percentages
7
  COUNTRY_DATA = {
 
21
  "PA": {"name": "Panama", "percent": random.randint(10, 90)}
22
  }
23
 
24
+ # Create an iframe that will display our map
25
+ def create_iframe():
26
  return """
27
+ <iframe id="map-iframe" src="/map" style="width:100%; height:600px; border:none;"></iframe>
 
 
 
 
 
28
  """
29
 
30
+ # Create a new random dataset
31
+ def generate_random_data():
32
+ global COUNTRY_DATA
 
33
 
34
+ # Create new random percentages
35
+ COUNTRY_DATA = {
36
+ code: {"name": data["name"], "percent": random.randint(10, 90)}
37
+ for code, data in COUNTRY_DATA.items()
38
+ }
39
+
40
+ # Refresh the iframe by changing the src with a timestamp
41
+ timestamp = random.randint(1, 1000000)
42
  return f"""
43
+ <iframe id="map-iframe" src="/map?t={timestamp}" style="width:100%; height:600px; border:none;"></iframe>
44
+ """
45
+
46
+ # Create the FastAPI application for Gradio
47
+ app = gr.routes.App()
48
+
49
+ # Create a route to serve the map HTML
50
+ @app.get("/map")
51
+ def serve_map():
52
+ # Create a standalone HTML file for the map
53
+ html_content = f"""
54
+ <!DOCTYPE html>
55
+ <html>
56
+ <head>
57
+ <meta charset="utf-8">
58
+ <title>Latin America Map</title>
59
+ <script src="https://d3js.org/d3.v7.min.js"></script>
60
+ <style>
61
+ body {{
62
+ margin: 0;
63
+ padding: 0;
64
+ background-color: #111;
65
+ color: white;
66
+ font-family: sans-serif;
67
+ }}
68
+ #map-container {{
69
+ width: 100%;
70
+ height: 600px;
71
+ position: relative;
72
+ }}
73
+ #tooltip {{
74
+ position: absolute;
75
+ background-color: rgba(0,0,0,0.8);
76
+ border-radius: 5px;
77
+ padding: 8px;
78
+ color: white;
79
+ font-size: 12px;
80
+ pointer-events: none;
81
+ opacity: 0;
82
+ transition: opacity 0.3s;
83
+ }}
84
+ </style>
85
+ </head>
86
+ <body>
87
+ <div id="map-container"></div>
88
+ <div id="tooltip"></div>
89
 
90
+ <script>
91
+ // Country data
92
+ const countryData = {json.dumps(COUNTRY_DATA)};
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
 
94
+ // Set up
95
+ document.addEventListener('DOMContentLoaded', function() {{
96
+ // Get container dimensions
97
+ const container = document.getElementById('map-container');
 
 
 
 
 
 
98
  const width = container.clientWidth;
99
+ const height = container.clientHeight || 600;
100
 
101
+ // Create SVG
102
+ const svg = d3.select('#map-container')
103
+ .append('svg')
104
+ .attr('width', width)
105
+ .attr('height', height)
106
+ .attr('viewBox', `0 0 ${{width}} ${{height}}`);
107
 
108
+ // Create color scale
109
+ const colorScale = d3.scaleLinear()
110
+ .domain([0, 100])
111
+ .range(['#4a1942', '#f32b7b']);
112
+
113
+ // Set up projection focused on Latin America
114
+ const projection = d3.geoMercator()
115
+ .center([-60, 0])
116
+ .scale(width / 5)
117
  .translate([width / 2, height / 2]);
118
+
119
+ const path = d3.geoPath().projection(projection);
120
 
121
+ // Tooltip setup
122
+ const tooltip = d3.select('#tooltip');
 
 
 
 
123
 
124
+ // Load GeoJSON data
125
+ d3.json('https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/world.geojson')
126
+ .then(function(data) {{
127
+ // Draw countries
128
+ svg.selectAll('path')
129
+ .data(data.features)
130
+ .enter()
131
+ .append('path')
132
+ .attr('d', path)
133
+ .attr('stroke', '#f32b7b')
134
+ .attr('stroke-width', 1)
135
+ .attr('fill', d => {{
136
+ // Get the ISO code from the properties
137
+ const iso = d.properties.iso_a2;
138
+
139
+ if (countryData[iso]) {{
140
+ return colorScale(countryData[iso].percent);
141
+ }}
142
+ return '#2d3748'; // Default gray for other countries
143
+ }})
144
+ .on('mouseover', function(event, d) {{
145
+ const iso = d.properties.iso_a2;
146
+
147
+ d3.select(this)
148
+ .attr('stroke', '#4a1942')
149
+ .attr('stroke-width', 2);
150
+
151
+ if (countryData[iso]) {{
152
+ tooltip.style('opacity', 1)
153
+ .style('left', (event.pageX + 15) + 'px')
154
+ .style('top', (event.pageY + 15) + 'px')
155
+ .html(`
156
+ <strong>${{countryData[iso].name}}</strong><br/>
157
+ Progress: ${{countryData[iso].percent}}%
158
+ `);
159
+ }}
160
+ }})
161
+ .on('mousemove', function(event) {{
162
+ tooltip.style('left', (event.pageX + 15) + 'px')
163
+ .style('top', (event.pageY + 15) + 'px');
164
+ }})
165
+ .on('mouseout', function() {{
166
+ d3.select(this)
167
+ .attr('stroke', '#f32b7b')
168
+ .attr('stroke-width', 1);
169
+
170
+ tooltip.style('opacity', 0);
171
+ }});
172
+
173
+ // Add a legend
174
+ const legendWidth = Math.min(width - 40, 200);
175
+ const legendHeight = 15;
176
+ const legendX = width - legendWidth - 20;
177
+
178
+ const legend = svg.append('g')
179
+ .attr('transform', `translate(${{legendX}}, 30)`);
180
+
181
+ // Create gradient for legend
182
+ const defs = svg.append('defs');
183
+ const gradient = defs.append('linearGradient')
184
+ .attr('id', 'dataGradient')
185
+ .attr('x1', '0%')
186
+ .attr('y1', '0%')
187
+ .attr('x2', '100%')
188
+ .attr('y2', '0%');
189
+
190
+ gradient.append('stop')
191
+ .attr('offset', '0%')
192
+ .attr('stop-color', '#4a1942');
193
+
194
+ gradient.append('stop')
195
+ .attr('offset', '100%')
196
+ .attr('stop-color', '#f32b7b');
197
+
198
+ // Add legend title
199
+ legend.append('text')
200
+ .attr('x', legendWidth / 2)
201
+ .attr('y', -10)
202
+ .attr('text-anchor', 'middle')
203
+ .attr('font-size', '12px')
204
+ .attr('fill', '#f1f5f9')
205
+ .text('Progress');
206
+
207
+ // Add legend rectangle
208
+ legend.append('rect')
209
+ .attr('width', legendWidth)
210
+ .attr('height', legendHeight)
211
+ .attr('rx', 2)
212
+ .attr('ry', 2)
213
+ .style('fill', 'url(#dataGradient)');
214
+
215
+ // Add legend labels
216
+ legend.append('text')
217
+ .attr('x', 0)
218
+ .attr('y', legendHeight + 15)
219
+ .attr('text-anchor', 'start')
220
+ .attr('font-size', '10px')
221
+ .attr('fill', '#94a3b8')
222
+ .text('0%');
223
+
224
+ legend.append('text')
225
+ .attr('x', legendWidth / 2)
226
+ .attr('y', legendHeight + 15)
227
+ .attr('text-anchor', 'middle')
228
+ .attr('font-size', '10px')
229
+ .attr('fill', '#94a3b8')
230
+ .text('50%');
231
+
232
+ legend.append('text')
233
+ .attr('x', legendWidth)
234
+ .attr('y', legendHeight + 15)
235
+ .attr('text-anchor', 'end')
236
+ .attr('font-size', '10px')
237
+ .attr('fill', '#94a3b8')
238
+ .text('100%');
239
+ })
240
+ .catch(function(error) {{
241
+ console.error('Error loading or rendering the map:', error);
242
+ container.innerHTML = `<div style="color: white; text-align: center;">Error loading map: ${{error.message}}</div>`;
243
+ }});
244
+
245
+ // Handle window resize
246
+ window.addEventListener('resize', function() {{
247
+ const width = container.clientWidth;
248
+
249
+ // Update SVG dimensions
250
+ d3.select('svg')
251
+ .attr('width', width)
252
+ .attr('viewBox', `0 0 ${{width}} ${{height}}`);
253
+
254
+ // Update projection
255
+ projection.scale(width / 5)
256
+ .translate([width / 2, height / 2]);
257
+
258
+ // Update paths
259
+ d3.selectAll('path').attr('d', path);
260
+
261
+ // Update legend position
262
+ const legendWidth = Math.min(width - 40, 200);
263
+ const legendX = width - legendWidth - 20;
264
+
265
+ d3.select('g').attr('transform', `translate(${{legendX}}, 30)`);
266
+ }});
267
  }});
268
+ </script>
269
+ </body>
270
+ </html>
 
 
 
 
 
 
271
  """
272
+
273
+ return gr.routes.Response(content=html_content, media_type="text/html")
274
 
275
  # Create a simple Gradio interface
276
+ with gr.Blocks(theme=gr.themes.Soft(primary_hue="pink", secondary_hue="purple"), css="#map-iframe{min-height:600px;}") as demo:
277
  gr.Markdown("# Latin America & Spain Map")
278
 
279
+ # Create an iframe to show the map
280
+ map_display = gr.HTML(create_iframe())
 
 
 
281
 
282
  # Button to generate new random data
283
+ gr.Button("Generate New Random Data").click(fn=generate_random_data, outputs=map_display)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
284
 
285
+ # Launch the app
286
  if __name__ == "__main__":
287
+ demo.launch(app=app)