How to put data ranges in piecharts using dc.js? - dc.js

I have a pie chart for age, which currently has pie slices for every age there in the data set. Since the age range is wide, numerous thin slices are formed in the pie chart. I want to make it as a range, like one slice should show 0-18, another 19-30, and so on. How can I do this?
Here is my code
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="bower_components/dcjs/dc.css">
<link rel="stylesheet" href="bower_components/leaflet/dist/leaflet.css">
<script src="bower_components/d3/d3.min.js"></script>
<script src="bower_components/crossfilter2/crossfilter.min.js"></script>
<script src="bower_components/dcjs/dc.js"></script>
<!--THE FOLLOWING META IS IMPORTANT, OTHERWISE THERE MIGHT BE A PROBLEM WITH SOME CHARACTERS-->
<meta http-equiv="content-type" content="text/html; charset=UTF8">
<!--CDN FOR JQUERY-->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.js"></script>
</head>
<body>
<div id="map">
<a class="reset" href="javascript:usChart.filterAll();dc.redrawAll();" style="display: none;">reset</a>
<span class="reset" style="display: none;"> | Current filter: <span class="filter"></span></span>
<div class="clearfix"></div>
</div>
<div id="pie-gender">
<a class="reset" href="javascript:usChart.filterAll();dc.redrawAll();" style="display: none;">reset</a>
<span class="reset" style="display: none;"> | Current filter: <span class="filter"></span></span>
<div class="clearfix"></div>
</div>
<div id="pie-age">
<a class="reset" href="javascript:usChart.filterAll();dc.redrawAll();" style="display: none;">reset</a>
<span class="reset" style="display: none;"> | Current filter: <span class="filter"></span></span>
<div class="clearfix"></div>
</div>
<div>
Reset All
</div>
<script type="text/javascript">
d3.csv("data/gender.csv", function (data) {
d3.json("data/us-states.json", function (json){
// set up crossfilter on the data.
var ndx = crossfilter(data);
// set up the dimensions
var stateDim = ndx.dimension(function (d) { return d.state; });
var genderDim = ndx.dimension(function(d) { return d.gender; });
var ageDim = ndx.dimension(function(d) { return d.age; });
//filtering age ranges
var age_0_18 = ageDim.filter([0,19]);
var age_19_30 = ageDim.filter([19,31]);
var age_31_60 = ageDim.filter([31,61]);
var age_61_101 = ageDim.filter([61,101]);
// set up the groups/values
var state = stateDim.group();
var gender = genderDim.group();
//var age = ageDim.group();
var age1 = age_0_18.group();
var age2 = age_19_30.group();
var age3 = age_31_60.group();
var age4 = age_61_101.group();
// the different charts - options are set below for each one.
var pieGender = dc.pieChart('#pie-gender');
var pieAge = dc.pieChart('#pie-age')
var usmap = dc.geoChoroplethChart("#map");
//create pie to show gender
pieGender
.width(180)
.height(180)
.radius(80)
.dimension(genderDim)
.group(gender)
.renderLabel(true)
.innerRadius(10)
.transitionDuration(500)
//.colorAccessor(function (d, i) { return d.value; });
//below is how to decide the colours for pie slices
.colors(d3.scale.ordinal().range([ '#14CAFF', '#4646FF']));
//creating pie to show age
pieAge
.width(180)
.height(180)
.radius(80)
.dimension(ageDim)
.group(age1,age2,age3,age4)
.renderLabel(true)
.innerRadius(10)
.transitionDuration(500)
.colorAccessor(function (d, i) { return d.value; });
//display US map
usmap
.width(900)
.height(500)
.dimension(stateDim)
.group(state)
.colors(["rgb(20,202,255)","rgb(70,70,255)"])
.overlayGeoJson(json.features, "name", function (d) { return d.properties.name; })
// at the end this needs to be called to actually go through and generate all the graphs on the page.
dc.renderAll();
});
});
</script>
</body>
I tried using filter and then grouping, but the result remained the same. I think the procedure is wrong maybe.
Any help would be greatly appreciated. Thanks.

I'm sure I've seen a lot of examples of this, but I couldn't find any in a quick search.
You'll want to use the group's groupValue function to put ages into the categories you want. This is exactly the same way you would round values down or do any other categorization:
var ageGroup = ageDim.group(function(v) {
if(v < 19) return "18 or under";
else if(v < 30) return "19-29";
else if(v < 30) return "30-59";
else return "over 60";
});
Note that dimension.filter() just returns the dimension and changes the filters for the entire crossfilter, so all of your groups above would be the same group, and only the last filter would take.

Related

Select a month in bar chart from dc.js

