d3.js Grouped Box plot - d3.js

I would like to ask that is it possible to plot grouped box plots by D3.js like this example from Plotly? So far, I didn't see any example on the internet yet.
Thanks in advance.
4th UPDATE: [SOLVED on 3/3/2016]
Boxplot grouped by dates at x axis and colored according to grouping on respective dates.
Solution is as below:
var state = svg1.selectAll(".state2")
.data(dataset2)
.enter().append("g")
.attr("class", "state")
.attr("transform", function(d) { return "translate(" + x0(d.Date) + ",0)"; } );
state.selectAll(".box")
.data(function(d) { return d.Data; })
.enter().append("g")
.attr("transform", function(d) { return "translate(" + x_1(d.group) + ",0)"; } )
.call(boxplot);
3rd UPDATE:
Done modifying data format.
Issue: Boxplot for both dates are the same.
2nd UPDATE:
Managed to group the Box plots but facing difficulties in formatting data into groups. plunker version 9
UPDATE:
I am trying to change the first chart (Grouped Bar chart) to Grouped Boxplot. Hit error on line 140 at index.html. plunker version 1.
state.selectAll(".box")
.data(function(d) { return d.data; })
.enter().append("g")
.attr("transform", function(d) { return "translate(" + x_1(d) + "," + margin.top + ")"; } )
.call(boxplot.width(x0.rangeBand())); //This line

Yes, it's doable, here is an example : https://bl.ocks.org/mbostock/4061502.
The main idea here is just to use svg rect path and circle to achieve the box and whisker style.
If you are will to use nvd3, there is a built-in boxPlot graph (example)

Try this
<!DOCTYPE html>
<html>
<head>
<style>
#chartdiv {
width: 100%;
height: 500px;
}
</style>
</head>
<body>
<div id="chartdiv"></div>
<script src="https://cdn.amcharts.com/lib/4/core.js"></script>
<script src="https://cdn.amcharts.com/lib/4/charts.js"></script>
<script src="https://cdn.amcharts.com/lib/4/themes/animated.js"></script>
<!-- Chart code -->
<script>
am4core.ready(function() {
// Themes begin
am4core.useTheme(am4themes_animated);
// Themes end
var chart = am4core.create("chartdiv", am4charts.XYChart);
chart.paddingRight = 20;
chart.dateFormatter.inputDateFormat = "yyyy-MM-dd";
var dateAxis = chart.xAxes.push(new am4charts.DateAxis());
dateAxis.renderer.minGridDistance = 40;
dateAxis.renderer.grid.template.location = 0;
var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.tooltip.disabled = true;
var series = chart.series.push(new am4charts.CandlestickSeries());
series.dataFields.dateX = "date";
series.dataFields.valueY = "close";
series.dataFields.openValueY = "open";
series.dataFields.lowValueY = "low";
series.dataFields.highValueY = "high";
series.simplifiedProcessing = true;
series.tooltipText = "Open:${openValueY.value}\nLow:${lowValueY.value}\nHigh:${highValueY.value}\nClose:${valueY.value}\nMediana:{mediana}";
series.riseFromOpenState = undefined;
series.dropFromOpenState = undefined;
chart.cursor = new am4charts.XYCursor();
var medianaSeries = chart.series.push(new am4charts.StepLineSeries());
medianaSeries.noRisers = true;
medianaSeries.startLocation = 0.1;
medianaSeries.endLocation = 0.9;
medianaSeries.dataFields.valueY = "mediana";
medianaSeries.dataFields.dateX = "date";
medianaSeries.strokeWidth = 2;
medianaSeries.stroke = am4core.color("#fff");
var topSeries = chart.series.push(new am4charts.StepLineSeries());
topSeries.noRisers = true;
topSeries.startLocation = 0.2;
topSeries.endLocation = 0.8;
topSeries.dataFields.valueY = "high";
topSeries.dataFields.dateX = "date";
topSeries.stroke = chart.colors.getIndex(0);
topSeries.strokeWidth = 2;
var bottomSeries = chart.series.push(new am4charts.StepLineSeries());
bottomSeries.noRisers = true;
bottomSeries.startLocation = 0.2;
bottomSeries.endLocation = 0.8;
bottomSeries.dataFields.valueY = "low";
bottomSeries.dataFields.dateX = "date";
bottomSeries.stroke = chart.colors.getIndex(0);
bottomSeries.strokeWidth = 2;
chart.scrollbarX = new am4core.Scrollbar();
chart.data = [ {
"date": "2019-08-01",
"open": 132.3,
"high": 136.96,
"low": 131.15,
"close": 136.49
}, {
"date": "2019-08-02",
"open": 135.26,
"high": 135.95,
"low": 131.50,
"close": 131.85
}, {
"date": "2019-08-03",
"open": 129.90,
"high": 133.27,
"low": 128.30,
"close": 132.25
}, {
"date": "2019-08-04",
"open": 132.94,
"high": 136.24,
"low": 132.63,
"close": 135.03
}, {
"date": "2019-08-05",
"open": 136.76,
"high": 137.86,
"low": 132.00,
"close": 134.01
}, {
"date": "2019-08-06",
"open": 131.11,
"high": 133.00,
"low": 125.09,
"close": 126.39
}, {
"date": "2019-08-07",
"open": 130.11,
"high": 133.00,
"low": 125.09,
"close": 127.39
}, {
"date": "2019-08-08",
"open": 125.11,
"high": 126.00,
"low": 121.09,
"close": 122.39
}, {
"date": "2019-08-09",
"open": 131.11,
"high": 133.00,
"low": 122.09,
"close": 124.39
}];
addMediana();
function addMediana(){
for(var i = 0; i < chart.data.length; i++){
var dataItem = chart.data[i];
dataItem.mediana = Number(dataItem.low) + (Number(dataItem.high) - Number(dataItem.low)) / 2;
}
}
}); // end am4core.ready()
</script>
</body>
</html>

