How to make qtip2 respond to dynamic user input - javascript

I have the following working code. It takes the input data and display the histogram based on a threshold.
"use strict";
var histograms,
thresholds = [];
var input_data = [{
"threshold": 1.5,
"histograms": [{
"sample": "Sample1",
"values": [{
"score": 6.7530200000000002,
"celltype": "Bcells"
}, {
"score": 11.432763461538459,
"celltype": "DendriticCells"
}, {
"score": 25.823089615384621,
"celltype": "Macrophages"
}, {
"score": 9.9911211538461551,
"celltype": "gdTCells"
}, {
"score": 7.817228076923076,
"celltype": "StemCells"
}, {
"score": 17.482806923076922,
"celltype": "StromalCells"
}, {
"score": 29.335427692307697,
"celltype": "Monocytes"
}, {
"score": 28.914959615384621,
"celltype": "Neutrophils"
}, {
"score": 13.818888461538467,
"celltype": "NKCells"
}, {
"score": 9.5030688461538464,
"celltype": "abTcells"
}]
}]
}, {
"threshold": 2,
"histograms": [{
"sample": "Sample1",
"values": [{
"score": 5.1335499999999996,
"celltype": "Bcells"
}, {
"score": 16.076072499999999,
"celltype": "DendriticCells"
}, {
"score": 46.182032499999998,
"celltype": "Macrophages"
}, {
"score": 6.5895700000000001,
"celltype": "gdTCells"
}, {
"score": 5.3218800000000002,
"celltype": "StemCells"
}, {
"score": 53.643625,
"celltype": "StromalCells"
}, {
"score": 85.1618225,
"celltype": "Monocytes"
}, {
"score": 55.559129999999996,
"celltype": "Neutrophils"
}, {
"score": 7.6717524999999984,
"celltype": "NKCells"
}, {
"score": 6.3277800000000006,
"celltype": "abTcells"
}]
}]
}];
processData(input_data);
function processData(data) {
histograms = data[0].histograms.map(function(data) {
return {
title: data.sample,
dataset: new Plottable.Dataset(),
dataByThreshold: {},
load: function(threshold) {
this.dataset.data(this.dataByThreshold[threshold]);
}
};
});
data.forEach(function(data) {
var threshold = data.threshold;
thresholds.push(threshold);
data.histograms.forEach(function(histogram, i) {
histograms[i].dataByThreshold[threshold] = histogram.values;
});
});
// Here we generalize the slide bar maximum threshold
$('#threshold').attr('max', thresholds.length - 1);
updateDatasets(thresholds[0]);
buildPlots();
updateThreshold();
}
$('#threshold').change(updateThreshold);
function updateThreshold() {
// This is where the user input updating slider
// takes place and where the QTIP is in action.
var thresholdIndex = parseInt($('#threshold').val(), 10);
$("#foldchange_threshold").html(thresholds[thresholdIndex]);
updateDatasets(thresholds[thresholdIndex]);
$(".tooltipped rect").qtip({
overwrite: true,
position: {
my: "bottom middle",
at: "top middle"
},
style: {
classes: "qtip-light"
}
});
}
function updateDatasets(threshold) {
histograms.forEach(function(histogram) {
histogram.load(threshold);
});
}
function buildPlots() {
var $histogramContainer = $('#sample-histograms');
histograms.forEach(function(histogram, index) {
var elementId = "sample-histogram-" + index;
$(document.createElementNS('http://www.w3.org/2000/svg', 'svg'))
.css({
width: '200px',
height: '200px',
display: 'inline-block'
})
.attr('id', elementId)
.appendTo($histogramContainer);
plotSampleHistogram(histogram.title, histogram.dataset, '#' + elementId);
});
}
function plotSampleHistogram(title, dataset, targetElement) {
var xScale = new Plottable.Scales.Category(),
yScale = new Plottable.Scales.Linear(),
colorScale = new Plottable.Scales.Color();
var xAxis = new Plottable.Axes.Numeric(xScale, "bottom"),
yAxis = new Plottable.Axes.Numeric(yScale, "left"),
titleLabel = new Plottable.Components.TitleLabel(title);
yScale.domainMin(0);
var plot = new Plottable.Plots.Bar()
.addDataset(dataset)
.x(function(d) { return d.celltype; }, xScale)
.y(function(d) { return d.score; }, yScale)
.attr("fill", function(d) { return d.celltype; }, colorScale)
.attr("title", function(d) { return '<div class="bartip">' + d.celltype + " (" + d.score.toFixed(2) + ') </div>'; })
.addClass("tooltipped");
new Plottable.Components.Table([
[null, titleLabel],
[yAxis, plot],
[null, xAxis]
]).renderTo(targetElement);
}
function drawHistogramLegend(targetElement) {
new Plottable.Components.Legend(colorScale)
.renderTo(targetElement);
}
<html>
<head>
<link href="https://cdnjs.cloudflare.com/ajax/libs/plottable.js/1.15.0/plottable.css" rel="stylesheet" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/qtip2/2.2.1/basic/jquery.qtip.css" rel="stylesheet" />
</head>
<body>
<!-- Display the sliding bar -->
<input id="threshold" type="range" min="0" max="1" step="1" value="0" />
<br>
<!-- Show foldchange threshold -->
<div id="foldchange_threshold" style="display: inline-block; align:center;"></div>
<!-- Show histograms -->
<div id="sample-histograms"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/plottable.js/1.15.0/plottable.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/qtip2/2.2.1/basic/jquery.qtip.js"></script>
</body>
</html>
If you run the code you can notice that the histogram will change as you drag the slider. AND a tool tip will appear if you place your mouse in one of the histogram bar.
The problem I'm facing is that the value of the tool tip does not change upon the user input to the sliding bar. For example with threshold=1.5 the Bcell score is 6.75 and threshold=2, the score is 5.13. This is not reflected in the tool tip.
How can resolve this issue?