I have a time series with a date, an amount and a count column. I just want to plot the aggregate of amount by month and select a month by clicking on the bar, not using the brush.
I thought my objective was pretty simple, but I'm rummaging for days without success. The main issue is that I apply a filter on the chart, but the filter is not taken into account when a redraw the chart.
Thanks for your help.
I'm using :
dc.js 2.0.2
d3.js 3.5.17
crossfilter 1.4
This is my code :
<!DOCTYPE html>
<html lang="en">
<head>
<title>Just selecting a month </title>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="../static/lib/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="../static/lib/css/dc.css"/>
</head>
<body>
<div>
Month selector
<a class="reset" href='javascript:chart.filterAll();dc.redrawAll();'> Reset</a>
<div id="time-chart"></div>
</div>
<script type="text/javascript" src="../static/lib/js/d3.js"></script>
<script type="text/javascript" src="../static/lib/js/crossfilter.js"></script>
<script type="text/javascript" src="../static/lib/js/dc.js"></script>
<script type="text/javascript">
var dateFormat_in = d3.time.format.utc("%Y-%m-%d");
var chart = dc.barChart("#time-chart");
d3.csv('setdates.csv', function(error, dataset) {
if(error)
throw new Error(error);
dataset.forEach(function(d) {
d["date"] = dateFormat_in.parse(d["date"]);
d["amount"] = +d["amount"];
});
var ndx = crossfilter(dataset);
var monthDim = ndx.dimension(d => d3.time.month(d["date"]));
var monthGroup = monthDim.group().reduceSum(d => d["amount"]);
var minDate = monthDim.bottom(1)[0]["date"];
var maxDate = monthDim.top(1)[0]["date"];
minDate=d3.time.day.offset(minDate, -40);
//console.log([minDate,maxDate]);
chart
.width(400)
.height(260)
.x(d3.time.scale().domain([minDate, maxDate]))
.xUnits(d3.time.months)
.dimension(monthDim)
.group(monthGroup)
.margins({left: 50, top: 20, right: 0, bottom: 20})
.elasticY(true)
.gap(60)
.centerBar(true).xAxisPadding(15).xAxisPaddingUnit('month')
.on('pretransition', function(ichart) {
ichart.selectAll("rect.bar").on("click", function (d) {
console.log([d.data.key,new Date(2016,d.data.key.getMonth()+1,1)]);
chart.filter([d.data.key,new Date(2016,5,1)]).redraw();
console.log(chart.filters())
//dc.renderAll();
});
})
.brushOn(false)
.clipPadding(20);
chart.centerBar(true).xAxisPadding(15).xAxisPaddingUnit('month')
dc.renderAll();
});
</script>
These are my data :
date,amount,count
2016-04-28,93.54,3.89
2016-04-29,94.42,3.94
2016-04-30,95.30,3.99
2016-05-02,97.06,4.08
2016-05-03,98.50,4.11
2016-05-04,99.94,4.13
2016-05-06,102.82,4.18
2016-05-07,104.26,4.20
2016-05-09,107.14,4.25
2016-05-10,109.27,4.26
2016-05-11,111.40,4.26
2016-05-12,113.53,4.27
2016-05-13,115.66,4.27
2016-05-14,117.78,4.28
2016-05-17,124.17,4.30
2016-05-18,126.30,4.30
2016-05-19,128.43,4.31
2016-05-20,130.56,4.32
2016-05-21,132.68,4.32
2016-05-23,136.94,4.33
2016-05-24,139.14,4.40
2016-05-25,141.35,4.48
2016-05-26,143.55,4.55
2016-05-27,145.75,4.62
2016-05-28,147.96,4.69
2016-05-30,152.36,4.83
2016-05-31,153.70,4.88
2016-06-01,155.04,4.93
2016-06-02,156.38,4.98
2016-06-03,157.73,5.02
2016-06-04,159.07,5.07
2016-06-06,161.75,5.17
2016-06-07,161.22,5.15
2016-06-08,160.70,5.14
2016-06-09,160.17,5.13
2016-06-10,159.64,5.12
2016-06-11,159.11,5.11
2016-06-13,158.06,5.08
2016-06-14,156.32,5.06
2016-06-15,154.59,5.04
2016-06-16,152.85,5.01
2016-06-17,151.12,4.99
2016-06-18,149.38,4.96
Interesting solution to this problem.
You probably want .redrawGroup() instead of .redraw() inside that handler, and you'll also need to wrap your range inside a dc.js filter object, specifically RangedFilter: unlike crossfilter's dimension.filter() dc.js's chart.filter() takes an object not an array.
Initial Range selection in DC.js chart

X axis time formatting in dc.js