Related

Amcharts 4: overlapping LabelBullet text

I have a line chart with similar values.
Is there a way to automatically add padding when LabelBullets overlaps?
or some other elegant solution to this problem....
Either no one has this problem, or this problem has not yet occurred to anyone
I found only one question on this topic, but it remained unanswered
Here is a screenshot of the case
Jfiddle link
`HTML`
<script src="https://cdn.amcharts.com/lib/4/core.js"></script>
<script src="https://cdn.amcharts.com/lib/4/charts.js"></script>
<script src="https://cdn.amcharts.com/lib/4/themes/animated.js"></script>
<div id="chartdiv"></div>
`CSS`
#chartdiv {
width: 100%;
height: 500px;
}
`JS`
am4core.ready(function() {
// Themes begin
am4core.useTheme(am4themes_animated);
// Themes end
var chart = am4core.create("chartdiv", am4charts.XYChart);
var data = [
{
"year": "2015",
"b1": "10",
"b2": "12"
},
{
"year": "2016",
"b1": "20",
"b2": "22"
},
{
"year": "2017",
"b1": "30",
"b2": "32"
},
{
"year": "2018",
"b1": "40",
"b2": "42"
},
{
"year": "2019",
"b1": "20",
"b2": "22"
}
]
;
chart.data = data;
var categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
var yAxis = chart.yAxes.push(new am4charts.ValueAxis());
//remove grid
valueAxis.renderer.grid.template.strokeWidth = 0;
categoryAxis.renderer.grid.template.disabled = true;
valueAxis.renderer.labels.template.disabled = true;
// Create series
categoryAxis.dataFields.category = "year";
categoryAxis.renderer.minGridDistance = 10;
CreateLineSeries("b1", "Data1", false);
CreateLineSeries("b2", "Data2", false);
function CreateLineSeries(field, name, stacked) {
var LineValueAxis = chart.yAxes.push(new am4charts.ValueAxis());
LineValueAxis.renderer.opposite = true;
LineValueAxis.renderer.grid.template.disabled = true;
LineValueAxis.renderer.labels.template.disabled = true;
var LineSeries = chart.series.push(new am4charts.LineSeries())
LineSeries.dataFields.valueY = field;
LineSeries.dataFields.categoryX = "year";
LineSeries.yAxis = LineValueAxis;
LineSeries.name = name;
LineSeries.strokeWidth = 4
var bullet = LineSeries.bullets.push(new am4charts.Bullet());
var circle = bullet.createChild(am4core.Circle);
circle.radius = 6;
var labelBullet = LineSeries.bullets.push(new am4charts.LabelBullet());
labelBullet.label.text = "{valueY.formatNumber('###.')} %";
labelBullet.label.background.fill = am4core.color("lightgrey");
labelBullet.label.padding(4, 8, 4, 8);
labelBullet.dy = -25;
labelBullet.fillOpacity = 0.5;
}
});