It looks like QTip2 modifies the "title" attribute in some way, cacheing the previous information under "oldtitle". I got it to work by switching the title to a different attribute:
plot.attr("qtip2-title", function(d) {
return '<div class="bartip">' + d.celltype + " (" + d.score.toFixed(2) + ') </div>';
});
Then, we tell QTip2 to look up the "qtip2-title" property for the tooltip text:
$(".tooltipped .content rect").qtip({
// ... other setup here...
content: {
text: function() {
return $(this).attr("qtip2-title");
}
}
});
(Note the use of .content to avoid selecting unwanted rectangles).
Also, I noticed that currently xAxis is an Axes.Numeric, which will not work with Scales.Category. Use Axes.Category instead.
"use strict";
var histograms,
thresholds = [];
var input_data = [{
"threshold": 1.5,
"histograms": [{
"sample": "Sample1",
"values": [{
"score": 6.7530200000000002,
"celltype": "Bcells"
}, {
"score": 11.432763461538459,
"celltype": "DendriticCells"
}, {
"score": 25.823089615384621,
"celltype": "Macrophages"
}, {
"score": 9.9911211538461551,
"celltype": "gdTCells"
}, {
"score": 7.817228076923076,
"celltype": "StemCells"
}, {
"score": 17.482806923076922,
"celltype": "StromalCells"
}, {
"score": 29.335427692307697,
"celltype": "Monocytes"
}, {
"score": 28.914959615384621,
"celltype": "Neutrophils"
}, {
"score": 13.818888461538467,
"celltype": "NKCells"
}, {
"score": 9.5030688461538464,
"celltype": "abTcells"
}]
}]
}, {
"threshold": 2,
"histograms": [{
"sample": "Sample1",
"values": [{
"score": 5.1335499999999996,
"celltype": "Bcells"
}, {
"score": 16.076072499999999,
"celltype": "DendriticCells"
}, {
"score": 46.182032499999998,
"celltype": "Macrophages"
}, {
"score": 6.5895700000000001,
"celltype": "gdTCells"
}, {
"score": 5.3218800000000002,
"celltype": "StemCells"
}, {
"score": 53.643625,
"celltype": "StromalCells"
}, {
"score": 85.1618225,
"celltype": "Monocytes"
}, {
"score": 55.559129999999996,
"celltype": "Neutrophils"
}, {
"score": 7.6717524999999984,
"celltype": "NKCells"
}, {
"score": 6.3277800000000006,
"celltype": "abTcells"
}]
}]
}];
processData(input_data);
function processData(data) {
histograms = data[0].histograms.map(function(data) {
return {
title: data.sample,
dataset: new Plottable.Dataset(),
dataByThreshold: {},
load: function(threshold) {
this.dataset.data(this.dataByThreshold[threshold]);
}
};
});
data.forEach(function(data) {
var threshold = data.threshold;
thresholds.push(threshold);
data.histograms.forEach(function(histogram, i) {
histograms[i].dataByThreshold[threshold] = histogram.values;
});
});
// Here we generalize the slide bar maximum threshold
$('#threshold').attr('max', thresholds.length - 1);
updateDatasets(thresholds[0]);
buildPlots();
updateThreshold();
}
$('#threshold').change(updateThreshold);
function updateThreshold() {
// This is where the user input updating slider
// takes place and where the QTIP is in action.
var thresholdIndex = parseInt($('#threshold').val(), 10);
$("#foldchange_threshold").html(thresholds[thresholdIndex]);
updateDatasets(thresholds[thresholdIndex]);
$(".tooltipped .content rect").qtip({
overwrite: true,
position: {
my: "bottom middle",
at: "top middle"
},
style: {
classes: "qtip-light"
},
content: {
text: function() {
return $(this).attr("qtip2-title");
}
}
});
}
function updateDatasets(threshold) {
histograms.forEach(function(histogram) {
histogram.load(threshold);
});
}
function buildPlots() {
var $histogramContainer = $('#sample-histograms');
histograms.forEach(function(histogram, index) {
var elementId = "sample-histogram-" + index;
$(document.createElementNS('http://www.w3.org/2000/svg', 'svg'))
.css({
width: '200px',
height: '200px',
display: 'inline-block'
})
.attr('id', elementId)
.appendTo($histogramContainer);
plotSampleHistogram(histogram.title, histogram.dataset, '#' + elementId);
});
}
function plotSampleHistogram(title, dataset, targetElement) {
var xScale = new Plottable.Scales.Category(),
yScale = new Plottable.Scales.Linear(),
colorScale = new Plottable.Scales.Color();
var xAxis = new Plottable.Axes.Category(xScale, "bottom"),
yAxis = new Plottable.Axes.Numeric(yScale, "left"),
titleLabel = new Plottable.Components.TitleLabel(title);
xAxis.tickLabelAngle(-90)
yScale.domainMin(0);
var plot = new Plottable.Plots.Bar()
.addDataset(dataset)
.x(function(d) { return d.celltype; }, xScale)
.y(function(d) { return d.score; }, yScale)
.attr("fill", function(d) { return d.celltype; }, colorScale)
.attr("qtip2-title", function(d) { return '<div class="bartip">' + d.celltype + " (" + d.score.toFixed(2) + ') </div>'; })
.addClass("tooltipped");
new Plottable.Components.Table([
[null, titleLabel],
[yAxis, plot],
[null, xAxis]
]).renderTo(targetElement);
}
function drawHistogramLegend(targetElement) {
new Plottable.Components.Legend(colorScale)
.renderTo(targetElement);
}
<html>
<head>
<link href="https://cdnjs.cloudflare.com/ajax/libs/plottable.js/1.15.0/plottable.css" rel="stylesheet" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/qtip2/2.2.1/basic/jquery.qtip.css" rel="stylesheet" />
</head>
<body>
<!-- Display the sliding bar -->
<input id="threshold" type="range" min="0" max="1" step="1" value="0" />
<br>
<!-- Show foldchange threshold -->
<div id="foldchange_threshold" style="display: inline-block; align:center;"></div>
<!-- Show histograms -->
<div id="sample-histograms"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/plottable.js/1.15.0/plottable.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/qtip2/2.2.1/basic/jquery.qtip.js"></script>
<script src="histo.js"></script>
</body>
</html>
Hopefully this works for you! Glad to see you're using Plottable.
P.S. We're working on getting a more detailed tooltip tutorial for the website. Stay tuned.

