Nonlinear Scaling in D3.js Line Chart

My task is to generate a line chart where the y-axis domain ranges from 1.01 to 1000. The tick values change at the following intervals along the axis:

  • 1.01 to 2, tick = 0.01
  • 2 to 3, tick = 0.02
  • 3 to 4, tick = 0.05
  • 4 to 6, tick = 0.1
  • 6 to 10, tick = 0.2
  • 10 to 20, tick = 0.5
  • 20 to 30, tick = 1
  • 30 to 50, tick = 2
  • 50 to 100, tick = 5
  • 100 to 1000, tick = 10

In the chart image, all the paths above x = 4.0 are twice as long as they should be. I have been exploring non-linear scales but haven't found a viable solution yet.


const svg = d3.select('#line_chart_svg');
const width = +svg.attr('width');
const height = +svg.attr('height');

const margin = { top: 20, bottom: 30, right: 20, left: 50 };
const innerWidth = width - margin.left - margin.right;
const innerHeight = height - margin.top - margin.bottom;

const render = priceTimeData => {

const xValue = d => d.timeStamp;
const yValue = d => d.price;

const xScale = d3.scaleTime()
    .domain(d3.extent(priceTimeData, xValue))
    .range([0, innerWidth])
    .nice();

const yScale = d3.scaleLinear()
    .domain(d3.extent(priceTimeData, yValue))
    .range([innerHeight, 0]);
    console.log(yScale)

// Declare g and adjust size
const g = svg.append('g')
    .attr('transform', `translate(${margin.left}, ${margin.top})`);

// Setup xAxis 
const xAxis = d3.axisBottom(xScale);
const xAxisG = g.append('g').call(xAxis)
    .attr('transform', `translate(0, ${innerHeight})`);

// Setup yAxis
const yAxis = d3.axisLeft(yScale)
    .tickSize(-innerWidth);
const yAxisG = g.append('g').call(yAxis);

const lineGenerator = d3.line()
    .x(d => xScale(xValue(d)))
    .y(d => yScale(yValue(d)));

g.append('path')
.attr('class', 'line_path')
    .attr('d', lineGenerator(priceTimeData));

}

const priceTimeData = d3.csv('data/priceTime.csv').then(data => {
data.forEach(d => {
    d.price = +d.price
    d.timeStamp = new Date(d.timeStamp);
})
render(data)
});

https://i.sstatic.net/UDM2T.png

Answer №1

If you want D3 to handle different scales for each period, manual tick value creation is necessary.

To achieve this, you can define the tick values as follows:

var tickValues = [
      {"lower": 1.01, "upper": 2, "interval": 0.01},
      {"lower": 2, "upper": 3, "interval": 0.02},
      {"lower": 3, "upper": 4, "interval": 0.05},
      {"lower": 4, "upper": 6, "interval": 0.1},
      {"lower": 6, "upper": 10, "interval": 0.2},
      {"lower": 10, "upper": 20, "interval": 0.5},
      {"lower": 20, "upper": 30, "interval": 1},
      {"lower": 30, "upper": 50, "interval": 2},
      {"lower": 50, "upper": 100, "interval": 5},
      {"lower": 100, "upper": 1000, "interval": 10}
    ]

    let tickArray = []
    let currentTickValue = 0

    tickValues.forEach(function(t){

      currentTickValue = t.lower

      for (var i = t.lower; i < t.upper; i = i + t.interval) {

        currentTickValue = currentTickValue + t.interval
        currentTickValue = (Math.floor(currentTickValue * 100))/100
        tickArray.push(currentTickValue)

      }
    })

    let yScale = d3.scaleLinear()
        //etc

    let yAxis = d3.axisRight(yScale)
        .tickValues(tickValues)

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

Perform Action Only When Clicking "X" Button on JQuery Dialog