amCharts - XY Charts Tooltip and Bullet

I have an XY Charts in amCharts 4 and I can't set the correct parameter to insert in the tooltip. This is the code that design the chart:
Is possible to show the parameter "desc" in the tooltip?
var chart = am4core.create("chartdiv", am4charts.XYChart);
// Add data
chart.data = [ {
"x": -6,
"y": 0,
"diam": 4,
"desc": "test"
}, {
"x": 0,
"y": -10,
"diam": 4,
"desc": "test"
}, {
"x": 12,
"y": 10,
"diam": 8,
"desc": "special"
} ];
// Create axes
var xAxis = chart.xAxes.push(new am4charts.ValueAxis());
var yAxis = chart.yAxes.push(new am4charts.ValueAxis());
// Create series
var series = chart.series.push(new am4charts.LineSeries());
series.dataFields.valueX = "x";
series.dataFields.valueY = "y";
series.strokeWidth = 2;
series.fillOpacity = 0;
series.stroke = "red";
// Create bullet and tooltip
seriesBullet = series.bullets.push(new am4charts.CircleBullet());
seriesBullet.circle.fill = am4core.color("#fff");
seriesBullet.circle.strokeWidth = 3;
seriesBullet.circle.propertyFields.radius = "diam";
seriesBullet.tooltipText = "desc";
#chartdiv {
width: 100%;
height: 200px;
}
<script src="https://www.amcharts.com/lib/4/core.js"></script>
<script src="https://www.amcharts.com/lib/4/charts.js"></script>
<div id="chartdiv"></div>
You need to wrap the desc in curly braces: {desc}
seriesBullet.tooltipText = "{desc}";
Here is your updated working example:
var chart = am4core.create("chartdiv", am4charts.XYChart);
// Add data
chart.data = [ {
"x": -6,
"y": 0,
"diam": 4,
"desc": "test"
}, {
"x": 0,
"y": -10,
"diam": 4,
"desc": "test"
}, {
"x": 12,
"y": 10,
"diam": 8,
"desc": "special"
} ];
// Create axes
var xAxis = chart.xAxes.push(new am4charts.ValueAxis());
var yAxis = chart.yAxes.push(new am4charts.ValueAxis());
// Create series
var series = chart.series.push(new am4charts.LineSeries());
series.dataFields.valueX = "x";
series.dataFields.valueY = "y";
series.strokeWidth = 2;
series.fillOpacity = 0;
series.stroke = "red";
series.tooltipText = "{desc}";
// Create bullet and tooltip
seriesBullet = series.bullets.push(new am4charts.CircleBullet());
seriesBullet.circle.fill = am4core.color("#fff");
seriesBullet.circle.strokeWidth = 3;
seriesBullet.circle.propertyFields.radius = "diam";
seriesBullet.tooltipText = "{desc}";
#chartdiv {
width: 100%;
height: 200px;
}
<script src="https://www.amcharts.com/lib/4/core.js"></script>
<script src="https://www.amcharts.com/lib/4/charts.js"></script>
<div id="chartdiv"></div>
You need to put your parameter inside a {} curly braces.
E.g :
seriesBullet.tooltipText = "{desc}";

