How can I dynamically resize a Bubble using CSV data based on the radius specified in a JSON file when a button is clicked?

I've developed a unique World Bubble Map that displays bubbles based on the geolocation of countries, with the size changing according to parameters selected from radio buttons.

For example, when population is chosen, the bubble sizes adjust based on each nation's population, and with each button click, they update to reflect the new parameter.

Currently, I've successfully created a Bubble Map that reads data from a JSON file to plot the initial bubbles. However, I'm facing a challenge in incorporating additional parameters found in a separate CSV file, which contains all the necessary data for visualization but is not linked to the JSON file providing geolocation data.

Is there a method to connect my CSV file to generate bubbles based on country geolocation and parameters from the CSV file? My code can be found in this Observable Notebook

Answer №1

Indeed, there exists a method in your code that actively re-renders when the selected value from a radio button list is changed. The issue with your current implementation does not pertain to bubbles or radius; instead, it revolves around a simple data referencing problem - specifically, how to merge arrays of data from multiple sources in Javascript.

NOTE: A post structured this way may not be effective on SO. While providing a link to a fiddle or observable as a secondary resource is beneficial, your focus on SO should concentrate on addressing the specific problem at hand. Putting in this effort typically aids in pinpointing the solution during the troubleshooting process. In this resolution, I will guide you through my debugging steps.

To begin, let's examine your initial attempt, showcasing the value of the currently selected property from the radio buttons. This starting point demonstrates your comprehension of the code and how the data loads into memory. Prioritize tackling the data issue before delving into the rendering of bubbles, which you have already shown how to accomplish.

Your current tooltip content fails to exhibit the value for the selected property (in yellow); instead, it displays the label of the chosen option (blue underline). Let's delve deeper into this by analyzing the current content logic:

<div>
  <h3>${hover.NAME}</h3>
  <div style="margin: 10px">
    <h4>CountryCode : ${hover.ISO_A2}  </h4> 
    <h4> ContinentCode : ${hover.CONTINENT}  </h>
    <h4>${parameter } : ${d3.format(",")(hover[p])}</h4>
  </div>
</div>

In this instance, 'hover' is an object containing properties 'ISO_A2' and 'CONTINENT,' which are not sourced from the referenced CSV file. These properties stem from the 'countries.json' file.

To verify this and explore available properties swiftly, we can adjust the tooltip content by adding the following lines:

<div>
  <h3>${hover.NAME}</h3>
  <div style="margin: 10px">
    <h4>CountryCode : ${hover.ISO_A2}  </h4> 
    <h4> ContinentCode : ${hover.CONTINENT}  </h>
    <h4>${parameter } : ${d3.format(",")(hover[p])}</h4>
    <h4>Expected Property: ${p}</h4>
    <smaller>${JSON.stringify(hover)}</smaller>
  </div>
</div>

If data capture is required rather than mere visual inspection, consider using 'console.log()' over dumping data onto the screen.

The original intention was evidently to make the data accessible as part of the data feed at that juncture. However, no action has been taken to integrate these two datasets until now. Let's rectify that promptly.

I suggest utilizing 'forEach' to iterate over 'countries' and amend each entry to incorporate the corresponding record from the CSV file entirely. By injecting the CSV data into the array of countries, we eliminate lookup overhead when accessing the information, ensuring a more deterministic approach.

An example snippet illustrating this integration follows:

// Convert the TopoJSON to GeoJSON
countries = {
  const geo = topojson.feature(map_layer, map_layer.objects.countries);
  geo.features.forEach(feature => {
    if(feature.geometry) {
      feature.centroid = centroid(feature);
    }
    let code = feature.properties.ISO_A2;
    let cData = country_data.find(x => x.CountryCode === code);
    feature.properties.csv = cData ?? {
  areasqkm: "",
  population: "",
  airports: "",
  gdpgrowthrate: "",
  inflationrate: "",
  unemploymentrate: "",
  popnbelowpoverty: "",
  medianage: ""
};
    return feature;
  });
  return geo;
}