I have a dialog box with two buttons, "Yes" and "No", which trigger different functions when clicked. $('#divDialog').dialog({ modal:true, width:450, resizable: false, buttons: [{ text: 'Yes', ...

I am interested in redirecting command line output to a file rather than displaying it in the standard

Is it possible to use child-process and spawn in node.js to execute a command and save the output to a file instead of displaying it on the standard output? test.js const expect = require('chai').expect; const { spawn } = require('child_pr ...

Is it possible to run a Vue file autonomously, similar to an HTML file

When it comes to running html, we can rely on mainstream browsers such as Chrome. But is there a similar tool for vue files, like the browsers designed for html? ...

Creating an interactive map on WordPress: A step-by-step guide

I have successfully created a clickable image on Codepen <div style="width: 1000px; height: 993.73px;"> <img src="https://www.dyfedarchaeology.org.uk/wp/wp-content/uploads/Testmap.svg" alt=&q ...

Save the text entered into an input field into a Python variable

Is there a way to retrieve the text from input fields that do not have a value attribute using Selenium? The issue is that these fields are populated automatically, possibly through JavaScript, upon page load and the text does not appear in the HTML source ...

Is there a way for me to delay sending an immediate response until the asynchronous loop has completed?

Currently trying to implement something similar to the code snippet below. I suspect that the issue lies within the asynchronous call as it seems like the response I am getting is always an empty array, despite the API returning data. As a beginner in th ...

The mute feature in Discord.js along with setting up a muterole seems to be malfunctioning and encountering errors

Currently, I am working on implementing a mute command feature. The main goal is to have the bot automatically create a role called Muted if it doesn't already exist, and then overwrite the permissions for every channel to prevent users with that role ...

What is the best way to establish a global database connection in express 4 router using express.Router()?

Is there a way to pass a global variable in Node.js from a file to a module? I have been attempting to do so with a 'db' variable that represents a MongoDB connection. I tried copying the content of my file for the connections, but it didn't ...

The function addEventListener is not found

When a button is pressed, I want to add a value into a container by adding an event listener. <div className="grid-container"> <div> <button id="redBet" className="redButton" onclick={thi ...

Capture individual frames from angular video footage

Trying to extract frames from a video using Angular has been quite challenging for me. While browsing through Stack Overflow, I came across this helpful post here. I attempted to implement the first solution suggested in the post, but unfortunately, I was ...

Is it possible to enlarge a div using "display: table-cell" property when clicked on?

There are various components displayed on my webpage: I require all components to have a minimum height of 150px. If the height is less than 150px, I want to vertically center their text. In case the height exceeds 150px, I aim to truncate the text at 15 ...

Catching the Selenium NoSuchElementError in JavaScript is impossible

Update: It's puzzling why this was marked as answered since the linked questions don't address the issue at hand and do not involve Javascript. My objective is to detect this error, rather than prevent it, given that methods like invisibilityOfEl ...

Create a custom chrome browser extension designed specifically for sharing posts on

I'm working on creating a basic chrome extension that features an icon. When the icon is clicked, I want the official Twitter window to pop up (similar to what you see here). One common issue with existing extensions is that the Twitter window remains ...

Exploring the functionality of the JavaScript Date constructor in relation to

Will using new Date('2015-01-01') provide me with the exact moment equivalent to 2015-01-01T00:00:00Z? ...

Angular login/signup modal/dialog component for seamless user authentication

Currently, I am working on adding a login/signin dialog to my app similar to the one used by Medium. After doing extensive research online, I have decided to use the $modal from angular ui-bootstrap for this. Can anyone please recommend a tutorial that wil ...

Issues with expanding all nodes in the Angular Treeview function by Nick Perkins in London are causing difficulties

Currently utilizing the angular treeview project found here: https://github.com/nickperkinslondon/angular-bootstrap-nav-tree After examining the functionality, it seems that this treeview is lacking search capabilities. To address this limitation, I deci ...

Inject a value sent from response.render directly into the script tag

Below you will find a pug snippet. I am looking for a way to dynamically insert the user value into the chatConfig object. script. var chatConfig = { user : 'foo', pass : 'bar', } When rendering from my Express applicatio ...

Selecting the checkbox will activate the POST endpoint

I am working on a nodejs/express app and looking for a way to update my database using a POST route when a checkbox is clicked. The challenge I am facing is that I want to avoid using a submit button or jQuery. I am currently using a Bootstrap4 checkbox ...

Connect the AngularJS data model with a Foundation checkbox element

I am attempting to link a model (a boolean value) to a checkbox created with Foundation (Zurb). I have created a small demonstration displaying the issue: http://jsfiddle.net/JmZes/53/ One approach could involve simply creating a function that triggers o ...

SignalR error: A type conversion issue has occurred where it is not possible to directly convert a task returning an object to a string

I'm encountering an issue with my C# hub class where the JavaScript code is returning a System.Threading.Tasks.Task instead of a string. I need help modifying the JavaScript method to return an actual string. Below is the hub class: public String ge ...