amcharts valueaxis incremental manner scaling

I have value range from 1 to 40 000 which I am trying to plot on amcharts serial chart. As chart is auto scaling depend on value range, values which are less than 500 (ex: 10, 50, 100...) are shown as line on x-axis itself. In this case auto scaling is 0-1000-2000-3000...
How to achieve scaling in incremental manner i.e. 0-10-100-1000-10000 ... so that all candles including low value candles also get significant visibility.
or suggest any better approach to get all chart candles visible in chart.
<style>
#chartdiv {
width: 100%;
height: 500px;
}
</style>
<!-- Resources -->
<script src="https://www.amcharts.com/lib/4/core.js">
</script>
<script src="https://www.amcharts.com/lib/4/charts.js">
</script>
<script>
src=
"https://www.amcharts.com/lib/4/themes/animated.js" >
</script>
<!-- Chart code -->
<script>
am4core.ready(function() {
// Themes begin
am4core.useTheme(am4themes_animated);
// Themes end
// Create chart instance
var chart = am4core.create("chartdiv",
am4charts.XYChart3D);
// Adding sample data
chart.data = [{
"country": "USA",
"visits": 39000
}, {
"country": "China",
"visits": 100
}, {
"country": "Japan",
"visits": 35000
}, {
"country": "Germany",
"visits": 50
}, {
"country": "UK",
"visits": 200
}, {
"country": "France",
"visits": 20
}, {
"country": "India",
"visits": 25
}, {
"country": "Spain",
"visits": 711
} ];
// Create axes
let categoryAxis = chart.xAxes.push(new
am4charts.CategoryAxis());
categoryAxis.dataFields.category = "country";
categoryAxis.renderer.labels.template.rotation = 270;
categoryAxis.renderer.labels.template.hideOversized =
false;
categoryAxis.renderer.minGridDistance = 20;
categoryAxis.renderer.labels.template.horizontalCenter =
"right";
categoryAxis.renderer.labels.template.verticalCenter =
"middle";
categoryAxis.tooltip.label.rotation = 270;
categoryAxis.tooltip.label.horizontalCenter = "right";
categoryAxis.tooltip.label.verticalCenter = "middle";
let valueAxis = chart.yAxes.push(new
am4charts.ValueAxis());
valueAxis.title.text = "Countries";
valueAxis.title.fontWeight = "bold";
// Create series
var series = chart.series.push(new
am4charts.ColumnSeries3D());
series.dataFields.valueY = "visits";
series.dataFields.categoryX = "country";
series.name = "Visits";
series.tooltipText = "{categoryX}: [bold]{valueY}[/]";
series.columns.template.fillOpacity = .8;
var columnTemplate = series.columns.template;
columnTemplate.strokeWidth = 2;
columnTemplate.strokeOpacity = 1;
columnTemplate.stroke = am4core.color("#FFFFFF");
columnTemplate.adapter.add("fill", (fill, target) => {
return chart.colors.getIndex(target.dataItem.index);
})
columnTemplate.adapter.add("stroke", (stroke, target) =>
{
return chart.colors.getIndex(target.dataItem.index);
})
chart.cursor = new am4charts.XYCursor();
chart.cursor.lineX.strokeOpacity = 0;
chart.cursor.lineY.strokeOpacity = 0;
}); // end am4core.ready()
</script>
<!-- HTML -->
<div id="chartdiv"></div>
You can achieve this by setting:
valueAxis.logarithmic = true;

Donut3D.js 3d pie chart change data event not firing

