Creating a dynamic multiline chart using data from a JSON file with D

Here is the JSON structure I am working with:

[{
    "city": "roma",
    "giornata": [{"hour": 0, "vscore": 2.691172504799798, "sscore": 37476.67912706408}, {"hour": 1, "vscore": 2.691172504799798, "sscore": 37476.67912706408}, {"hour": 2, "vscore": 2.6911859886310534, "sscore": 37477.76228681598}, {"hour": 3, "vscore": 2.692891756586413, "sscore": 37633.63745016247}, {"hour": 4, "vscore": 2.7490858604464163, "sscore": 40331.835034215015}, {"hour": 5, "vscore": 3.6348376398556206, "sscore": 29087.830074293775}, {"hour": 6, "vscore": 5.227711033677134, "sscore": 40951.01373374646}, {"hour": 7, "vscore": 5.437638544676074, "sscore...

I want to create a dynamic d3 line chart using this data, where each city represents a line on the chart. For example:

One line for "roma" with X-axis as "hour" and Y-axis as "vscore"

Another line for "milan" with X-axis as "hour" and Y-axis as "vscore"

The challenge is to create the d3.svg.line() dynamically from this JSON structure.

Currently, my code only works with a single line:

     var margin = {
            top: 20,
            right: 20,
            bottom: 50,
            left: 40
        },
        width = 900 - margin.left - margin.right,
        height = 290 - margin.top - margin.bottom;

    // Set the ranges
    var x = d3.scale.ordinal()
    .rangeRoundBands([0, width], .1);

    var y = d3.scale.linear().range([height, 0]);

    // Define the axes
    var xAxis = d3.svg.axis()
        .scale(x)
        .orient("bottom")
        .innerTickSize(-height)
        .outerTickSize(0)
        .tickPadding(10);

    var yAxis = d3.svg.axis()
        .scale(y)
        .orient("left").innerTickSize(-width)
        .outerTickSize(0)
        .tickPadding(10);


        // Define the line

// Struggling to generate lines dynamically
    var valueline = d3.svg.line()
    .interpolate("basis")
    .x(function (d) {
        return x(d.hour);
    })
    .y(function (d) {
        return y(d.vscore);
    });

        // Adds the svg canvas
        var svg = d3.select("#dailyChart")
            .append("svg").
            .attr("width", width + margin.left + margin.right)
            .attr("height", height + margin.top + margin.bottom)
            .append("g")
            .attr("transform",
                "translate(" + margin.left + "," + margin.top + ")");

                d3.json("data/ranking_sscore.json", function(error, data) {

                    data = data[0].giornata

                    data.forEach(function (d) {

                            d.hour = d.hour;
                            d.vscore = +d.vscore;

                    });
                    x.domain(data.map(function (d) {
                        return d.hour;
                    }))
                    y.domain([0, d3.max(data,
                        function (d) {
                            return Math.max(d.vscore);
                        })]);

                  // Add the valueline path.
                    svg.append("path")
                    .attr("class", "line")
                    .attr("d", valueline(data))
                    .style("stroke", 1);

                  // Add the X Axis
                    svg.append("g")
                        .attr("class", "x axis")
                        .attr("transform", "translate(0," + height + ")")
                        .call(xAxis)
                        .selectAll("text")
                        .attr("y", 15)
                        .attr("x", 0)
                        .attr("dy", ".35em")

                    // Add the Y Axis
                    svg.append("g")
                        .attr("class", "y axis")
                        .call(yAxis);

    })

Any help would be appreciated. Thank you!

Answer №1

Let D3 handle the looping process for you.

Below is a more updated version of D3v5 for your reference.

If you need to apply colors to multiple cities, you can utilize a color ordinal scale. Check out the commented line (remember to define color).

var margin = { top: 20, right: 20, bottom: 50, left: 40 },
    svgWidth = 900,
    svgHeight = 290,
    width = svgWidth - margin.left - margin.right,
    height = svgHeight - margin.top - margin.bottom;

// Data for roma and milan
var data = [{
    "city": "roma",
    ...
}, {
    "city": "milan",
    ...
}];

// Setting up the scales
var x = d3.scaleLinear().range([0, width]);

var y = d3.scaleLinear().range([height, 0]);

// Defining the axes
var xAxis = d3.axisBottom()
...
var yAxis = d3.axisLeft()
...

var valueline = d3.line()
...

// Creating the SVG element
var g = d3.select("#dailyChart")
...

// Function to draw the graph using provided data
drawGraph(null, data);

function drawGraph(error, data) {
    
    // Domain for scales
    x.domain(d3.extent(data[0].giornata, d => d.hour));
    y.domain([0, d3.max(data, d => d3.max(d.giornata, g => g.vscore) ) + 1 ]);

    // Adding X Axis
    g.append("g")
    ...

    // Adding Y Axis
    g.append("g")
    ...
    
    // Drawing paths for each city
    g.selectAll(".city")
    ...
}
.roma {
  fill:none;
  stroke:red;
}
.milan {
  fill:none;
  stroke:blue;
}
<script src="https://d3js.org/d3.v5.min.js"></script>
<div id="dailyChart"></div>

Answer №2

To begin, iterate through the main array before moving onto each "gionarta" array.

window.addEventListener('load', function () {
var margin = {
  top: 20,
  right: 20,
  bottom: 50,
  left: 40
},
  width = 900 - margin.left - margin.right,
  height = 290 - margin.top - margin.bottom;

// Establish ranges
var x = d3.scale.ordinal()
  .rangeRoundBands([0, width], .1);

var y = d3.scale.linear().range([height, 0]);

// Define the axes
var xAxis = d3.svg.axis()
  .scale(x)
  .orient("bottom")
  .innerTickSize(-height)
  .outerTickSize(0)
  .tickPadding(10);

var yAxis = d3.svg.axis()
  .scale(y)
  .orient("left").innerTickSize(-width)
  .outerTickSize(0)
  .tickPadding(10);

// Define the line

//Unable to dynamically retrieve the line here
var valueline = d3.svg.line()
  .interpolate("basis")
  .x(function (d) {
    return x(d.hour);
  })
  .y(function (d) {
    return y(d.vscore);
  });


// Create the svg canvas
var svg = d3.select("#dailyChart")
  .append("svg")
// .call(zoom)
  .attr("width", width + margin.left + margin.right)
  .attr("height", height + margin.top + margin.bottom)
  .append("g")
  .attr("transform","translate(" + margin.left + "," + margin.top + ")");


//Iterate over the main array first

data.forEach(function(el,index){
  items = el.giornata;
// then on each array giornata
  items.forEach(function (d) {

    d.hour = d.hour;
    d.vscore = +d.vscore;

  });
  x.domain(items.map(function (d) {
    return d.hour;
  }))
  y.domain([0, d3.max(items,
  function (d) {
    return Math.max(d.vscore);
  })]);

// Append the valueline path.
  svg.append("path")
    .attr("class", "line roma  "+data[index].city)
    .attr("d", valueline(items))
    .style("stroke", 1);

});

// Add the X Axis
svg.append("g")
  .attr("class", "x axis")
  .attr("transform", "translate(0," + height + ")")
  .call(xAxis)
  .selectAll("text")
  .attr("y", 15)
  .attr("x", 0)
  .attr("dy", ".35em")


// Add the Y Axis
svg.append("g")
  .attr("class", "y axis")
  .call(yAxis);
});


var data = [{
    "city": "roma",
    "giornata": [{"hour": 0, "vscore": 2.691172504799798, "sscore": 37476.67912706408}, {"hour": 1, "vscore": 2.691172504799798, "sscore": 37476.67912706408}, {"hour": 2, "vscore": 2.6911859886310534, "sscore": 37477.76228681598}, {"hour": 3, "vscore": 2.692891756586413, "sscore": 37633.63745016247}, {"hour": 4, "vscore": 2.7490858604464163, "sscore": 40331.835034215015}, {"hour": 5, "vscore": 3.6348376398556206, "sscore": 29087.830074293775}, {"hour": 6, "vscore": 5.227711033677134...
}, {
    "cit...

.milan{
  fill:none;
  stroke:blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

<div id="dailyChart"></div>

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

Keeping the script tag intact while adding it to the off-page DOM, and then injecting it into the page with jQuery

Currently, I am developing a never-ending scrolling mechanism that stores rows to include off-screen. My approach involves fetching the rows using $.get and inserting them into a new $('<div/>'). Then, whenever a new row is needed, I extra ...

AngularJS routing creates a conflict with Express routing

Having an issue with routing in Express, specifically when using code like this: app.get("/profile/:param", function (req, res) It seems to be conflicting with the path routing in AngularJS. For example, when a view in Angular with a URL like /profile/so ...

What is the best way to extract the delta from audio.currentTime?

I'm looking to synchronize my Three.js skeletal animation with an audio track. Typically, for animating the model, I would use the following code: var clock = new THREE.Clock(); function animate(){ var delta = clock.getDelta(); THREE.Animati ...

What is the best way to combine several lists into a single list?

In Java, I am attempting to consolidate multiple lists into one list. Below is the essential code snippet. String jsonText = buffer.toString(); // retrieves JSON data from URL JSONObject obj = new JSONObject(jsonText); // converts JSON object to array f ...

A step-by-step guide on incorporating a JSON array into a JSON file using Python

There is an array that looks like this: [{"Name": "abcd"}, {"Name": "efgh"}, {"Name": "hijk"}] The task at hand is to add this array to a JSON document. The JSON document in question resembles the following: {"widget": { "debug": "on", ...

Converting Java String to JSONObject in Android: Troubleshooting JSONP issue

Here is the code snippet I am working with: String json = request.excutePost("http://192.168.1.42:3000/login_client",urlParameters); JSONObject jsonObj = new JSONObject(json); The error displayed in logCat is as follows: org.json.JSONException: Value ...

Tips for utilizing the for each function within a for loop

Looking to showcase prices alongside each product based on their unique sku value, I've put together a price list. An array of data is being iterated through and pushed into the div container. var arr = [ { "sku": "552", "title": "orange", "pric ...

When I try to use this code in Eclipse, it runs without any issues. However, when I attempt to convert it into a

In my code snippet, I am reading a JSON array in Java to display the h1 value. It works perfectly in regular Java environment, but when I use it in Maven, I encounter a compile time error. [ERROR] \WebApp_maven\SimpleCar1\src\main&bsol ...

The Ionic application encounters an issue with the $stateParams being

Can someone assist me with resolving an issue related to ionic $stateParams? Here is the state configuration: .state('tabs.categories', { url: "/categories/:parentID", views: { 'categories-tab': { templateU ...

How can I transfer data to a different component in Angular 11 that is not directly related?

Within the home component, there is a line that reads ...<app-root [message]="hii"> which opens the app-root component. The app-root component has an @input and {{message}} in the HTML is functioning properly. However, instead of opening t ...

Utilizing a refreshed array of elements within a component directive

When working within a view, I am utilizing ng-repeat inside a directive to iterate over an array of objects from my controller. However, as the objects in the array undergo value changes, I encounter a dilemma when transitioning to a new instance of the sa ...

Recursion in Angular2 components causes emit to malfunction in child components

In my Angular2 (Typescript) app, I have integrated a 'tree' list of categories. This feature allows users to click on a category name, whether it's a main category or sub-category, and view the related products. The 'category-tree&apos ...

Handling multiple render calls and rerenders in React function components with setTimeout (best practice for firing multiple times)

Is there a way to optimize the Notification component in my App, so that the setTimeout function is only initialized once even if multiple notifications are pushed into the state? function Notification(props) { console.log("Notification function compone ...

Executing JavaScript code within a class object using ASP-VB

I'm looking to create a function that will show a Javascript-based notification. I already have the code for the notification, but I'm trying to encapsulate it in a class library as a function. However, I am unsure about what to return from the f ...

Transforming irregular JSON data with System.Text.Json

When working with the service, it returns an empty array instead of null for objects. This causes issues during deserialization. Encountered System.Text.Json.JsonException : The JSON value could not be converted to Models.Error. Path: $.errors | LineNumb ...

HTTP AJAX request automatically switching to HTTPS

Currently, I am facing an issue with making an AJAX POST request from a Chrome extension to my AWS app. The request is defined over http instead of https. I have made sure to incorporate the necessary CORS headers in my AWS app as seen below: app.use(func ...

What could be causing the embedded dropdown to automatically select the initial option every time?

I am encountering an issue with a page that includes an html table rendered using node with express and ejs. The table contains a select dropdown in one of the cells, and it populates correctly with the right values. However, regardless of which option I ...

Exploring the variations between getRequestHandler and render functions in Custom Next.js applicationsIn a

Greetings, I found it quite unexpected that there is a lack of information available on the functionalities of the getRequestHandler and render functions within the next package. As I am in the process of setting up a custom server, I am curious about wh ...

Go through the array and perform an action once you reach the final occurrence

I have a challenge where I need to iterate over an array that contains data fetched from a .txt file on a server. The content of the file appears as follows: 12345|Test message 55555|55555's message 12345|Test message 2 After making a simple GET req ...

Transition smoothly with a fade effect when switching between models

I am in the process of creating a basic query system. While I can display questions one at a time, I am looking to incorporate transitions when switching between questions. To further illustrate my issue, I have set up a Plunker demonstration: http://plnk ...