Related

prebid.js ad is not getting rendered

I have setup prebid.js with single adaptor configured on test page. I am getting the ad response from adaptor and I can see the pbjs.getBidResponses() object is present still ad is not getting rendered on the page.
you can visit test page
standard prebid setup as follows
JAVSCRIPT
var sizes = [
[300, 250]
];
var PREBID_TIMEOUT = 1000;
var FAILSAFE_TIMEOUT = 3000;
var adUnits = [{
code: '/19968336/header-bid-tag-1',
mediaTypes: {
banner: {
sizes: sizes
}
},
bids: [{
bidder: 'incrementx',
params: {
placementId: 'PNX-HB-R787915V41024E'
}
}]
}];
// ======== DO NOT EDIT BELOW THIS LINE =========== //
var googletag = googletag || {};
googletag.cmd = googletag.cmd || [];
googletag.cmd.push(function () {
googletag.pubads().disableInitialLoad();
});
var pbjs = pbjs || {};
pbjs.que = pbjs.que || [];
pbjs.que.push(function () {
pbjs.addAdUnits(adUnits);
pbjs.requestBids({
bidsBackHandler: initAdserver,
timeout: PREBID_TIMEOUT
});
});
function initAdserver() {
if (pbjs.initAdserverSet) return;
pbjs.initAdserverSet = true;
googletag.cmd.push(function () {
pbjs.setTargetingForGPTAsync && pbjs.setTargetingForGPTAsync();
googletag.pubads().refresh();
});
}
// in case PBJS doesn't load
setTimeout(function () {
initAdserver();
}, FAILSAFE_TIMEOUT);
googletag.cmd.push(function () {
googletag.defineSlot('/19968336/header-bid-tag-1', sizes, 'div-1')
.addService(googletag.pubads());
googletag.pubads().collapseEmptyDivs();
googletag.pubads().enableSingleRequest();
googletag.enableServices();
});
HTML
<div id='div-1'>
<script type='text/javascript'>
googletag.cmd.push(function () {
googletag.display('div-1');
});
</script>
</div>
ADAPTOR Response
{
"vzhPlacementId": "<placement-id>",
"bid": "<bid>",
"adWidth": "300",
"adHeight": "250",
"cpm": "0.017442",
"ad": "<ad-tag>",
"slotBidId": "<slot-id>",
"statusText": "Vertoz:Success"
}
pbjs.getBidResponses() output
{
"/19968336/header-bid-tag-1": {
"bids": [
{
"bidderCode": "incrementx",
"width": 300,
"height": 250,
"statusMessage": "Bid available",
"adId": "389575b4d6d5f1",
"requestId": "2b7446c2969f1f",
"transactionId": "a6a81b3e-8cf7-4d71-bc7e-34c283e1a746",
"auctionId": "4455d9a4-4364-4f9d-bd1a-d7f0a7fd56e4",
"mediaType": "banner",
"source": "client",
"cpm": 0.017442,
"currency": "USD",
"ttl": 300,
"creativeId": 0,
"netRevenue": false,
"meta": {
"mediaType": "banner",
"advertiserDomains": [],
"dchain": {
"ver": "1.0",
"complete": 0,
"nodes": [
{
"name": "incrementx"
}
]
}
},
"ad": "<ad-tag>",
"adapterCode": "incrementx",
"originalCpm": "0.017442",
"originalCurrency": "USD",
"responseTimestamp": 1656921876245,
"requestTimestamp": 1656921875927,
"bidder": "incrementx",
"adUnitCode": "/19968336/header-bid-tag-1",
"timeToRespond": 318,
"pbLg": "0.00",
"pbMg": "0.00",
"pbHg": "0.01",
"pbAg": "0.00",
"pbDg": "0.01",
"pbCg": "",
"size": "300x250",
"adserverTargeting": {
"hb_bidder": "incrementx",
"hb_adid": "389575b4d6d5f1",
"hb_pb": "0.00",
"hb_size": "300x250",
"hb_source": "client",
"hb_format": "banner",
"hb_adomain": ""
},
"status": "targetingSet"
}
]
}
}
pbjs.getAllPrebidWinningBids() & pbjs.getAllWinningBids() output
[]
this is the output I am getting
not able to find the issue, there is only 1 adaptor integrated so in all cases the bid should win, not sure am I missing something in setup?. Any help would be appreciated, thank you
Because this line is a copy from the prebid.org docs:
googletag.defineSlot('/19968336/header-bid-tag-1', sizes, 'div-1')
I don't think you have your own GAM account configured correctly.
You'll need to have a GAM account and switch the first parameter of defineSlot to be your own GAM ad unit code.
You'll want to follow the postbid instructions if you want to avoid using GAM.

AmChart : hide event