I'm using Donut3D.js library (which is based on D3.js chart library) (http://bl.ocks.org/NPashaP/9994181).
I've created a javascript event listener to listen for changes in a select option Html combo box control. Users select an option from the combo box and based on the selected option, the data for the 3d pie chart is fetched from a SQL Server database and the chart is re-drawn. However, my chart is not rendering, although when I'm in Firebug debug mode, it is re-drawn. I'm using Firefox and Firebug for debugging. My Web app is using an MVC pattern and C# programming language. Following are the code snippets:
In Partial View1:
<select id=hucDdl></select>
In Partial View2:
<script>
$(document).ready(function(){
//Event listener when selection changes
$("#hucDdl").change(function () {
//Get huc value
var huc;
if($("#hucDdl").val() != null){
huc = $("#hucDdl").val();
});
//Call function
ChangeData();
});
function ChangeData(){
<blockquote>var huc = $("#hucDdl").val();
var arr = [];
var lulcData = null;
//get data from SQL Server
$.ajax({<br/></blockquote>
url: "/Home/GetBaseLulcJson/",
type: "GET",
data: {huccode: huc},
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function(result){
arr = result;
},
error: function(data){
}
})
lulcData = [
{ "label": "Cropland", "value": arr[0], "color": "#ffb3ba" },
{ "label": "Forest", "value": arr[1], "color": "#ffdfba" },
{ "label": "Pasture", "value": arr[2], "color": "#ffffba" },
{ "label": "Rangeland", "value": arr[3], "color": "#baffc9" },
{ "label": "Urban", "value": arr[4], "color": "#bae1ff" }
];
//Draw the 3d pie chart
Donut3D.draw("blulcpie", getData(), 90, 50, 90, 40, 30, 0);
function getData(){
<blockquote>return lulcData.map(function (d) {
return { label: d.label, value: +d.value, color: d.color };
});
}
});
</script>
The ChangeData() function is not firing on selection change.
Does anyone know how to get the chart to re-draw when data changes?
The data fetched from SQL Server are correct.
I'm just not sure what's causing the chart not to re-draw.
Solved this issue. I revised my codes as follows:
Index.cshmtl (main view):
<!--d3.js references-->
<script src="http://d3js.org/d3.v3.min.js" type="text/javascript"></script>
<script src="~/myscripts/donut3d.js" type="text/javascript"></script>
<div id="bLulc">
<label>Major Landuse</label>
#Html.Partial("~/Views/Shared/_BaseLanduse.cshtml")
</div>
Partial View1 (holds the select HTML control):
<select id = "hucDdl"></select>
Partial View2 (contains the 3d pie chart) "_BaseLanduse.cshtml":
<script type="text/javascript">
$(document).ready(function () {
//Set default array values for initial display on page load
var def_arr = [0.2, 80.3, 1.9, 16.9, 0.7];
var defData = [
{ "label": "Cropland", "value": def_arr[0], "color": "#ffb3ba" },
{ "label": "Forest", "value": def_arr[1], "color": "#ffdfba" },
{ "label": "Pasture", "value": def_arr[2], "color": "#ffffba" },
{ "label": "Rangeland", "value": def_arr[3], "color": "#baffc9" },
{ "label": "Urban", "value": def_arr[4], "color": "#bae1ff" }
];
//Define chart parameters
var margin = { top: 0, right: 20, bottom: 0, left: 20 }
var width = 180,
height = 230 - margin.bottom;
var svg = d3.select("#bLulc")
.append("svg")
.attr("width", width)
.attr("height", height);
svg.append("g")
.data([defData])
.attr("id", "blulcpie");
//Draw the chart
Donut3D.draw("blulcpie", defData, 90, 50, 90, 40, 30, 0);
//Define legend square size
var legendSpace = 4;
var rectSize = 8;
//Add legend
defData.forEach(function (d, i) {
svg.append("rect")
.attr("transform", "translate(0," + i * (rectSize + legendSpace) + ")")
.attr("class", "rect")
.attr("width", rectSize)
.attr("height", rectSize)
.attr("x", 50) //x-axis of rect
.attr("y", 130) //y-axis of rect
.style("stroke", "#000000")
.style("stroke-width", .25)
.style("fill", defData[i].color);
svg.append("text")
.attr("class", "legend")
.attr("x", rectSize + legendSpace)
.attr("y", (i * legendSpace) + (i * rectSize))
.attr("dx", 50) //x-axis of text
.attr("dy", 138) //y-axis of text
.style("font-size", "10px")
.text(defData[i].label);
});
//Event listener when huccode changes
$("#hucDdl").bind("mousedown mouseup", function () {
debugger;
//Get data from SQL Server via Controller
$.ajax({
url: "/Home/GetBaseLulcJson/",
type: "GET",
data: { huccode: $("#hucDdl").val() },
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function (result) {
arr = result;
//alert(arr);
},
error: function (data) {
//alert(data);
}
})
var currData = [
{ label: "Cropland", value: arr[0], color: "#ffb3ba" },
{ label: "Forest", value: arr[1], color: "#ffdfba" },
{ label: "Pasture", value: arr[2], color: "#ffffba" },
{ label: "Rangeland", value: arr[3], color: "#baffc9" },
{ label: "Urban", value: arr[4], color: "#bae1ff" }
];
Donut3D.transition("blulcpie", currData, 90, 40, 30, 0);
});
});
Controller:
[HttpGet]
public JsonResult GetBaseLulcJson(string huccode)
{
//Returns single row, selected columns
var lulcBase = (from f in db.FractionsLulcs
where f.HUCCODE == huccode
select new
{
f.Cropland,
f.Forest,
f.Pasture,
f.Range,
f.Urban
}).SingleOrDefault();
//Convert to percentage
double?[] lulc = new double?[5];
lulc[0] = Math.Round(Convert.ToDouble(lulcBase.Cropland) * 100, 1);
lulc[1] = Math.Round(Convert.ToDouble(lulcBase.Forest) * 100, 1);
lulc[2] = Math.Round(Convert.ToDouble(lulcBase.Pasture) * 100, 1);
lulc[3] = Math.Round(Convert.ToDouble(lulcBase.Range) * 100, 1);
lulc[4] = Math.Round(Convert.ToDouble(lulcBase.Urban) * 100, 1);
return Json(lulc, JsonRequestBehavior.AllowGet);
}

