Mapping geographic coordinates with a null projection using D3

With d3.geo.path having a null projection due to TopoJSON already being projected, it can be displayed without any additional transformation. My goal is to plot data in the format of [longitude, latitude] on a map.

Here is a simplified version of my code:

var width, height, path, svg;

width = 960;
height = 600;
path = d3.geo.path().projection(null);
svg = d3.select('.viz').append('svg')
    .attr('width', width)
    .attr('height', height);

d3.json("counties.json", function(error, us) {
    svg.append('path')
        .datum(topojson.mesh(us))
        .attr('d', path);
});

svg.selectAll('.pin')
    .data(ds) // e.g., ds = {[12.521, 15.312], [616.122,-31.160]}
    .enter().append('circle', '.pin')
    .attr('r', 3)
    .attr('transform', function (d) {
        return 'translate(' + path([
            d.longitude,
            d.latitude
        ]) + ')';
    });

While debugging, I confirmed that the data is fetched properly. However, I encounter an error stating that "path([d.longitude, d.latitude])" is undefined. Both "d" and "path" contain the necessary values. This issue seems related to the null projection.

How can I address this problem?

------- EDIT ------- Following Ben Lyall's suggestion, I removed "path" from the selectAll statement and placed it inside the .json() function. I also corrected the sample data in ds. Below is the updated code.

The map now displays correctly without any console errors, but the circles are not visible on the map itself.

var width, height, path, svg;

width = 960;
height = 600;
path = d3.geo.path().projection(null);
svg = d3.select('.viz').append('svg')
    .attr('width', width)
    .attr('height', height);

d3.json("counties.json", function(error, us) {
    svg.append('path')
        .datum(topojson.mesh(us))
        .attr('d', path);

    svg.selectAll('.pin')
        .data(ds) // e.g., ds = [{longitude: 12.521, latitude: 15.312}, {longitude: 616.122, latitude: -31.160}]
        .enter().append('circle', '.pin')
        .attr('r', 3)
        .attr('transform', function (d) {
            return 'translate(' +
                d.longitude + ',' + d.latitude +
            ')';
        });
});

------- EDIT ------- The solution involved implementing Ben Lyall's suggestion and considering the existing projection for the pins. Since the projection is null in the code, a new one matching the map projection had to be created for the pins' transform. Here is the final solution:

var width, height, path, projection, svg;

width = 960;
height = 600;
path = d3.geo.path().projection(null);
projection = d3.geo.albersUsa().scale(1280).translate([width/2, height/2]);
svg = d3.select('.viz').append('svg')
    .attr('width', width)
    .attr('height', height);

d3.json("counties.json", function(error, us) {
    svg.append('path')
        .datum(topojson.mesh(us))
        .attr('d', path);

    svg.selectAll('.pin')
        .data(ds)
        .enter().append('circle', '.pin')
        .attr('r', 3)
        .attr('transform', function (d) {
            return 'translate(' +
                projection([d.longitude, d.latitude]) +
            ')';
        });
});

Answer №1

When adjusting the position of your .pin elements, why are you incorporating the path function within your translate? The use of path is unnecessary as the d.latitude and d.longitude values are likely already in pixel coordinates due to prior projection. Thus, you should be able to utilize these values directly.

Additionally, it's advisable to place that portion of your code inside the d3.json handler instead of outside. This ensures that it runs synchronously after your data has been properly set (this may be the main issue with your code rather than the misapplication of path).

While a concrete example would provide clarity, consider implementing the following:

var width, height, path, svg;

width = 960;
height = 600;
path = d3.geo.path().projection(null);
svg = d3.select('.viz').append('svg')
    .attr('width', width)
    .attr('height', height);

d3.json("counties.json", function(error, us) {
    svg.append('path')
        .datum(topojson.mesh(us))
        .attr('d', path);

    svg.selectAll('.pin')
        .data(ds) // e.g. ds = {[12.521, 15.312], [616.122, -31.160]}
        .enter().append('circle', '.pin')
        .attr('r', 3)
        .attr('transform', function (d) { 
            return 'translate(' + d.longitude + "," + d.latitude + ')';
        });
});

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

A Vue filtering feature that consistently adds 5 additional elements upon each use

I was wondering, how can I create a computed property filter function that always adds 5 more elements to the current array? Here are more details: Template: <span class="box-content" v-for="item in activeItems" :key="item.id"> <img class=" ...

Building a Sharepoint application with Angular 2 using the CLI and Webpack

Trying to deploy an Angular 2 CLI App to a SharePoint 2013 site has been quite challenging. The app works fine when embedded via a Content Editor Webpart, but the console throws an exception: zone.js:158 Uncaught Error: Sys.ParameterCountException: Parame ...