I'm using amChart with the plugin dataLoader to load data and eventData so I have something like this :
var defaultStockChartData = {
"dataLoader": {
"url": "urlToMyFile.csv",
"format": "csv",
"delimiter": ",",
"useColumnNames": true
},
/**
* data loader for events data
*/
"eventDataLoader": {
"url": urlToMyFile.scv,
"async": true,
"postProcess": function(data) {
for (var x in data) {
var color = "#85CDE6";
switch (data[x].Type) {
case 'A':
color = "#85CDE6";
break;
case 'B':
color = "#85C56E6";
break;
default:
color = "#cccccc";
break;
}
data[x] = {
"type": "pin",
"graph": "g1",
"backgroundColor": color,
"date": data[x].Date,
"text": data[x].Type,
"description": data[x].Description
};
}
return data;
}
}
...
}
Now what I need to do is a checkbox that shows all the event on the graph with the type 'A' when it's checked and hide all the event with the type 'A' when it's unchecked.
How I can I access the events of my chart and hide them follow their type?
A better way to do this is to modify the event data directly and toggle each element's graph property to null or the original graph to show/hide them so you don't have to hack around the charts' bullet handling on zoom and other events. For example:
HTML:
<div>
<label>Hide Event A <input type="checkbox" class="hide-event" data-event="A"></label>
<label>Hide Event B <input type="checkbox" class="hide-event" data-event="B"></label>
</div>
JS:
//show/hide events based on selected checkbox
Array.prototype.forEach.call(
document.querySelectorAll('.hide-event'),
function(checkbox) {
checkbox.addEventListener('change', function() {
var event = checkbox.dataset.event;
chart.dataSets[0].stockEvents.forEach(function(eventItem) {
if (eventItem.text === event) {
if (checkbox.checked) {
//copy graph reference to a dummy value and null out the original graph
eventItem.oldGraph = eventItem.graph;
eventItem.graph = null;
}
else {
//restore original graph and null out copy/dummy reference
eventItem.graph = eventItem.oldGraph;
eventItem.oldGraph = null;
}
}
});
chart.validateData(); //redraw the chart
});
}
);
Full demo below:
var chartData = [];
var eventData = [];
generateChartData();
//show/hide events based on selected checkbox
Array.prototype.forEach.call(
document.querySelectorAll('.hide-event'),
function(checkbox) {
checkbox.addEventListener('change', function() {
var event = checkbox.dataset.event;
chart.dataSets[0].stockEvents.forEach(function(eventItem) {
if (eventItem.text === event) {
if (checkbox.checked) {
//copy graph reference to a dummy value and null out the original graph
eventItem.oldGraph = eventItem.graph;
eventItem.graph = null;
}
else {
//restore original graph and null out copy/dummy reference
eventItem.graph = eventItem.oldGraph;
eventItem.oldGraph = null;
}
}
});
chart.validateData(); //redraw the chart
});
}
);
function generateChartData() {
var firstDate = new Date( 2012, 0, 1 );
firstDate.setDate( firstDate.getDate() - 500 );
firstDate.setHours( 0, 0, 0, 0 );
for ( var i = 0; i < 500; i++ ) {
var newDate = new Date( firstDate );
newDate.setDate( newDate.getDate() + i );
var a = Math.round( Math.random() * ( 40 + i ) ) + 100 + i;
var b = Math.round( Math.random() * 100000000 );
chartData.push( {
"date": newDate,
"value": a,
"volume": b
} );
if ((i + 1) % 8 === 0) {
eventData.push({
"date": newDate,
"type": "sign",
"backgroundColor": "#85CDE6",
"graph": "g1",
"text": (i + 1) % 5 == 0 ? "B" : "A",
"description": "Event " + ((i + 1) % 5 == 0 ? "B" : "A") + " at index " + i
})
}
}
}
var chart = AmCharts.makeChart( "chartdiv", {
"type": "stock",
"theme": "light",
"dataSets": [ {
"color": "#b0de09",
"fieldMappings": [ {
"fromField": "value",
"toField": "value"
}, {
"fromField": "volume",
"toField": "volume"
} ],
"dataProvider": chartData,
"categoryField": "date",
// EVENTS
"stockEvents": eventData
} ],
"panels": [ {
"title": "Value",
"stockGraphs": [ {
"id": "g1",
"valueField": "value"
} ],
"stockLegend": {
"valueTextRegular": " ",
"markerType": "none"
}
} ],
"chartScrollbarSettings": {
"graph": "g1"
},
"chartCursorSettings": {
"valueBalloonsEnabled": true,
"graphBulletSize": 1,
"valueLineBalloonEnabled": true,
"valueLineEnabled": true,
"valueLineAlpha": 0.5
}
} );
#chartdiv {
width: 100%;
height: 500px;
}
<script src="https://www.amcharts.com/lib/3/amcharts.js"></script>
<script src="https://www.amcharts.com/lib/3/serial.js"></script>
<script src="https://www.amcharts.com/lib/3/amstock.js"></script>
<script src="https://www.amcharts.com/lib/3/themes/light.js"></script>
<div>
<label>Hide Event A <input type="checkbox" class="hide-event" data-event="A"></label>
<label>Hide Event B <input type="checkbox" class="hide-event" data-event="B"></label>
</div>
<div id="chartdiv"></div>
I didn't find a way to do it with AmChart so I did it in javascript (not by type but just need to check the value)
First I need this function :
function hideShowGraphEvent()
{
if($("#chxEventA").prop("checked"))
{
$("g.amcharts-graph-bullet").show();
}
else
{
$("g.amcharts-graph-bullet").hide();
}
}
And call it each time you check or uncheck the box :
$("#chxEventA").change(function()
{
hideShowGraphEvent();
});
But if you use zoom (like me) it will stop working when you zoom so you need to call the function each time you zoom :
"listeners" : [
{
"event": "zoomed",
"method": function()
{
hideShowGraphEvent();
}
},
...
]

Create drilldown fusion chart on the same page

