Exploring Time Scaling and Range Adjustment in D3 Barcharts

My dataset looks something like this:

dateRange = [
 { date: 2017-03-23, value: 10 },
 { date: 2017-03-25, value: 15 },
 { date: 2017-04-01, value: 13 },
 { date: 2017-04-02, value: 19 }
];

The results can be viewed here: https://embed.plnkr.co/iOBAuCZmoMePL5P3Jwr4/

I am interested in creating a barchart with an x-axis that spans the entire date range (from March 23rd to April 2nd in this case). This means that every single day between these two dates should be displayed on the x-axis and set to a value of 0.

I would like to accomplish this without altering the original data source. I am aware that d3.js can handle this task using d3.time.scale. However, since rangeBand is not available when using d3.time.scale, I am struggling to determine the correct width for the barchart.

Thank you in advance for your assistance.

Answer №1

To work with an ordinal scale, create an array that includes all dates from the start date to the end date:

var dateArray = d3.time.days(d3.min(dataset, function(d) {
    return d.date
}), d3.time.day.offset(d3.max(dataset, function(d) {
    return d.date
}), +1));

Use this array for defining your domain.

Note that since the last value in d3.time.days is exclusive, an offset is necessary to add an extra day to the end date.

Below is your updated code:

var margin = {
     top: 20,
     right: 0,
     bottom: 21,
     left: 30
   },
   height = 300,
   width = 400,
   w = width - margin.left - margin.right,
   h = height - margin.top - margin.bottom;
 var parseDate = d3.time.format("%Y-%m-%d").parse;

 dataset = [{
   date: '2017-03-23',
   value: 10
 }, {
   date: '2017-03-25',
   value: 15
 }, {
   date: '2017-04-01',
   value: 13
 }, {
   date: '2017-04-02',
   value: 19
 }];
 dataset.forEach(function(d) {
   d.date = parseDate(d.date);
 });

 var svg = d3.select('body')
   .append('svg')
   .attr("width", '100%')
   .attr("height", '100%')
   .attr("viewBox", "0 0 " + width + " " + height)
   .attr("preserveAspectRatio", "xMinYMin meet")
   .append("g")
   .attr("transform",
     "translate(" + margin.left + "," + margin.top + ")");

 var dateArray = d3.time.days(d3.min(dataset, function(d) {
   return d.date
 }), d3.time.day.offset(d3.max(dataset, function(d) {
   return d.date
 }), +1));

 var x = d3.scale.ordinal().rangeRoundBands([0, w], .2, .02);
 var xAxis = d3.svg.axis()
   .scale(x)
   .orient("bottom")
   .tickSize(0)
   .tickPadding(5)
   .tickFormat(d3.time.format("%d/%b"));
 x.domain(dateArray);

 svg.append("g")
   .attr("class", "axis easting")
   .attr("transform", "translate(0," + h + ")")
   .call(xAxis)
   .selectAll("text")
   .style("text-anchor", "middle");

 var y = d3.scale.linear().range([h, 0]);
 var yAxis = d3.svg.axis()
   .scale(y)
   .orient("left")
   .ticks(6);
 y.domain([0, d3.max(dataset, function(d) {
   return d.value;
 })]);

 svg.append("g")
   .attr("class", "axis northing")
   .call(yAxis)
   .selectAll("line")
   .attr("x2", w)

 svg.selectAll('rect')
   .data(dataset)
   .enter()
   .append('rect')
   .attr('width', function(d, i) {
     return x.rangeBand();
   })
   .attr('height', function(d, i) {
     return h - y(d.value);
   })
   .attr('x', function(d, i) {
     return x(d.date);
   })
   .attr('y', function(d, i) {
     return y(d.value);
   })
   .attr('fill', 'blue');
.chart {
  width: 450px;
  height: 300px;
  margin: 20px;
}

.axis {
  font-size: 10px;
  line-height: 16px;
}

.northing line {
  stroke: #F2F2F2;
}

line {
  fill: none;
  stroke: #727272;
}

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

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

Sending JSON data from the primary window to the secondary window in Electron - A step-by-step guide

I am currently working with a set of 3 files. index.html: ... <a href="#" onclick="fetch(function(data) {console.log(data); subWindow(data)})">subWindow</a> ... The fetch() function retrieves a callback in JSON format. subWindows.js: let m ...

The directive code takes precedence over the controller code and is executed first

A custom directive has been implemented and is utilized as shown below: <div car-form car="car" on-submit="createCar(car)"></div> This directive is used on both the new and edit pages, each with its own controller. The EditCarController retri ...

Guide on traversing and modifying properties within a intricate JSON structure using Node.js