My Vue frontend project is encountering an error during compilation that states "this relative module module was not found."

I have created a vue frontend to interact with my spring backend, which is working well. However, when I compile the frontend, it compiles to 98% and shows an error message: ERROR Failed to compile with 1 error 11:24:51 The relative module was not foun ...

Encountering net::ERR_CONNECTION_RESET and experiencing issues with fetching data when attempting to send a post request

I am facing a React.js task that involves sending a POST request to the server. I need to trigger this POST request when a user clicks on the submit button. However, I keep encountering two specific errors: App.js:19 POST http://localhost:3001/ net::ERR_CO ...

Ways to display pictures by invoking an API within the antd item list container

Upon page load, I am fetching images from a database using an API. Now, my goal is to display these images within a Modal in Antd. How can I accomplish this with the code snippet below? const MyVehiclePage = (props) => { useEffect(() => { co ...

Advancing through time with progress

How can I display a progress indicator for events in fullcalendar based on the current time by changing their color dynamically in HTML? Thank you for your help! ...

Increased impact of dynamically added elements following page transition

After implementing dynamic functionality from jQuery in my code, I encountered an issue where if I navigate back one page and then return to the original page containing the added elements, they seem to trigger twice upon clicking. To troubleshoot, I incl ...

Improving List performance with React.cloneElement

I am uncertain about the usage of React.cloneElement within a List component. Is it recommended to avoid using it, especially when dealing with a large number of elements in the list? Does React.cloneElement cause unnecessary re-renders that can be optimal ...

Using an ng-repeat directive alongside an if condition in Angular

My website contains a vast array of 30 articles, previously represented by around 300 lines of HTML code, but now condensed to just 10 lines with angularjs. However, certain articles hold special significance and require specific display criteria. Check ou ...

In TypeScript, use a Record<string, any> to convert to {name: string}

I have developed a custom react hook to handle API calls: const useFetch: (string) => Record<string, any> | null = (path: string) => { const [data, setData] = useState<Record<string, any> | null>(null); var requestOptions: Requ ...

Is there a way to showcase a row of images when a button is clicked?

I am looking to create a functionality where pressing one of the buttons shown in the image below will toggle visibility of specific sections containing 3 images each. For example, clicking on "Tapas" will only display tapas images and hide main course ima ...

The Next.js website displays a favicon in Chrome, but it does not appear in Brave browser

As I work on my debut next.js website, I am configuring the favicon in index.js like this: <Head> <title>Create Next App</title> <link rel="icon" href="/favicon.ico" /> </Head> Initially, all my source ...

Error in delete operation due to CORS in Flask API

After successfully developing a rest api in Flask and testing all api endpoints with Postman, I encountered an issue while working on an application in Javascript that consumes the resources of my api. The problem lies in consuming an endpoint that uses t ...

Converting line breaks into a visible string format within Angular

After thorough research, all I've come across are solutions that demonstrate how to display the newline character as a new line. I specifically aim to exhibit the "\n" as a string within an Angular view. It appears that Angular disrega ...

Sorting data by percentages in AngularJS

I am currently facing an issue with sorting percentages in a table column. Despite using methods like parseFloat and other AngularJS (1.5.0) sorting techniques, the percentages are not being sorted as expected. [ {percentage: 8.82} {percentage: 0. ...

PhpStorm flawlessly detects ES7 type hinting errors

For my project, I have implemented TypeScript. While JavaScript's array includes() function has been valid since ECMA6, setting the lib parameter in tsconfig to "es6" results in a non-fatal error being thrown in the browser console when using the foll ...

Creating a column for dates using the js-xlsx library

After multiple attempts using js-xlsx, I have encountered an issue when trying to write a XLSX file with a Date column. Whenever I open the file in Excel 2010, the date is displayed as the number of days from a specific origin rather than in the desired fo ...

What is the best way to generate a random string output from an object in JavaScript?

I'm struggling with extracting a random value from the object provided below, can anyone help me out? const hellos = { English: "Hello", Japanese: "Konnichiwa", German: "Hallo", Spanish: "Hola", Arabic: "Ah ...

How can I dynamically retrieve the width of an image in React as the screen size changes?

I have successfully implemented an image hover effect on my website. When I hover over a certain text, an image appears. The image is responsive, but I am facing an issue where I want the width of the text to be equal to the width of the image. When I resi ...

The attribute 'positive_rule' is not found within the structure '{ addMore(): void; remove(index: any): void;'

data() { return { positive_rule: [ { positive_rule: "", }, ], }; }, methods: { addMore() { this.positive_rule.push({ positive_rule: "", }); }, ...