I am trying to create a linear chart in d3.js where i want x-axis to be of following format "27/11 1" where 27 is date, 11 is month and 1 is hour(24 hour time). But with the code i have it looks like only hour is printing. Can someone please help me in getting the format correctly?
<!DOCTYPE html>
<html lang="en">
<meta charset="UTF8">
<body>
<div id="task-submissions-created-at" >
<div class="reset" style="visibility: hidden;">selected: <span class="filter"></span>
reset
</div>
<div id="gender-tasks" style="width:300px; height:300px">
<div class="reset" style="visibility: hidden;">selected: <span class="filter"></span>
reset
</div>
</div>
<script type="text/javascript" src="../js/d3.js" charset="utf-8"></script>
<script type="text/javascript" src="../js/crossfilter.js"></script>
<script type="text/javascript" src="../js/dc.js"></script>
<script type="text/javascript">
//var genderChart=dc.pieChart('#gender-tasks');
var taskSubmissionsChart=dc.lineChart('#task-submissions-created-at');
var parseDate = d3.time.format("%Y-%m-%d %H:%M:%S.%L+05:30").parse;
d3.json("../data/task_submissions.json",function(error,value){
var ndx=crossfilter(value);
value.forEach(function(d) {
d.created_at = parseDate(d.created_at);
});
var timestampDimension=ndx.dimension(function(d){
var x=d.created_at.getHours();
return x;
});
var taskSubmissionId = timestampDimension.group().reduceSum(function(d) {return d.id;});
var minDate =timestampDimension.bottom(1)[0].created_at.getHours();
var maxDate = timestampDimension.top(1)[0].created_at.getHours();
taskSubmissionsChart
.width(768)
.height(480)
//.x(d3.time.scale().domain([d3.min(data,function(d){return d.time}),d3.max(data,function(d){return d.time})]))
.x(d3.scale.linear().domain([minDate,maxDate+1]))
.interpolate('step-before')
.renderArea(true)
.brushOn(false)
.clipPadding(10)
.yAxisLabel("This is the Y Axis!")
.dimension(timestampDimension)
.group(taskSubmissionId)
.xAxis().tickFormat(function(v){
console.log("v: "+v);
return v;
});
taskSubmissionsChart.render();
});
/*
d3.json("../data/users.json", function(error,value) {
var ndx=crossfilter(value);
var runDimension = ndx.dimension(function(d) {
return d.gender;
});
var speedSumGroup = runDimension.group();
genderChart
.width(300)
.height(300)
.slicesCap(4)
.innerRadius(10)
.dimension(runDimension)
.group(speedSumGroup)
.controlsUseVisibility(true);
dc.renderAll();
});
*/
</script>
</body>
</html>

Randomised division selection

Bit of an odd one.... How can I get a website to *random*ly select a division to show each time the page is loaded? I have absolutely no idea where to start.
<body>
<div id="option1">Dog</div>
<div id="option2">Cat</div>
<div id="option3">Rabbit</div>
</body>
Thanks!!
I would recommend doing something in Javascript.
When the body load you should tell Javascript either to remove the once you dont want or to create the one you want.
Update:
This will delete all divs but the one selected randomly.
Html
<head>
<script type="text/javascript" src="script.js"></script>
</head>
<body onload="load()">
<div id="1">
</div>
<div id="2">
</div>
<div id="3">
</div>
</body>
Javascript
function load() {
var amount_of_divs = 3;
var random = Math.floor((Math.random()*amount_of_divs) + 1);
for (var i = 1; i < amount_of_divs + 1; i++) {
if(i == random)
continue;
var div = document.getElementById(i);
div.parentNode.removeChild(div);
}
}

get viewdatadictionary value in partial view