You will get results on the fusioncharts website if you search up what I asked, but it is not exactly what I am looking for.
I am querying data from a MySQL database, and putting this data into a fusion chart to display on my webpage. I want there to be 2 graphs on the same page, and when you click on one of the datapoints on the parent graph, the child graph will display the "drilled down" graph. How can I do this? As of right now I can press on the parent graph and it will open the child graph on a new webpage. This is the code for the home page with the parent graph. The file is named "dept.php".
<?php
/*Include the `fusioncharts.php` file that contains functions
to embed the charts.
*/
include("includes/fusioncharts.php");
// Establish a connection to the database. Variables defined before
$dbhandle = new mysqli($hostdb, $userdb, $passdb, $namedb);
// Render an error message, to avoid abrupt failure, if the database connection parameters are incorrect
if ($dbhandle->connect_error) {
exit("There was an error with your connection: ".$dbhandle->connect_error);
}
?>
<html>
<head>
<title>FusionCharts XT - Column 2D Chart - Data from a database</title>
<link rel="stylesheet" type="text/css" href="css/style.css" />
<!-- Include the `fusioncharts.js` file. This file is needed to render the chart. Ensure that the path to this JS file is correct. Otherwise, it may lead to JavaScript errors. -->
<script src="fusioncharts/js/fusioncharts.js"></script>
</head>
<body>
<?php
// Form the SQL query that returns the top 10 most populous countries
$strQuery = "SELECT Department, SUM(Quantity) AS Quantity FROM Scrap GROUP BY Department ORDER BY Department";
// Execute the query, or else return the error message.
$result = $dbhandle->query($strQuery) or exit("Error code ({$dbhandle->errno}): {$dbhandle->error}");
// If the query returns a valid response, prepare the JSON string
if ($result) {
// The `$arrData` array holds the chart attributes and data
$arrData = array(
"chart" => array(
"caption" => "Sample Chart",
"paletteColors" => "#0075c2",
"bgColor" => "#ffffff",
"borderAlpha"=> "20",
"canvasBorderAlpha"=> "0",
"usePlotGradientColor"=> "0",
"plotBorderAlpha"=> "10",
"showXAxisLine"=> "1",
"xAxisLineColor" => "#999999",
"showValues"=> "0",
"divlineColor" => "#999999",
"divLineIsDashed" => "1",
"showAlternateHGridColor" => "0"
)
);
$arrData["data"] = array();
// Push the data into the array
while($row = mysqli_fetch_array($result)) {
array_push($arrData["data"], array(
"label" => $row["Department"],
"value" => $row["Quantity"],
"link" => "deptDrillDown.php?Department=".$row["Department"]
)
);
}
/*JSON Encode the data to retrieve the string containing the JSON representation of the data in the array. */
$jsonEncodedData = json_encode($arrData);
/*Create an object for the column chart. Initialize this object using the FusionCharts PHP class constructor. The constructor is used to initialize
the chart type, chart id, width, height, the div id of the chart container, the data format, and the data source. */
$columnChart = new FusionCharts("column2D", "myFirstChart" , 600, 300, "chart-1", "json", $jsonEncodedData);
// Render the chart
$columnChart->render();
// Close the database connection
$dbhandle->close();
}
?>
<div id="chart-1"><!-- Fusion Charts will render here--></div>
</body>
</html>
And then here is the other page that contains the child graph. The file is named "deptDrillDown.php".
<?php
/* Include the `includes/fusioncharts.php` file that contains functions to embed the charts.*/
include("includes/fusioncharts.php");
// Establish a connection to the database. Variables defined earlier
$dbhandle = new mysqli($hostdb, $userdb, $passdb, $namedb);
/*Render an error message, to avoid abrupt failure, if the database connection parameters are incorrect */
if ($dbhandle->connect_error) {
exit("There was an error with your connection: ".$dbhandle->connect_error);
}
?>
<html>
<head>
<title>FusionCharts XT - Column 2D Chart</title>
<link rel="stylesheet" type="text/css" href="css/style.css" />
<!-- Include the `fusioncharts.js` file. This file is needed to render the chart. Ensure that the path to this JS file is correct. Otherwise, it may lead to JavaScript errors. -->
<script src="fusioncharts/js/fusioncharts.js"></script>
</head>
<body>
<?php
// Get the country code from the GET parameter
$countryCode = $_GET["Department"];
// Form the SQL query that returns the top 10 most populous cities in the selected country
$cityQuery = "SELECT ScrapDate, SUM(Quantity) AS Quantity FROM Scrap WHERE Department = ? GROUP BY ScrapDate ORDER BY ScrapDate";
// Prepare the query statement
$cityPrepStmt = $dbhandle->prepare($cityQuery);
// If there is an error in the statement, exit with an error message
if($cityPrepStmt === false) {
exit("Error while preparing the query to fetch data from City Table. ".$dbhandle->error);
}
// Bind the parameters to the query prepared
$cityPrepStmt->bind_param("s", $countryCode);
// Execute the query
$cityPrepStmt->execute();
// Get the results from the query executed
$cityResult = $cityPrepStmt->get_result();
// If the query returns a valid response, prepare the JSON string
if ($cityResult) {
/* Form the SQL query that will return the country name based on the country code. The result of the above query contains only the country code.
The country name is needed to be rendered as a caption for the chart that shows the 10 most populous cities */
$countryNameQuery = "SELECT ScrapDate FROM Scrap WHERE Department = ?";
// Prepare the query statement
$countryPrepStmt = $dbhandle->prepare($countryNameQuery);
// If there is an error in the statement, exit with an error message
if($countryPrepStmt === false) {
exit("Error while preparing the query to fetch data from Country Table. ".$dbhandle->error);
}
// Bind the parameters to the query prepared
$countryPrepStmt->bind_param("s", $countryCode);
// Execute the query
$countryPrepStmt->execute();
// Bind the country name to the variable `$countryName`
$countryPrepStmt->bind_result($countryName);
// Fetch the result from prepared statement
$countryPrepStmt->fetch();
// The `$arrData` array holds the chart attributes and data
$arrData = array(
"chart" => array(
"caption" => "Top 10 Most Populous Cities in ".$countryName,
"paletteColors" => "#0075c2",
"bgColor" => "#ffffff",
"borderAlpha"=> "20",
"canvasBorderAlpha"=> "0",
"usePlotGradientColor"=> "0",
"plotBorderAlpha"=> "10",
"showXAxisLine"=> "1",
"xAxisLineColor" => "#999999",
"showValues"=> "0",
"divlineColor" => "#999999",
"divLineIsDashed" => "1",
"showAlternateHGridColor" => "0"
)
);
$arrData["data"] = array();
// Push the data into the array
while($row = $cityResult->fetch_array()) {
array_push($arrData["data"], array(
"label" => $row["ScrapDate"],
"value" => $row["Quantity"]
)
);
}
/*JSON Encode the data to retrieve the string containing the JSON representation of the data in the array. */
$jsonEncodedData = json_encode($arrData);
/*Create an object for the column chart using the FusionCharts PHP class constructor. Syntax for the constructor is `FusionCharts("type of chart",
"unique chart id", "width of chart", "height of chart", "div id to render the chart", "data format", "data source")`.*/
$columnChart = new FusionCharts("column2D", "myFirstChart" , 600, 300, "chart-1", "json", $jsonEncodedData);
// Render the chart
$columnChart->render();
// Close the database connection
$dbhandle->close();
}
?>
Back
<div id="chart-1"><!-- Fusion Charts will render here--></div>
</body>
</html>
n number of charts can be rendered in a single page using FusionCharts.
Store their chart references, e.g. in an associative array.
Use the dataplotClick event to capture the event being generated by clicking on a data.
Inside the callback, use the setJSONData to update the child chart, one wanna update.
A dummy code for this would be:
FusionCharts.ready(function () {
var chart1 = new FusionCharts({
type: 'msstackedcolumn2d',
renderAt: 'chart-container1',
width: '550',
height: '350',
dataFormat: 'json',
dataSource: {
// enter the json data here
},
"events": {
"dataplotClick": function(eventObj, dataObj) {
/* so every time a dataClickEvent is being triggered from the data plot,
a new json `json2` is fetched from a sql query and
chart2 is updated with it.*/
chart2.setJSONData(json2);
}
}
}
}).render();
});
Couple of days back I created this fiddle, hope this becomes useful here too. Instead of doing a SQL query, here we have a generalised data, every time a click is made, it internally makes a function call, and creates a data dynamically out of it. Lot of function calls for making it entirely dynamic might make the code look complex. But the basic philosophy I shared in the dummy code avobe is the same here.
The snippet version for the code for a quick reference.Better to run the result in full page to check whats exactly happening.
function getData() {
var arr = [{
seriesname: "Book A",
data: [{
"label": "Paper",
"value": 100
}, {
"label": "Promotion",
"value": 150
}, {
"label": "Transportation",
"value": 175
}, {
"label": "Royality",
"value": 200
}, {
"label": "Printing",
"value": 250
}, {
"label": "Binding",
"value": 275
}]
}, {
seriesname: "Book B",
data: [{
"label": "Paper",
"value": 130
}, {
"label": "Promotion",
"value": 110
}, {
"label": "Transportation",
"value": 155
}, {
"label": "Royality",
"value": 250
}, {
"label": "Printing",
"value": 210
}, {
"label": "Binding",
"value": 215
}]
}, {
seriesname: "Book C",
data: [{
"label": "Paper",
"value": 70
}, {
"label": "Promotion",
"value": 180
}, {
"label": "Transportation",
"value": 125
}, {
"label": "Royality",
"value": 150
}, {
"label": "Printing",
"value": 290
}, {
"label": "Binding",
"value": 245
}]
}, {
seriesname: "Book D",
data: [{
"label": "Paper",
"value": 150
}, {
"label": "Promotion",
"value": 100
}, {
"label": "Transportation",
"value": 105
}, {
"label": "Royality",
"value": 125
}, {
"label": "Printing",
"value": 278
}, {
"label": "Binding",
"value": 235
}]
}, {
seriesname: "Book E",
data: [{
"label": "Paper",
"value": 60
}, {
"label": "Promotion",
"value": 250
}, {
"label": "Transportation",
"value": 115
}, {
"label": "Royality",
"value": 189
}, {
"label": "Printing",
"value": 190
}, {
"label": "Binding",
"value": 285
}]
}, {
seriesname: "Book F",
data: [{
"label": "Paper",
"value": 190
}, {
"label": "Promotion",
"value": 200
}, {
"label": "Transportation",
"value": 160
}, {
"label": "Royality",
"value": 148
}, {
"label": "Printing",
"value": 178
}, {
"label": "Binding",
"value": 295
}]
}];
return arr;
}
function getValues(componentName) {
var i,
j,
arr = getData(),
valueArr = [],
len1;
for (i = 0, len = arr.length; i < len; i += 1) {
for (j = 0, len1 = arr[i].data.length; j < len1; j += 1) {
if (arr[i].data[j].label === componentName) {
valueArr.push({
value: arr[i].data[j].value
});
break;
}
}
}
return [{
seriesname: componentName,
data: valueArr
}];
}
function getProducts(componentName) {
var arr = getData(),
productArr = [];
for (i = 0, len = arr.length; i < len; i += 1) {
for (j = 0; j < arr[i].data.length; j += 1) {
if (arr[i].data[j].label === componentName) {
productArr.push({
"label": arr[i].seriesname,
"value": arr[i].data[j].value
});
break;
}
}
}
return productArr;
}
function getComponents(label, value) {
var arr = getData(),
sum,
i,
j,
len,
len1,
obj =
componentArr = [];
if (label === undefined) {
label = true;
}
if (value === undefined) {
value = true;
}
for (i = 0, len = arr[0].data.length; i < len; i += 1) {
sum = 0;
obj = {};
for (j = 0, len1 = arr.length; j < len1; j += 1) {
sum += arr[j].data[i].value;
}
if (label) {
obj.label = arr[0].data[i].label;
}
if (value) {
obj.value = sum;
}
componentArr.push(obj);
}
return componentArr;
}
function getSeriesNames() {
var arr = getData(),
seriesName = [];
for (i = 0, len = arr.length; i < len; i += 1) {
seriesName.push({
"label": arr[i].seriesname
});
}
return seriesName;
}
function getMode() {
var e = document.getElementById("interaction");
return e.options[e.selectedIndex].value;
}
FusionCharts.ready(function() {
var lastClickedId = true;
var pieChart = new FusionCharts({
type: 'pie2d',
renderAt: 'pieContainer',
width: '600',
height: '400',
dataFormat: 'json',
dataSource: {
"chart": {
"caption": "Expenditures Incurred in Publishing a Book",
"subCaption": "Component-wise BreakUp",
"enableMultiSlicing": "0",
"bgcolor": "FFFFFF",
"showvalues": "1",
"showpercentvalues": "1",
"showborder": "0",
"showplotborder": "0",
"showlegend": "1",
"legendborder": "0",
"legendposition": "bottom",
"enablesmartlabels": "1",
"use3dlighting": "0",
"showshadow": "0",
"legendbgcolor": "#CCCCCC",
"legendbgalpha": "20",
"legendborderalpha": "0",
"legendshadow": "0",
"legendnumcolumns": "3",
"palettecolors": "#f8bd19,#e44a00,#008ee4,#33bdda,#6baa01,#583e78"
},
"data": getComponents()
},
"events": {
"dataplotClick": function(eventObj, dataObj) {
if (getMode() === 'pie') {
var json = stackedChart.getJSONData(),
categoryLabel = dataObj.categoryLabel;
json.chart.subCaption = "BreakUp of " + categoryLabel + " in different product";
json.categories[0].category = getSeriesNames();
json.dataset = getValues(dataObj.categoryLabel);
stackedChart.setJSONData(json);
}
}
}
}).render();
var stackedChart = new FusionCharts({
type: 'stackedBar2D',
renderAt: 'barContainer',
width: '600',
height: '400',
dataFormat: 'json',
dataSource: {
"chart": {
"bgcolor": "FFFFFF",
"outcnvbasefontcolor": "666666",
"caption": "Expenditures Incurred in Publishing a Book",
"subCaption": "Product-wise BreakUp",
"xaxisname": "Expenditures Cost",
"yaxisname": "Cost",
"numberprefix": "$",
"showvalues": "0",
"numvdivlines": "10",
"showalternatevgridcolor": "1",
"alternatevgridcolor": "e1f5ff",
"divlinecolor": "e1f5ff",
"vdivlinecolor": "e1f5ff",
"basefontcolor": "666666",
"tooltipbgcolor": "F3F3F3",
"tooltipbordercolor": "666666",
"canvasbordercolor": "666666",
"canvasborderthickness": "1",
"showplotborder": "1",
"plotfillalpha": "80",
"showborder": "0",
"legendbgcolor": "#CCCCCC",
"legendbgalpha": "20",
"legendborderalpha": "0",
"legendshadow": "0",
"legendnumcolumns": "3"
},
"categories": [{
"category": getComponents(true, false)
}],
"dataset": getData()
},
"events": {
"dataplotClick": function(eventObj, dataObj) {
if (getMode() === 'stackedBar') {
var JSON = pieChart.getJSONData(),
categoryLabel = dataObj.categoryLabel;
JSON.chart.subCaption = "BreakUp of " + categoryLabel + " in different product";
JSON.data = getProducts(categoryLabel);
pieChart.setJSONData(JSON);
pieChart.slicePlotItem(dataObj.datasetIndex);
}
}
}
}).render();
function resetFN() {
var json = pieChart.getJSONData();
json.chart.subCaption = "Component-wise BreakUp";
json.data = getComponents();
pieChart.setJSONData(json);
json = stackedChart.getJSONData();
json.chart.subCaption = "Product-wise BreakUp";
json.categories[0].category = getComponents(true, false);
json.dataset = getData();
stackedChart.setJSONData(json);
}
document.getElementById('reset').addEventListener('click', resetFN);
document.getElementById('interaction').addEventListener('change', resetFN);
});
h4 {
font-size: 20px;
margin-bottom: 10px
}
.intro {
margin: 0 auto;
background-color: #fff280;
padding: 15px
}
em {
font-style: italic
}
#interactionWrapper {
margin: 5px 10px;
}
button {
border: 1px solid #0b77bc;
background-color: #0d83ce;
color: #ffffff;
margin: 10px 0 0 15px;
padding: 5px 10px;
font-size: 14px;
cursor: pointer
}
.centerAlign {
text-align: center;
}
<script src="http://static.fusioncharts.com/code/latest/fusioncharts.js"></script>
<script src="http://static.fusioncharts.com/code/latest/themes/fusioncharts.theme.fint.js"></script>
<div class="intro">
<h4>Expenditures incurred while publishing books</h4>
<p><em>A company has 6 books to publish for this quater. The stacked chart shows component prices stacked as per different books. While the pie chart, shows the cumilative component price.</em></p>
<p>
<em>There are two interaction modes - namely "Interact in stacked chart" and "Interact in pie chart".On clicking in any plot on stacked chart, it shows the book-wise distribution of that component in the pie chart. Whereas on clicking the pie chart, for a component being clicked, it shows the book-wise distribution in the bar chart</em>
</p>
</div>
<div id="interactionWrapper">
<span>Interaction Mode:</span>
<span>
<select id="interaction">
<option value="stackedBar">Interact in stacked bar</option>
<option value="pie">Interact in the pie chart</option>
</select>
</span>
</div>
<div class="centerAlign">
<span id="barContainer">FusionCharts XT will load here!</span>
<span id="pieContainer">FusionCharts XT will load here!</span>
</div>
<button id="reset">Reset</button>