NVD3 Y axis order

I have the following line chart: http://jsfiddle.net/cp3fV/2/
var data = [
{
"days_to_expiry": 0,
"close": "7.1120000000"
},
{
"days_to_expiry": 1,
"close": "8.4580000000"
},
{
"days_to_expiry": 2,
"close": "7.2830000000"
},
{
"days_to_expiry": 3,
"close": "12.2820000000"
},
{
"days_to_expiry": 4,
"close": "7.1820000000"
}
]
nv.addGraph(function() {
var chart = nv.models.lineChart()
.margin({left: 100, right:50})
.useInteractiveGuideline(true)
.transitionDuration(350)
.showLegend(false)
.showYAxis(true)
.showXAxis(true)
//.forceY([0, 19])
.y(function (d) { return d.close })
.x(function (d) { return d.days_to_expiry })
;
console.log(data);
chart.xAxis
.axisLabel('Date')
.ticks(10);
chart.yAxis
.axisLabel('Close')
.tickFormat(d3.format('.03f'));
var testData = [{key:"Test", color: '#2ca02c', values: data}];
d3.select('#chart svg')
.datum(testData)
.call(chart);
nv.utils.windowResize(function() { chart.update() }); // Update on resize
return chart;
});
I just want to order the Y axis from minimum to maximum. It works fine if all the values are <10
I know I can use forceY(min, max) but I don't want to calculate the minimum every time(I'm planning to use AJAX to update the chart)
It works if you use the numbers as numbers and not as strings:
data.forEach(function(d) { d.close = +d.close; });
Complete example here.

Resources