D3 - best way to dynamically update a Pie chart? - dynamic

I am trying to dynamically update a Pie chart and I am not 100% sure if this is the best way to do it. What do you say?
var arcsenter = arcs.enter().append("g")
.attr("class", "arc");
arcsenter.append("path")
.attr("d", arc)
.attr("fill", function (d) {
return color(d.data);
})
.on("click", function (evt) {
alert(JSON.stringify(evt));
});
Fiddle - http://jsfiddle.net/hsfid/dr7X3/embedded/result/

Related

vue function not returning dynamic property instead showing initial value

I am trying to make a progress bar the progress bar works fine but its not changing text within html and keeps static 0%. N.B I am pasting here only relevant codes to avoid a large page of code.
<div class="progressTopBar"><div class="inner-progressBar" :style="{width: this.ProgressBar }">
#{{ getProgressBar() }}
</div></div>
//property
data: function () {
return {
ProgressBar:"0%",
}
}
//function on change to upload and make progress
fileSelected(e) {
let fd = new FormData();
fd.append('fileInput', $("#file")[0].files[0], $("#file")[0].files[0].name);
axios.post("/admin/chatFileUpload", fd, {
onUploadProgress: function (uploadEvent) {
this.ProgressBar = Math.round((uploadEvent.loaded / uploadEvent.total)*100) + '%';
$(".inner-progressBar").css("width", this.ProgressBar);
}
});
},
//getting progress bar value in text which only returns preset value
getProgressBar() {
return this.ProgressBar;
},
You need to make getProgressBar() a computed property instead of a method.
computed: {
getProgressBar() {
return this.progressBar;
}
}
Also, you should use camel case or snake case for your variables.
The problem is the scoping of this in the code below:
onUploadProgress: function (uploadEvent) {
this.ProgressBar = Math.round((uploadEvent.loaded / uploadEvent.total)*100) + '%';
Because this is a new function it has its own this value, it does not use the this value from the surrounding code.
The simplest way to fix this is to use an arrow function:
onUploadProgress: (uploadEvent) => {
this.ProgressBar = Math.round((uploadEvent.loaded / uploadEvent.total)*100) + '%';
An arrow function retains the this value from the surrounding scope.
I also suggest getting rid of the jQuery line starting $(".inner-progressBar"), that shouldn't be necessary once you fix the this problem as it will be handled by the template instead.
Further, it's unclear why you have a getProgressBar method at all. If it is just going to return ProgressBar then you can use that directly within your template without the need for a method.

Solid guage refresh when receives new data (point value)

I am having issues with my solid gauge component using the highcharts-vue wrapper.
Basically every time it receives new data it re-draws the animation from 0. Please see sandbox link below for example: https://codesandbox.io/s/n0no0jky1l
The desired behavour im trying to achieve is shown here: https://www.highcharts.com/demo/gauge-solid
Where the gauge animates from old to new value smoothly.
From what i can tell it is not recommended to access the charts methods manually (for example to call the points.update method). (source: https://github.com/highcharts/highcharts-vue#chart-object-reference)
Any ideas?
It occurs because of mutating data in Highcharts. Please use Point.update, instead of updating whole series, to make animation work. You can access whole Chart object by reference in your component, specifically this.children[0].chart. Here is the code:
watch: {
title(newValue) {
this.chartOptions.title.text = newValue;
},
points(newValue, oldValue) {
console.log("watch firing", newValue, oldValue);
this.$children[0].chart.series[0].data[0].update(oldValue += 1);
},
units(newValue) {
this.chartOptions.series[0].dataLabels.format =
'<div style="text-align:center"><span style="font-size:2rem;color: black">{y}</span><div>' +
newValue +
"</div><div/>";
},
min(newValue) {
this.chartOptions.yAxis.min = newValue;
},
max(newValue) {
this.chartOptions.yAxis.max = newValue;
}
},
Don't worry about your data, Highcharts mutate it, so your points prop should be updated every time.
Live example: https://codesandbox.io/s/ojkzvo05z
Kind regards!

Chartist.js and events

I am trying to add click events on the graphs that I am rendering. From chart.click to chart.on('click', function (e){ }).
What I am trying to do is allow the user to select points on the graph and for me to now what selections the user made. Is that at all possible using chartist.js?
I read through the documentation: CHARTIST.JS
My code:
if (item.GraphType.Description == "Line") {
var chart = new Chartist.Line(
container[0],
{
labels: d.Labels,
series: d.SeriesData
},
{
axisY: {
offset: 60
}
}
);
chart.click(function (e) {
console.log(e);
});
}
It is entirely possible, yes. Chartist renders SVG nodes to the page, so using a library like jQuery you can easily find all nodes that you want and attach events to them. You can be as specific or broad in the nodes you're looking for to only attach events to very specific nodes or elements on the chart.
For completeness sake, here is a short example of how to attach events that log the value of a data point when clicked upon to the console using jQuery:
$('.ct-chart-line .ct-point').click(function () {
var val = $(this).attr("ct:value");
console.log(val);
});
You should, however, make sure that the events attach only when the chart is created or drawn if you want to ensure the data points are on the page, which can be triggered by the "created" or "draw" events:
var chart = new Chartist.Line(...);
// attach an event handler to the "created" event of the chart:
chart.on("created", function () {
// attach the necessary events to the nodes:
$('.ct-chart-line .ct-point').click(function () {
var val = $(this).attr("ct:value");
console.log(val);
});
});

Updating a chart with new data in App SDK 2.0

I am using a chart to visualize data in a TimeboxScopedApp, and I want to update the data when scope changes. The more brute-force approach of using remove() then redrawing the chart as described here leaves me with an overlaid "Loading..." mask, but otherwise works. The natural approach of using the Highchart native redraw() method would be my preference, only I don't know how to access the actual Highchart object and not the App SDK wrapper.
Here's the relevant part of the code:
var chart = Ext.getCmp('componentQualityChart');
if (chart) {
var chartCfg = chart.getChartConfig();
chartCfg.xAxis.categories = components;
chart.setChartConfig(chartCfg);
chart.setChartData(data);
chart.redraw(); // this doesn't work with the wrapper object
} else { // draw chart for the first time
How do I go about redrawing the chart with the new data?
Assuming chart (componentQualityChart) is an instance of Rally.ui.chart.Chart, you can access the HighCharts instance like this:
var highcharts = chart.down('highchart').chart;
// Now you have access to the normal highcharts interface, so
// you could change the xAxis
highcharts.xAxis[0].setCategories([...], true);
// Or you could change the series data
highcharts.series[0].data.push({ ... }); //Add a new data point
// Or pretty much anything else highcharts lets you do
Using _unmask() removes the overlaid "Loading.." mask
if (this.down('#myChart')) {
this.remove('myChart');
}
this.add(
{
xtype: 'rallychart',
height: 400,
itemId: 'myChart',
chartConfig: {
//....
},
chartData: {
categories: scheduleStateGroups,
series: [
{
//...
}
]
}
}
);
this.down('#myChart')._unmask();

D3.js stacked bar chart broken transition

I am trying to get a stacked bar chart to transition in the same way as this bar chart - http://www.animatedcreations.net/d3/animatedBarChart_Slide.html
I have been following Mike Bostock's "A bar chart, part 2" example, and things are OK up to transitioning the stacked bars in and out.
My broken example is here - http://www.animatedcreations.net/d3/stackedBarChart7.html
I am reasonably sure the problem is with how I set up the data, as shown below. I am even wondering if the data needs to be transformed to be in columns rather than layers?
Insight much appreciated :) Thanks.
From redraw():
// stack the new data
var stacked = d3.layout.stack()(["act1", "act2","act3","other"].map(function(activity){
return stats.map(function(d) {
return {x:(d.hour), y: +d[activity]};
});
}));
// update x axis
x.domain(stacked[0].map(function(d) { return d.x; }));
var valgroup = graph.selectAll("g.valgroup").data(stacked);
// want the data in d. var rect contains the data AND functions.
// I am guessing this is where it all breaks??
var rect = valgroup.selectAll("rect")
.data((function(d) { return d; }), (function(d) { return d.x; }));
// new data set. slide by hour on x axis.
In this problem, the transitions are clearly the trickiest part, so I prefered to go from the simple bar example you provided and go to the stacked bar chart using Mike Bostock's example.
The principal problem with the stacked implementation you provide is that the information is "reversed" as you would want each bar to be in a different element of the data array, this way you can identify your data by its time stamp.
So, first, let's define some data with an array of values for each element:
function next () {
return {
time: ++t,
value: d3.range(3).map(getRand)
};
}
Then, inside of the redraw() function:
First format the data for the bar stacks:
customData = data.map(function(d){
y0=0
return {value:d.value.map(function(d){return {y0:y0, y1: y0+=d}}), time:d.time}
})
Then create the group for each stack of bar
var state = graph.selectAll(".g")
.data(customData, function(d) { return d.time; });
var stateEnter = state.enter().append("g")
.attr("class", "g")
.attr("transform", function(d) { return "translate(" + x(d.time+1) + ",0)"; });
Then, add the stack of bars of the group:
stateEnter.selectAll("rect")
.data(function(d) { return d.value; })
.enter().append("rect")
.attr("width", barWidth)
.attr("y", function(d) {return y(d.y1); })
.attr("height", function(d) { return y(d.y0) - y(d.y1); })
.attr("class", "bar")
.style("fill", function(d,i) { return color(i); });
Move every bar group to update the x values:
state.transition().duration(1000)
.attr("transform", function(d) {console.log(d); return "translate(" + x(d.time) + ",0)"; });
Remove old values
state.exit()
.attr("transform", function(d) {return "translate(" + x(d.time) + ",0)";})
.remove()
Here is a working example.
PS: Next time, please provide jsFiddles so we don't have to go to the source code of your page to provide a solution. Also, try to minimize as much as possible the code of your example (remove axis, useless parsing etc) so we can concentrate on what is wrong. Also, in the process you will often find the problem by yourself as you isolate it.