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.
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 have an issue trying to color my bar chart dynamically based on a JSON response.
I know this has been asked a number of times before but none of the answers I've found or tried to work thorugh have got me any closer to a solution.
I've created a quick JSfiddle to show the issue.
I have a number of other charts which are all generated from different JSON strings so have cut this down a lot to try and isolate the issue. I don't have the same problem with the other charts as the number of entries in the Label array in consistent with the number of colours. The offending piece of code is this;
DT_Labels.forEach(function(DT_LABELS, x) {
data.datasets.push({
label: DT_LABELS,
backgroundColor: backgroundColor[x],
data: JSON.parse(DT_Values[x]).map(Number)
});
});
DT_Labels only contains a single entry as the chart is a summarised list - In theory, this would work if I counted the number of DT_Values but if I do that, I can't get the correct data in the chart.
Any ideas how I can reformat this to generate the colours counter based on the number of Values instead of Labels?
Change:
backgroundColor: backgroundColor[x],
to:
backgroundColor: backgroundColor,
Result:
Why does this work?
The backgroundColor property can be specified in a number of ways. Typically it's set to a string, e.g. #abcdef but it can also be set to an array. In this case Chart.js itself will pick the colour from the array based on the index of the data point it is drawing.
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.
I'm having a bit of a problem.
I'm using D3 to make a pie chart for an application I'm building. I basically it have it working, but I'm annoyed by one aspect of the chart. I've adapted the chart from here: http://jsfiddle.net/vfkSs/1/ to work with my application.
The data is passed in here:
data = data ? data : { "slice1": Math.floor((Math.random()*10)+1),
"slice2": Math.floor((Math.random()*10)+1),
"slice3": Math.floor((Math.random()*10)+1),
"slice4": Math.floor((Math.random()*10)+1) };
But somewhere in this file these slices are being ordered by value, which is not what I want.
The issue with this chart is that when it updates it adjusts all pieces of the chart to keep them in ascending order. For example the largest portion of the pie is always on the right, and smallest on the left. I would like these to remain in the order they are when the data is passed in.
This is buried a bit in the documentation.
pie.sort([comparator])
If comparator is specified, sets the sort order of data for the layout
using the specified comparator function. Pass null to disable sorting.
(bolding mine)
So, modify your .pie call to:
var cv_pie = d3.layout.pie().sort(null).value(function (d) { return d.value });
Updated fiddle.
I am trying to implement stacked bar chart.
My data source is JSON array.
Data might be negative or positive.
I am referencing this link
http://bl.ocks.org/ZJONSSON/2975320
But the problem is the data used here like matrix type.
like :
var data = [[{y:3},{y:6},{y:-3}],
[{y:4},{y:-2},{y:-9}],
[{y:10},{y:-3},{y:4}]
]
I have same data but in JSON array like :
var data = [{x:"abc", y1:"3", y2:"4", y3:"10"},
{x:"abc2", y1:"6", y2:"-2", y3:"-3" },
{x:"abc3", y1:"-3", y2:"-9", y3:"4"}
]
Now my question is how I can implement this graph with JSON formatted data.
In the example you linked, the original data is grouped by band type. Your data is grouped by set - that is, in the original each color band is grouped in the data array. In your data, each stack of bands is a group of objects in the data array.
If you want to reuse the original code, we need to translate the data (90 degrees) like so:
var initialData = [{x:"abc", y1:"3", y2:"4", y3:"10"},
{x:"abc2", y1:"6", y2:"-2", y3:"-3" },
{x:"abc3", y1:"-3", y2:"-9", y3:"4"}]
var data = ["y1","y2","y3"].map(
function(v){
return initialData.map(function(d){
return {y: +d[v]};
});
});
Then, most of the original code can be used as-is.
Another part which you can adapt is the domain for the x-scale
x = d3.scale.ordinal()
.domain(['abc','abc2','abc3'])
.rangeRoundBands([margin,w-margin], .1)
The group names are hard coded, but you have them in your objects as "x".
Instead, we can automatically use the x value of each object as the label for each set:
x = d3.scale.ordinal()
.domain(initialData.map(function(d){return d.x}))
.rangeRoundBands([margin,w-margin], .1)
Putting it all together, with some extra values: http://jsfiddle.net/fLMAZ/1/
The other option is to rewrite the code to bind the data as-is, but you will need to understand how the stacked bar chart is built and then adapt it to your original JSON.
You have a couple of options:
Is to provide the data from the server side to make it look like the JSON structure that graph likes.
You can parse through your JSON on the client side and make a new JSON
You can modify the graph chart such that it will work with your JSON