Now that the data is incorporated, including a null record for streamlined error handling, cross-check its functionality by updating the tooltip content as follows:

<div>
  <h3>${hover.NAME}</h3>
  <div style="margin: 10px">
    <h4>CountryCode : ${hover.ISO_A2}  </h4> 
    <h4> ContinentCode : ${hover.CONTINENT}  </h>
    <h4>${parameter } : ${d3.format(",")(hover.csv[p])}</h4>
    <hr style="padding:0px"/>
    <smaller>
     Area Sqkm: ${d3.format(",")(hover.csv['areasqkm'])}<br/>
     Population: ${d3.format(",")(hover.csv['population'])}<br/>
     Airports: ${hover.csv['airports']}<br/>
     GDP Growth Rate: ${d3.format(",")(hover.csv['gdpgrowthrate'])}<br/>
     Inflation Rate: ${d3.format(",")(hover.csv['inflationrate'])}<br/>
     Unemployment Rate: ${d3.format(",")(hover.csv['unemploymentrate'])}<br/>
     Pop. Below Poverty: ${d3.format(",")(hover.csv['popnbelowpoverty'])}<br/>
     Median Age: ${hover.csv['medianage']}<br/>
    <smaller>
  </div>
</div>

Lastly, adapt property mapping paths in your bubble logic based on this modified setup. Mapping values to specific size domains often proves more practical than direct proportional shaping due to potential visibility issues with excessively small or large elements on the map.

For further insights into executing this methodology effectively, feel free to explore additional resources beyond the scope of this discussion space.

Answer №2

The example provided by Chris is functioning flawlessly and serves as an excellent solution to the query I posed. The step-by-step walkthrough was greatly appreciated, and I express my gratitude for the valuable answer and the effort put into clarifying my confusion.

In my attempt to quickly resolve the issue, I generated my own (.geojson) data from a (.CSV) file, which does work but not as efficiently as the aforementioned solution.

Considering the need for numerous parameters such as “Energy Consumption, production, Electricity production and consumption, Gold Reserve, Silver reserve ...and all economical data” for countries worldwide, creating (.csv) files for each set of data is impractical and time-consuming. Therefore, utilizing OWID DATA seemed like the most viable option to access the necessary datasets for a comprehensive visualization project. Despite attempting to implement the “fetch” method, I encountered difficulties in making it functional.

Any guidance on navigating me towards a suitable solution would be greatly appreciated. Furthermore, assistance in configuring parameter names according to OWID database specifications and fetching data based on button clicks, similar to how it currently functions with my JSON file, would be highly beneficial. This way, adjusting the bubble radius upon button click and displaying selected parameter information when hovering over the bubbles would enhance the overall user experience.

You can find my Notebook showcasing the implementation using (.geojson data) here: Bubble Cluster.

Ps: Please note that the bubbles only appear after selecting a parameter :)

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the best way to smoothly transition in an image that is dynamically set using Angular?

I am using Angular to set a background image for my page, but the current loading behavior is not visually appealing as the image loads from top to bottom. I would like to implement a fade-in effect or load the image from a blurry view to enhance the user ...

php issue with sorting an array using asort

Here is the array I am working with: $myarr = array( 4 => 3, 2 => 9, 7 => 8, 1 => 1 ); After using the asort function on $myarr: asort($myarr); The new order of $myar ...

React.js TypeScript Error: Property 'toLowerCase' cannot be used on type 'never'

In my ReactJS project with TSX, I encountered an issue while trying to filter data using multiple key values. The main component Cards.tsx is the parent, and the child component is ShipmentCard.tsx. The error message I'm receiving is 'Property &a ...

Tips on creating a button that, upon clicking, triggers the download of an Excel file using PHPSpreadsheet

I am trying to figure out how to create a button that, when clicked, will download an Excel file named b1b5.xls with some specified values added. Here is the code I have so far: <html> <head> </head> <body> <center> < ...

Issue: Catching errors in proxy function calls