How to make two plots side-by-side using JavaScript Plottable

With the following script I tried to make the side by side pie chart
var pies;
var indata = [
{ 'sample' : "Foo",
"pies_pct":[
{
"score": 6.7530200000000002,
"celltype": "Bcells"
},
{
"score": 11.432763461538459,
"celltype": "DendriticCells"
}]
},
{ 'sample' : "Bar",
"pies_pct":[
{
"score": 26.8530200000000002,
"celltype": "Bcells"
},
{
"score": 31.432763461538459,
"celltype": "BCells"
}]
},
];
processData(indata);
function processData(data) {
pies = data.map(function (data) {
return {
title : data.sample,
dataset : data.pies_pct
};
});
buildPlots();
}
function buildPlots () {
var $pieContainer = $('#sample-pies');
pies.forEach(function (pie, index) {
var elementId = "sample-pie-" + index;
$(document.createElementNS('http://www.w3.org/2000/svg', 'svg'))
.css({width: '200px', height: '200px', display: 'inline-block'})
.attr('id', elementId)
.appendTo($pieContainer);
plotSamplePie(pie.title, pie.dataset, '#' + elementId);
});
}
function plotSamplePie(title,purity_data,targetElement) {
var scale = new Plottable.Scales.Linear();
var tableau20 = ['#1F77B4', '#FF7F0E', '#2CA02C', '#D62728',
'#9467BD', '#8C564B', '#CFECF9', '#7F7F7F', '#BCBD22', '#17BECF'];
var colorScale = new Plottable.Scales.Color();
var legend = new Plottable.Components.Legend(colorScale);
colorScale.range(tableau20);
var titleLabel = new Plottable.Components.TitleLabel(title);
var plot = new Plottable.Plots.Pie()
.addDataset(new Plottable.Dataset(purity_data))
.attr("fill", function(d) { return d.score; }, colorScale)
.sectorValue(function(d) { return d.score; }, scale)
.labelsEnabled(true);
.renderTo(targetElement);
}
<html>
<head>
<link href="https://cdnjs.cloudflare.com/ajax/libs/plottable.js/1.15.0/plottable.css" rel="stylesheet" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/qtip2/2.2.1/basic/jquery.qtip.css" rel="stylesheet" />
</head>
<body>
My Plot
<!-- Show histograms -->
<div id="sample-pies"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/plottable.js/1.15.0/plottable.js"></script>
</body>
</html>
So this functios does
processData() reads the data,
buildPlots() read piechart data chunk by chunk
plotSamplePie() draw individual pie.
But why it doesn't work?
I expect it to show plot like this:
There is a simple error if you can see in you console.
var plot = new Plottable.Plots.Pie()
.addDataset(new Plottable.Dataset(purity_data))
.attr("fill", function(d) { return d.score; }, colorScale)
.sectorValue(function(d) { return d.score; }, scale)
.labelsEnabled(true);
.renderTo(targetElement);
Just remove ; after .labelsEnabled(true); and it should work.
var indata = [
{ 'sample' : "Foo",
"pies_pct":[
{
"score": 6.7530200000000002,
"celltype": "Bcells"
},
{
"score": 11.432763461538459,
"celltype": "DendriticCells"
}]
},
{ 'sample' : "Bar",
"pies_pct":[
{
"score": 26.8530200000000002,
"celltype": "Bcells"
},
{
"score": 31.432763461538459,
"celltype": "BCells"
}]
},
];
processData(indata);
function processData(data) {
pies = data.map(function (data) {
return {
title : data.sample,
dataset : data.pies_pct
};
});
buildPlots();
}
function buildPlots () {
var $pieContainer = $('#sample-pies');
pies.forEach(function (pie, index) {
var elementId = "sample-pie-" + index;
$(document.createElementNS('http://www.w3.org/2000/svg', 'svg'))
.css({width: '200px', height: '200px', display: 'inline-block'})
.attr('id', elementId)
.appendTo($pieContainer);
plotSamplePie(pie.title, pie.dataset, '#' + elementId);
});
}
function plotSamplePie(title,purity_data,targetElement) {
var scale = new Plottable.Scales.Linear();
var tableau20 = ['#1F77B4', '#FF7F0E', '#2CA02C', '#D62728',
'#9467BD', '#8C564B', '#CFECF9', '#7F7F7F', '#BCBD22', '#17BECF'];
var colorScale = new Plottable.Scales.Color();
var legend = new Plottable.Components.Legend(colorScale);
colorScale.range(tableau20);
var titleLabel = new Plottable.Components.TitleLabel(title);
var plot = new Plottable.Plots.Pie()
.addDataset(new Plottable.Dataset(purity_data))
.attr("fill", function(d) { return d.score; }, colorScale)
.sectorValue(function(d) { return d.score; }, scale)
.labelsEnabled(true)
.renderTo(targetElement);
}
<html>
<head>
<link href="https://cdnjs.cloudflare.com/ajax/libs/plottable.js/1.15.0/plottable.css" rel="stylesheet" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/qtip2/2.2.1/basic/jquery.qtip.css" rel="stylesheet" />
</head>
<body>
My Plot
<!-- Show histograms -->
<div id="sample-pies"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/plottable.js/1.15.0/plottable.js"></script>
</body>
</html>