Is there a way to update the value of "message" for "chatTemplateId":"5" and "mid":"b" to "Test2" in the JSON data below using node-js/javascript? In C# I would have used LINQ, but I'm not sure how to achieve this in an optimized manner in JavaScript/ ...

Getting POST data in Next.js is a common task that requires understanding of how the

I am currently working on a form validation project using the App Router within Next.js. // app/register/page.tsx export default function Register(context: any) { console.log("Register page", context.params, context.searchParams); return ...

Dealing with a surprise JSON error in Express.js using Javascript

Dealing with Unexpected JSON in my express js application using try and catch. I attempted to achieve this as follows: try{ let body = JSON.parse(req.body); }catch(e){ res.json({ error:e }) } However, the Unexpected JSON error is not caught in ...

Enhancing data rendering by incorporating extra verifications through the logical AND operator to prevent crashes upon page refresh

Upon refreshing the page, my app crashed. The issue stemmed from the page loading faster than my data, prompting me to include additional checks using the logical AND operator. While effective in preventing crashes, this approach seems laborious and begs t ...

Creating a dynamic shift in background color

Is it possible to use jQuery to slowly change the color of diagonal lines in a background styled with CSS, while also adding a fading effect? I have created a fiddle with the necessary CSS to display a static background. You can view it here: http://jsfid ...

Please indicate the decimal separator for the Number() function

UPDATE : TITLE IS MISLEADING as testing showed that Number() returned a dot-separated number and the HTML <input type="number"/> displayed it as a comma due to locale settings. I changed to using an <input type="text"/> and filtered keydown lik ...

Encountering the error message "Module 'request' not found" despite the fact that I've already included the request module

I'm currently facing an issue with my Cloud Function that involves using the request library. After installing the request package using npm install request, I noticed it's located in the node_modules directory, just like all the other packages: ...

Creating a bespoke validation in AngularJS to verify if the selected date falls within a specific range of weekdays

Hey there! I'm looking to enhance the validation process for a date input field in a unique manner. Currently, my default validation setup looks like this: <div> <input type="text" name="firstName" ng-model="appointmentForm.firstName" ng- ...

Retrieve JSON data and use a button to sort and display markers on a Google Map

Is it possible to modify my function in order to use different PHP files with separate buttons without duplicating the code? Currently, I have a function that displays markers on an external HTML page when a button is clicked. The data is retrieved from fi ...

Leveraging the power of $lookup and $mergeObjects in aggregation

I'm looking to join a collection. Previously, I used only lookup to get separated fields that are joined, but now I need the results similar to MySQL join. I have tried using $lookup and $mergeObjects for this action, but they are not working well. H ...

Matching patterns with regular expressions in Javascript

There's a string that goes like this: |Africa||Africans||African Society||Go Africa Go||Mafricano||Go Mafricano Go||West Africa|. I'm attempting to craft a regular expression that will only match terms containing the word Africa or any variation ...

Please refrain from refreshing the page multiple times in order to receive updated data from the database

Currently, I have created a countdown timer from 00:60 to 00:00. However, once the timer reaches 00:00, I am looking to refresh the page only once in order to retrieve a new value from the database. Does anyone have any suggestions on how to achieve this ...

CSS Testimonial Slider - Customer Feedback Display

I'm having some issues with the code below: <div id="box"> <div class="wrapper"> <div class="testimonial-container" id="testimonial-container"> <div id="testimon ...

Tips for incorporating jQuery to load Rails form partials and submit them as a single form:

Trying to improve the readability of my Rails HTML code, I decided to extract certain portions into partials and then used jQuery to render these partials. However, a problem arose where the form seems disconnected after implementing this approach. It appe ...

What is the best way to initiate a function from within another function while working with ReactJS?

Seeking guidance on how to trigger a Redux state change by calling a function from another function using the onClick event. Currently, I am able to invoke the Jammingmenu upon clicking an icon, however, no action is performed or alert displayed. Any assis ...

Utilize angular to call a function when navigating

Having an issue with ChartJS while creating a chart using angular. The problem arises when navigating to a new page and then back to the original one, as the JavaScript is not triggered again. Is there a way to automatically invoke a JavaScript function o ...

"Emphasize menu items with an underline as you navigate through the

I am using Gatsby with React and have a navigation menu with links. I would like to make it so that when a link is clicked, a border bottom appears to indicate the current page, rather than only on hover. <ul className="men" id="menu"> ...

What are some tips for utilizing the "bottom-row" slot within the "b-table" component in bootstrap-vue?

I am working on a component that utilizes the bootstrap-vue b-table component. My goal is to create a bottom row that displays the sum of each column in the table. However, I encountered an issue where the bottom-row only fills the first column, leaving ...