I am currently using Vue 3 along with the latest Quasar Framework. To simplify my API calls, I created an Api class as a wrapper for Axios with various methods such as get, post, etc. Now, I need to intercept these method calls. In order to achieve this ...

Issue with Knockout.js: Parsing error in bindings - SyntaxError: Unexpected token `};`

Take a look at this example. I've tried to simplify it as much as possible, but I'm still struggling to figure out where I went wrong. Any help would be greatly appreciated )) P.S Stack Overflow requires code, not just a link to jsfiddle. H ...

Navigating through an ajax-based webpage entirely with selenium webdriver

I have attempted to scroll a page entirely using the following code: var scrollToBottom = function() { window.scrollTo(0, Math.max(document.documentElement.scrollHeight, document.body.scrollHeight, document.documentElement.clientHeight)); }; window.on ...

Sidebar navigation text shifting during transition

I attempted to modify the CSS and JavaScript, but unfortunately, it had no effect and actually caused more issues. I adjusted the position and display properties in the CSS, but it seems that wasn't the root of the problem. If anyone could offer assis ...

Coloring a table in vue.js based on performance rankings

I'm facing an issue with sorting my data performance in vue js. Here is the script I have created so far: <template> <div> <div class="row"> <h2> Campaign Performance </h2> <table class=&q ...

Is there a way to invoke a JavaScript function specifically for a given link?

I am trying to make the JavaScript only apply to a specific A LINK (#tornado,_bar -> ul -> li -> a links) when clicked, but it is applying to all A links. How can I specify the particular link in the JS? The JavaScript code is not functioning cor ...

Converting a string to HTML in Angular 2 with proper formatting

I'm facing a challenge that I have no clue how to tackle. My goal is to create an object similar to this: { text: "hello {param1}", param1: { text:"world", class: "bla" } } The tricky part is that I want to ...

Ways to determine if an element in one result array exists in another result array

I have coded the following in my program: <?php session_start(); $_SESSION['user_id']=201102887; $con = mysqli_connect('localhost', 'root', ''); if(!$con) { die("not ok"); } mysqli_select_db($con,"uoh"); $q1 ...

Transform the date and display it for every element in a PHP array

I am currently working on outputting a list of dates in the format 2012-06-18 to an XML file. foreach ($result_array as $date) { echo "<market date=\"".$date['saledate']."></market>\n"; } Everything seems to be working ...

Transferring request body data between routes in Express: A guide

In my MERN application, there are two specific routes in place. The first route is designated for 'Storing Data' and is referred to as the 'data' route. The second route is used for 'Register User' functionalities and is known ...

transferring scoped model information to the controller

When using AngularJS, my view is structured like this: <div class="sli1" ng-init="values=[10,20,30,40,50]" <div class="sli2" ng-init="values2=[10,20,30,40,50]" I am attempting to send the initial data models back to the controller for retrieva ...

Locate records that meet criteria in various fields within a nested array in MongoDB

Suppose I have an array of objects (let's call it array A) and I am looking for a way to query MongoDB to find documents where one field matches a property in object 1 from array A, and another field matches a different property in the same object. N ...

JavaScript button for displaying and hiding all content in one click

I came across a tutorial on W3Schools that showed how to create collapsibles, and I thought it would be great to have buttons that could expand or collapse all at once. I've been trying to implement this feature using the code provided in the tutorial ...

A guide on tallying values in an array and organizing them into an object within a fresh array using Javascript

I have a large array filled with various words, and I am aiming to create a new array that organizes each word along with the number of times it appears as properties within an object. Here is an example: const arrayWithWords = [`word1`, `word2`, `word5`, ...

TinyMCE generates HTML code with embedded tags

Hey there, I'm currently facing an issue with TinyMCE that I just can't seem to solve. I've browsed through some related posts but haven't found a solution that works for me... For example: When I input something in my back office, ...

What's the quickest method for duplicating an array?

What is the quickest method for duplicating an array? I wanted to create a game, but I found that Array.filter was performing too slowly, so I developed a new function: Array.prototype.removeIf = function(condition: Function): any[] { var copy: any[] ...