ouhenio commited on
Commit
f7a1251
verified
1 Parent(s): 9ed5b46

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +78 -28
app.py CHANGED
@@ -46,7 +46,7 @@ HTML_TEMPLATE = """
46
  padding: 20px;
47
  background-color: #0f1218;
48
  color: #fff;
49
- font-family: sans-serif;
50
  }
51
  h1 {
52
  margin-bottom: 20px;
@@ -80,6 +80,7 @@ HTML_TEMPLATE = """
80
  transition: opacity 0.3s;
81
  border: 1px solid rgba(255, 255, 255, 0.2);
82
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
 
83
  }
84
  .country {
85
  cursor: pointer;
@@ -122,22 +123,34 @@ HTML_TEMPLATE = """
122
  justify-content: space-between;
123
  margin-bottom: 8px;
124
  align-items: center;
 
125
  }
126
  .country-bar {
127
- width: 60%;
128
  height: 6px;
129
  background-color: #30363d;
130
  border-radius: 3px;
131
  overflow: hidden;
 
132
  }
133
  .country-bar-fill {
134
  height: 100%;
135
  background: linear-gradient(to right, #4a1942, #f32b7b);
136
  border-radius: 3px;
137
  }
 
 
 
 
138
  .legend {
139
  margin-top: 20px;
140
  }
 
 
 
 
 
 
141
  </style>
142
  </head>
143
  <body>
@@ -148,15 +161,18 @@ HTML_TEMPLATE = """
148
  <div class="stat-title">Resumen General</div>
149
 
150
  <div class="stat-item">
151
- Pa铆ses en la base de datos: <span class="stat-value">20</span>
 
152
  </div>
153
 
154
  <div class="stat-item">
155
- Total de documentos: <span class="stat-value" id="total-docs">0</span>
 
156
  </div>
157
 
158
  <div class="stat-item">
159
- Promedio de completitud: <span class="stat-value" id="avg-percent">0%</span>
 
160
  </div>
161
 
162
  <div class="top-countries">
@@ -166,7 +182,7 @@ HTML_TEMPLATE = """
166
  </div>
167
  </div>
168
 
169
- <div class="stat-item" style="margin-top: 30px; font-style: italic; font-size: 0.9em;">
170
  Selecciona un pa铆s en el mapa para ver informaci贸n detallada.
171
  </div>
172
  </div>
@@ -181,27 +197,32 @@ HTML_TEMPLATE = """
181
  const countryData = COUNTRY_DATA_PLACEHOLDER;
182
 
183
  document.addEventListener('DOMContentLoaded', function() {
 
 
184
  // Set up dimensions
185
  const container = document.getElementById('map-container');
186
  const width = container.clientWidth;
187
  const height = container.clientHeight;
188
 
 
 
189
  // Create SVG
190
  const svg = d3.select('#map-container')
191
  .append('svg')
192
  .attr('width', width)
193
- .attr('height', height)
194
- .attr('viewBox', '0 0 ' + width + ' ' + height);
 
195
 
196
  // Create color scale
197
  const colorScale = d3.scaleLinear()
198
  .domain([0, 100])
199
  .range(['#4a1942', '#f32b7b']);
200
-
201
- // Set up projection focused on Latin America with Spain
202
  const projection = d3.geoMercator()
203
- .center([-60, 0])
204
- .scale(width / 3.5)
205
  .translate([width / 2, height / 2]);
206
 
207
  const path = d3.geoPath().projection(projection);
@@ -209,17 +230,33 @@ HTML_TEMPLATE = """
209
  // Tooltip setup
210
  const tooltip = d3.select('#tooltip');
211
 
 
 
212
  // Load GeoJSON data
213
  d3.json('https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/world.geojson')
214
  .then(function(data) {
 
 
215
  // Filter to only include our target countries
216
  const relevantCountryCodes = Object.keys(countryData);
217
 
 
 
 
 
 
 
 
 
 
 
218
  // Filter the features
219
  const relevantFeatures = data.features.filter(d =>
220
  relevantCountryCodes.includes(d.properties.iso_a2)
221
  );
222
 
 
 
223
  // Draw only our target countries
224
  svg.selectAll('.country')
225
  .data(relevantFeatures)
@@ -257,16 +294,15 @@ HTML_TEMPLATE = """
257
 
258
  tooltip.style('opacity', 0);
259
  });
260
-
261
- // Add a legend at the top right
262
  const legendWidth = 200;
263
  const legendHeight = 15;
264
  const legendX = width - legendWidth - 20;
265
  const legendY = 20;
266
 
267
- // Create a legend group
268
  const legend = svg.append('g')
269
- .attr('class', 'legend')
270
  .attr('transform', 'translate(' + legendX + ',' + legendY + ')');
271
 
272
  // Legend title
@@ -275,7 +311,8 @@ HTML_TEMPLATE = """
275
  .attr('y', -5)
276
  .attr('text-anchor', 'middle')
277
  .style('fill', '#fff')
278
- .text('Porcentaje de Datos Recolectados');
 
279
 
280
  // Create gradient for legend
281
  const defs = svg.append('defs');
@@ -298,7 +335,8 @@ HTML_TEMPLATE = """
298
  legend.append('rect')
299
  .attr('width', legendWidth)
300
  .attr('height', legendHeight)
301
- .style('fill', 'url(#legendGradient)');
 
302
 
303
  // Add min and max labels
304
  legend.append('text')
@@ -330,14 +368,23 @@ HTML_TEMPLATE = """
330
  })
331
  .catch(function(error) {
332
  console.error('Error loading or rendering the map:', error);
333
- container.innerHTML = '<div style="color: white; text-align: center;">Error loading map: ' + error.message + '</div>';
334
  });
335
 
336
  // Function to update statistics
337
  function updateStatistics() {
338
- // Calculate total documents (mock data)
 
 
 
 
 
 
 
 
 
339
  const totalDocs = Object.values(countryData).reduce((sum, country) => {
340
- return sum + (country.documents || Math.floor(Math.random() * 100000) + 50000);
341
  }, 0);
342
 
343
  // Calculate average percentage
@@ -355,12 +402,12 @@ HTML_TEMPLATE = """
355
  code: code,
356
  name: countryData[code].name,
357
  percent: countryData[code].percent,
358
- docs: countryData[code].documents || Math.floor(Math.random() * 100000) + 50000
359
  };
