JSFiddle here: https://jsfiddle.net/ayyrickay/k1crg7xu/47/
My code is a bit of a mess right now, but essentially, I have two choropleths, and I want to render a multiline chart based on the choropleth data - I just have no idea how to wrangle the data to make it work.
The line chart is be a composite line chart. One line would be New Yorker circulation data, the other would be Saturday Evening Post circulation data. The y axis is issue_circulation, the x axis is actual_issue_date
In the current implementation I’ve set up two crossfilters (one for each data set) and I’m creating a dimension for the choropleth and one for the line chart. The choropleths render properly, but I’ve yet to get the line charts to render. I can’t tell if its because of the format of my data ({key: date, value: y-axis-value}) or if my implementation of crossfilter is just too janky. I'm trying to understand based on other StackOverflow questions, but nothing I've tried seems to work (this includes prefiltering the data like I'm doing now, creating two different crossfilters and separate dimensions, trying to be meticulous apart parsing dates, etc.)
When you're using a time scale for the X axis, the keys of your group should be Date objects. So it won't work to format the dates as strings when creating the dimensions & groups; instead just use raw Date objects.
Since Dates are slow, I suggest doing this as a data preprocessing step:
data.forEach(function(d) {
d.actual_issue_date = new Date(d.actual_issue_date);
})
Then your dimension key functions just extract the date object:
const dimension1 = title1Circulation.dimension(d => d.actual_issue_date)
const lineChartYear1 = title1Circulation.dimension(d => d.actual_issue_date)
const lineChartYear2 = title2Circulation.dimension(d => d.actual_issue_date)
This ends up looking kind of messy, because the Saturday Evening Post data fluctuates a lot by week:
Zoomed in:
Assuming this isn't a data cleaning problem (kind of looks like it?), one way to improve the display would be to aggregate by month:
const circulationGroup1 = lineChartYear1.group(d => d3.timeMonth(d)).reduceSum(d => d.issue_circulation)
const circulationGroup2 = lineChartYear2.group(d => d3.timeMonth(d)).reduceSum(d => d.issue_circulation)
composite
.xUnits(d3.timeMonths)
This rounds the group key down to the beginning of each month, adding together all the values for each month.
Still kind of messy, but better:
Welp, you still have some work to do, but anyway, that's why the data was not displaying!
Fork of your fiddle.
Related
The data I am trying to plot is of the form :
[
[24894174208.0, 1604842800],
[24903880704.0, 1604843100]
]
where x = data points; y = UNIX_EPOC_Time
while plotting I am interchanging x,y; so as to plot UNIX_EPOC_Time on X-axis & data points on Y-axis
I have to multiply UNIX_EPOC_Time by 1000 as: Javascript uses milliseconds internally, while normal UNIX timestamps are usually in seconds. ( Why do I need to multiply unix timestamps by 1000 in JavaScript? )
Also I am trying to find anomalies in the dataPoints which is being plotted with a dot (yellow/orange/red).
However, in the function
js[isIn(anomoly, point){...}]
where I find anomalies in dataPoints, I see the datapoints take the form as:
[1604923500000, 22179459072000]
instead of:
[1604923500, 22179459072.0]
due to which I have to divide the data point (here: 22179459072000) by 1000 to bring it to it's original form 22179459072.0 in order to plot it on the graph.
I am not sure why this is happening though.
I have reproduced the issue in stackblitz.
After some debugging, I finally found the source of the problem.
It is happening because of the way you are cloning your data.
let clone_element = { ...element };
The spread operator is not creating a deep copy of the element, it's just the shallow one meaning that some parts of the clone_element will still have a reference to the source of data causing mutation.
To fix that you could use for example the lodash's cloneDeep(). This function will produce a real deep copy, so there is no way you will mutate your initial data.
const clone_element = cloneDeep(element);
Live demo:
https://stackblitz.com/edit/highchart-highstock-pddlto?file=src%2Fapp%2Fapp.component.ts
Additional references:
What is the most efficient way to deep clone an object in JavaScript?
https://dassur.ma/things/deep-copy/
https://lodash.com/docs/4.17.15#cloneDeep
I am trying to plot a multiline d3 chart. I have created a method which should take a new dataset and try to plot it in the same d3 frame for new data update changes (possibly filters).
The first draw works fine but the next draw (mocked data: which is a slice of the previous data and few manipulated values) is not showing correct is crossing the x axis.
[See Image below]
Also the starting origin is missing a tick which should also be 2010 in this example
I also want to create few more lines if there is more datapoints in the future which should be dynamic. Current model is {date, actual, projected}, More expected is mean or difference which will only be shown on trigger.
Any help would be appreciated.
Here is a Stackblitz https://stackblitz.com/edit/angular-rhr39p
References:
Animated line chart: http://bl.ocks.org/atmccann/8966400
Multiline chart: https://bl.ocks.org/larsenmtl/e3b8b7c2ca4787f77d78f58d41c3da91
Dataset updates: https://bl.ocks.org/d3noob/7030f35b72de721622b8
Please keep just one problem per question here at Stack Overflow. This answer will deal with problem #1, consider asking separate questions for the other problems.
The issue here is just your enter/update methodology, that is not correct and. Stick with the idiomatic D3, which is along these lines:
const update = this.svg.selectAll('.records')
.data(records);
const enter = update.enter().append('g')
.attr('class', 'records');
Then, you append new paths using enter and update those paths using update.
You can also ditch the groups and create enter/update/exit selections for the paths directly. That will make your code simpler.
Here is the forked code: https://stackblitz.com/edit/angular-lyd79t?file=src%2Fapp%2Flinechart%2Flinechart.component.ts
I am struggling with D3. I have a dataset that I am pulling into D3, and populating a bar chart. The problem is there are too many bars! I want to only display the top 10 values.
My csv has two values, the key (column header) is "Name" and the value is "NumberOfTickets". I want to show only 10 names that have the most tickets. I assume i need to sort and splice my dataset, but I have tried everything and cant get it to work. It seems most tutorials are geared towards simple arrays and not a dataset that comes from a CSV with key value pairs. Any help would be appreciated. Here is my dataset portion of the D3 code. I assume this is where I need to manipulate the dataset:
var report = data.forEach(function(d){
d.Name= d.Name;
d.NumberOfTickets= +d.NumberOfTickets;
});
Try this:
var report = data.sort(function(a, b) {
return d3.descending(+a.NumberOfTickets, +b.NumberOfTickets);
}).slice( 0, 10);
If you want the names that get less tickets, just change for "ascending". If you want to change your slice, remember that the start number is inclusive, but the ending number is not.
I have a nvd3 line chart which displays a time series and can't get the ticks on the x axis right.
For longer time spans, it works as expected. But for shorter time spans (here: 12/31/05 to 01/01/06), the same date is displayed for multiple ticks:
Please have a look at the code for this chart on JSFiddle
I want the chart to only display ticks at data points, and not in between. Is that possible with a line chart? From my understanding, it is possible with d3, but I can't figure out if this functionality is exposed by nvd3.
I've tried explicitly setting the number of ticks with chart.xAxis.ticks() without success. The only thing that has any effect is explicitly setting the tick values with chart.xAxis.tickValues([...]), but I would prefer not having to calculate them myself.
The way to solve this in general is with custom multi-scale time formats. Note that this example itself will not work with NVD3 because it uses an older version of D3, the examples below will though.
The problem in your case is that the ticks aren't "clean" divisions of time and if you apply a multi-scale format, you get something like this. It always shows the more fine-grained format because anything else would involve a loss of precision.
You can however use a simple heuristic to show the date instead of the time if the hour is less than 3, which works reasonably well in your case. See here for an example. The proper way to do this would be to make your ticks clean divisions.
Which brings us to your actual question. There's no other way than to explicitly set .tickValues() for what you want to do, but you can compute the x positions in your data quite easily:
var xvalues = [],
tmp = data.map(function(e) {
return e.values.map(function(d) { return d[0]; });
});
xvalues.concat.apply(xvalues, tmp);
The code is not the prettiest because it's a nested structure, but fairly straightforward. Using this, you can set your tick values explicitly, full example here.
Check out this fiddle, using D3 and plotting a line graph against dates.
http://jsfiddle.net/T546B/172/
I want to plot some further data on my graph and want to know if its possible, I would ideally like the graph to look like below:-
The extra data is linear and doesn't have a price value and I want it to be included somewhere near the middle of the graph. The data array would be in a format along the lines of:-
var eventArray = [[startdate, enddate, name]];
I was basically wondering if this is possible, plotting two types of data, using different SVG elements on one graph. - not sure how to approach this problem. Any help appreciated!
you just need to set up a second line generator with the coordinates that you want for x and y