How to label Highcharts tooltip from json data?

i am passing data as JSON to highcharts this JSON comes from a java method so i cant change this...so please dont suggest to change JSON format...
my code for highchart is below...
var json = [{
"value": 12,
"name": "platform1",
"key": "event4"
}, {
"value": 10,
"name": "platform1",
"key": "event1"
}, {
"value": 14,
"name": "platform1",
"key": "event3"
}, {
"value": 9,
"name": "platform1",
"key": "event2"
}, {
"value": 13,
"name": "platform3",
"key": "event4"
}, {
"value": 13,
"name": "platform3",
"key": "event1"
}];
var processed_json = new Array();
$.map(json, function (obj, i) {
processed_json.push([obj.key, parseInt(obj.value), obj.name]);
});
$('#container').highcharts({
chart: {
type: 'column'
},
xAxis: {
type: "category"
},
tooltip: {
formatter: function () {
return 'Branch: <b>' + this.series.name +
'</b><br/>Platform: ' + this.point.y;
}
},
series: [{
name: 'Data',
data: processed_json
}]
});
i am trying to put platform name on the tooltip as i hover over...but i can not find any way to do that...plus is there any way i can create legends as number of platforms...right now i only have one legend named "Data".
jfiddle can be found here : http://jsfiddle.net/QTJb7/
You need to use object instead of array, in point definition and add paramter in your $.map.
$.map(json, function (obj, i) {
processed_json.push({name: obj.key,y: parseInt(obj.value),customName : obj.name });
});
tooltip:
tooltip: {
formatter: function () {
return 'Branch: <b>' + this.series.name +
'</b><br/>Platform: ' + this.point.name + ' <br> name ' + this.point.customName;
}
},
http://jsfiddle.net/QTJb7/1/

Categories