I have a partial view in which I am trying to get the values from the parent view.
This is what I am trying:
#Html.Partial("Shared", "Home", new ViewDataDictionary { { "9595959", "8sd8sds8das8d" } })
And this is the partial view:
<!-- Google Code for apply Conversion Page --> <script type="text/javascript">
/* <![CDATA[ */
var google_conversion_id = "viewdata-number1";
var google_conversion_language = "en";
var google_conversion_format = "2";
var google_conversion_color = "ffffff";
var google_conversion_label = "viewdata-number2"; var google_conversion_value = 0;
/* ]]> */
</script>
<script type="text/javascript"
src="https://www.googleadservices.com/pagead/conversion.js">
</script>
<noscript>
<div style="display:inline;">
<img height="1" width="1" style="border-style:none;" alt=""
src="https://www.googleadservices.com/pagead/conversion/viewdata-number1/?value=0&label=viewdata-number2&guid=ON&script=0"/>
</div>
</noscript>
Is it possible to get the value straight away? I don't have any model or controller assigned to the partial view.
Thx in advance, Laziale
Updated Code:
#{
var variable = ViewData["First"];
<!-- Google Code for apply Conversion Page --> <script type="text/javascript">
/* <![CDATA[ */
var google_conversion_id = variable;
var google_conversion_language = "en";
var google_conversion_format = "2";
var google_conversion_color = "ffffff";
var google_conversion_label = "f6vICKTT6gMQzNOf3gM"; var google_conversion_value = 0;
/* ]]> */
</script>
<script type="text/javascript"
src="https://www.googleadservices.com/pagead/conversion.js">
</script>
<noscript>
<div style="display:inline;">
<img height="1" width="1" style="border-style:none;" alt=""
src="https://www.googleadservices.com/pagead/conversion/1002957260/?value=0&label=f6vICKTT6gMQzNOf3gM&guid=ON&script=0"/>
</div>
</noscript>
}
You think that will work?
Sorry i don't understan your question quite well. You can get ViewData values in partial like this:
var a = (int)ViewData["9595959"]; // variable a will get value "8sd8sds8das8d"
You can also create new ViewDataDictionary extending current view ViewDataDictionary like this:
#Html.Partial("Shared", "Home", new ViewDataDictionary(ViewData) { { "9595959", "8sd8sds8das8d" } })
it will work like this:
#{
var variable = (int)ViewData["First"];
}
<!-- Google Code for apply Conversion Page --> <script type="text/javascript">
/* <![CDATA[ */
var google_conversion_id = #variable;
var google_conversion_language = "en";
var google_conversion_format = "2";
var google_conversion_color = "ffffff";
var google_conversion_label = "f6vICKTT6gMQzNOf3gM"; var google_conversion_value = 0;
/* ]]> */
</script>
<script type="text/javascript" src="https://www.googleadservices.com/pagead/conversion.js">
</script>
<noscript>
<div style="display:inline;">
<img height="1" width="1" style="border-style:none;" alt=""
src="https://www.googleadservices.com/pagead/conversion/1002957260/?value=0&label=f6vICKTT6gMQzNOf3gM&guid=ON&script=0"/>
</div>
</noscript>
link
Here is an example of someone doing the same thing I think you're wanting to do.
Also, within your partial, just do ViewData["9595959"] to hook into that specific data.

How can I solve append issue for an image using ajax

My first script provides to random image as you can see below
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js"></script>
<!-- include Cycle plugin -->
<script type="text/javascript" src="http://cloud.github.com/downloads/malsup/cycle/jquery.cycle.all.latest.js"></script>
<script type="text/javascript">
var $t = jQuery.noConflict();
$t(function () {
$t('.slideshow').cycle({
fx: 'fade'
});
});
</script>
It works when I add some images like that
<div class="news_area_left">
<div class="slideshow" style="position: relative; ">
<img src="../../banner_image/nemo.jpg" width="154px" height="108px"/>
<img src="../../banner_image/up.jpg" width="154px" height="108px" />
</div>
</div>
But when I add my second script which get images as you can see
<script type="text/javascript">
$(function () {
$.ajax({
type: "get", url: "Home/Oku", data: {}, dataType: "json",
success: function (data) {
for (var i = 0; i < data.length; i++) {
var newFirmDiv= $(' <img src="../../banner_image/' + data[i] + '" width="154px" height="108px"/>');
$(".slideshow").append(newFirmDiv);
}
}
});
});
</script>
Finally I try to use my dynamic images in my "slideshow div" but the effect does not work
<div class="news_area_left">
<div class="slideshow" style="position: relative; ">
</div>
</div>
You need to run $t('.slideshow').cycle after you have dynamically inserted your images. Also you need to append to the "slideshow" class and not the "firmShowCase" class.
See this jsFiddle I've created http://jsfiddle.net/davew9999/sgUeq/
HTML
<div class="news_area_left">
<div class="slideshow" style="position: relative; ">
<img src="http://activephilosophy.files.wordpress.com/2009/09/number1.jpg" width="154px" height="108px"/>
<img src="http://www.clker.com/cliparts/h/Y/i/C/Y/W/red-rounded-square-with-number-2-md.png" width="154px" height="108px"/>
</div>
</div>​
JavaScript
var $t = jQuery.noConflict();
var newFirmDiv = $t('<img src="http://www.mosamuse.com/wp-content/uploads/2012/05/number3.png" width="154px" height="108px"/>');
$t(".slideshow").append(newFirmDiv);
var anotherDiv = $t('<img src="http://2.bp.blogspot.com/-_A_8UYb0zIQ/Te5lpI9iZ3I/AAAAAAABgWk/sErDyHjEhPw/s1600/number-4.jpg" width="154px" height="108px"/>');
$t(".slideshow").append(anotherDiv);
$t(function() {
$t('.slideshow').cycle({
fx: 'fade'
});
});

Resources