360
  });
361
 
362
  // Sort by document count descending
363
- countriesWithDocs.sort((a, b) => b.docs - a.docs);
364
 
365
  // Take the top 5
366
  const topCountries = countriesWithDocs.slice(0, 5);
@@ -378,26 +425,29 @@ HTML_TEMPLATE = """
378
  <div class="country-bar">
379
  <div class="country-bar-fill" style="width: ${country.percent}%;"></div>
380
  </div>
381
- <span>${country.docs.toLocaleString()}</span>
382
  `;
383
 
384
  topCountriesList.appendChild(countryDiv);
385
  });
 
 
386
  }
387
 
388
  // Handle window resize
389
  window.addEventListener('resize', function() {
 
 
390
  const width = container.clientWidth;
391
  const height = container.clientHeight;
392
 
393
  // Update SVG dimensions
394
  d3.select('svg')
395
  .attr('width', width)
396
- .attr('height', height)
397
- .attr('viewBox', '0 0 ' + width + ' ' + height);
398
 
399
  // Update projection
400
- projection.scale(width / 3.5)
401
  .translate([width / 2, height / 2]);
402
 
403
  // Update paths
@@ -422,7 +472,7 @@ async def serve_map():
422
 
423
  # Add random document counts
424
  for code in country_data:
425
- country_data[code]["documents"] = random.randint(50000, 700000)
426
 
427
  # Convert to JSON for JavaScript
428
  country_data_json = json.dumps(country_data)
 
46
  padding: 20px;
47
  background-color: #0f1218;
48
  color: #fff;
49
+ font-family: system-ui, -apple-system, sans-serif;
50
  }
51
  h1 {
52
  margin-bottom: 20px;
 
80
  transition: opacity 0.3s;
81
  border: 1px solid rgba(255, 255, 255, 0.2);
82
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
83
+ z-index: 1000;
84
  }
85
  .country {
86
  cursor: pointer;
 
123
  justify-content: space-between;
124
  margin-bottom: 8px;
125
  align-items: center;
126
+ font-size: 14px;
127
  }
128
  .country-bar {
129
+ flex: 1;
130
  height: 6px;
131
  background-color: #30363d;
132
  border-radius: 3px;
133
  overflow: hidden;
134
+ margin: 0 10px;
135
  }
136
  .country-bar-fill {
137
  height: 100%;
138
  background: linear-gradient(to right, #4a1942, #f32b7b);
139
  border-radius: 3px;
140
  }
141
+ .country-value {
142
+ width: 80px;
143
+ text-align: right;
144
+ }
145
  .legend {
146
  margin-top: 20px;
147
  }
148
+ .footer-note {
149
+ margin-top: 30px;
150
+ font-style: italic;
151
+ font-size: 0.9em;
152
+ color: #abb4c2;
153
+ }
154
  </style>
155
  </head>
156
  <body>
 
161
  <div class="stat-title">Resumen General</div>
162
 
163
  <div class="stat-item">
164
+ Pa铆ses en la base de datos:<br>
165
+ <span class="stat-value">20</span>
166
  </div>
167
 
168
  <div class="stat-item">
169
+ Total de documentos:<br>
170
+ <span class="stat-value" id="total-docs">0</span>
171
  </div>
172
 
173
  <div class="stat-item">
174
+ Promedio de completitud:<br>
175
+ <span class="stat-value" id="avg-percent">0%</span>
176
  </div>
177
 
178
  <div class="top-countries">
 
182
  </div>
183
  </div>
184
 
185
+ <div class="footer-note">
186
  Selecciona un pa铆s en el mapa para ver informaci贸n detallada.
187
  </div>
188
  </div>
 
197
  const countryData = COUNTRY_DATA_PLACEHOLDER;
198
 
199
  document.addEventListener('DOMContentLoaded', function() {
200
+ console.log('Document loaded, initializing map...');
201
+
202
  // Set up dimensions
203
  const container = document.getElementById('map-container');
204
  const width = container.clientWidth;
205
  const height = container.clientHeight;
206
 
207
+ console.log('Container dimensions:', width, height);
208
+
209
  // Create SVG
210
  const svg = d3.select('#map-container')
211
  .append('svg')
212
  .attr('width', width)
213
+ .attr('height', height);
214
+
215
+ console.log('SVG created');
216
 
217
  // Create color scale
218
  const colorScale = d3.scaleLinear()
219
  .domain([0, 100])
220
  .range(['#4a1942', '#f32b7b']);
221
+
222
+ // Set up projection with specific focus
223
  const projection = d3.geoMercator()
224
+ .center([-60, -15]) // Centered on South America
225
+ .scale(width / 3)
226
  .translate([width / 2, height / 2]);
227
 
228
  const path = d3.geoPath().projection(projection);
 
230
  // Tooltip setup
231
  const tooltip = d3.select('#tooltip');
232
 
233
+ console.log('Loading GeoJSON data...');
234
+
235
  // Load GeoJSON data
236
  d3.json('https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/world.geojson')
237
  .then(function(data) {
238
+ console.log('GeoJSON data loaded');
239
+
240
  // Filter to only include our target countries
241
  const relevantCountryCodes = Object.keys(countryData);
242
 
243
+ // Log countries in data
244
+ console.log('Countries in countryData:', relevantCountryCodes);
245
+ console.log('First few features from GeoJSON:', data.features.slice(0, 3));
246
+
247
+ // Add ocean background
248
+ svg.append('rect')
249
+ .attr('width', width)
250
+ .attr('height', height)
251
+ .attr('fill', '#0f1218');
252
+
253
  // Filter the features
254
  const relevantFeatures = data.features.filter(d =>
255
  relevantCountryCodes.includes(d.properties.iso_a2)
256
  );
257
 
258
+ console.log('Filtered features count:', relevantFeatures.length);
259
+
260
  // Draw only our target countries
261
  svg.selectAll('.country')
262
  .data(relevantFeatures)
 
294
 
295
  tooltip.style('opacity', 0);
296
  });
297
+
298
+ // Add a legend on the right side of the map
299
  const legendWidth = 200;
300
  const legendHeight = 15;
301
  const legendX = width - legendWidth - 20;
302
  const legendY = 20;
303
 
304
+ // Create legend group
305
  const legend = svg.append('g')
 
306
  .attr('transform', 'translate(' + legendX + ',' + legendY + ')');
307
 
308
  // Legend title
 
311
  .attr('y', -5)
312
  .attr('text-anchor', 'middle')
313
  .style('fill', '#fff')
314
+ .style('font-size', '12px')
315
+ .text('Porcentaje de Datos Recolectado');
316
 
317
  // Create gradient for legend
318
  const defs = svg.append('defs');
 
335
  legend.append('rect')
336
  .attr('width', legendWidth)
337
  .attr('height', legendHeight)
338
+ .style('fill', 'url(#legendGradient)')
339
+ .style('stroke', 'none');
340
 
341
  // Add min and max labels
342
  legend.append('text')
 
368
  })
369
  .catch(function(error) {
370
  console.error('Error loading or rendering the map:', error);
371
+ container.innerHTML = '<div style="color: white; text-align: center; padding: 20px;">Error loading map: ' + error.message + '</div>';
372
  });
373
 
374
  // Function to update statistics
375
  function updateStatistics() {
376
+ console.log('Updating statistics');
377
+
378
+ // Add random document counts to countries that don't have them
379
+ Object.keys(countryData).forEach(code => {
380
+ if (!countryData[code].documents) {
381
+ countryData[code].documents = Math.floor(Math.random() * 300000) + 300000;
382
+ }
383
+ });
384
+
385
+ // Calculate total documents
386
  const totalDocs = Object.values(countryData).reduce((sum, country) => {
387
+ return sum + (country.documents || 0);
388
  }, 0);
389
 
390
  // Calculate average percentage
 
402
  code: code,
403
  name: countryData[code].name,
404
  percent: countryData[code].percent,
405
+ documents: countryData[code].documents
406
  };
407
  });
408
 
409
  // Sort by document count descending
410
+ countriesWithDocs.sort((a, b) => b.documents - a.documents);
411
 
412
  // Take the top 5
413
  const topCountries = countriesWithDocs.slice(0, 5);
 
425
  <div class="country-bar">
426
  <div class="country-bar-fill" style="width: ${country.percent}%;"></div>
427
  </div>
428
+ <span class="country-value">${country.documents.toLocaleString()}</span>
429
  `;
430
 
431
  topCountriesList.appendChild(countryDiv);
432
  });
433
+
434
+ console.log('Statistics updated');
435
  }
436
 
437
  // Handle window resize
438
  window.addEventListener('resize', function() {
439
+ console.log('Window resized');
440
+
441
  const width = container.clientWidth;
442
  const height = container.clientHeight;
443
 
444
  // Update SVG dimensions
445
  d3.select('svg')
446
  .attr('width', width)
447
+ .attr('height', height);
 
448
 
449
  // Update projection
450
+ projection.scale(width / 3)
451
  .translate([width / 2, height / 2]);
452
 
453
  // Update paths
 
472
 
473
  # Add random document counts
474
  for code in country_data:
475
+ country_data[code]["documents"] = random.randint(300000, 700000)
476
 
477
  # Convert to JSON for JavaScript
478
  country_data_json = json.dumps(country_data)