I need a little bit of help to change data from a chart, when an option is selected from a drop-down menu. I've searched for similar questions but nothing was really helpful.
So far I have this code and I don't understand what am I missing that it's not working?
the html:
<div id="scroll-container">
<select id="menu">
<option value="Oil">Oil</option>
<option value="Gas">Gas</option>
</select>
<div id="container_Oil" data-role="ejmchart" style="height: 320px"></div>
</div>
and the javascript part:
<script>
$(function () {
var value = document.getElementById("menu").value;
var chart = document.getElementById("container_Oil");
$('#menu').change(function(evt){
var dataSelection = eval($("#menu").val());
var chart = $('#container_Oil').ejChart ({
dataSource: dataSelection
})
})
})
</script>
The date I am using for the chart, I have in another file, app.js and it contains the following:
var Oil = ...
var Gas = ...
$("#container_Oil").ejChart(
{
primaryXAxis:
{
//labelFormat: 'dd, MM',
//labelFormat: "{value}",
range: { min: 1, max: 30, interval: 2 },
font: { size: '10px' },
labelRotation: 20,
visible :false
},
primaryYAxis:
{
labelFormat: "{value}",
//range: { min: 39, max: 40, interval: 0.1 },
rangePadding: 'normal',
font: { size: '10px' },
visible : false
},
commonSeriesOptions: {
tooltip: { visible: true },
type: 'line', enableAnimation: false,
marker:
{
shape: 'circle',
size:
{
height: 5, width: 5
},
visible: true
},
border: { width: 2 }
},
series: [{
//Binding series with a JSON data source
dataSource: Oil,
//Mapping name of the field containing X value to series
//xName: 'Day',
//Mapping name of the field containing Y value to series
yName: 'Actual',
name: 'Actual'
},
{ dataSource: Oil,
//xName: 'Day',
yName: 'Plan',
name: 'Plan'
}
],
canResize: true,
load: 'onchartload',
title: { text: 'Product - Oil', font: { size: '12px' } },
legend: { visible: true, position: "top" }
});
I want when I select for example Gas in the selector to change the dataSource for the chart from Oil to Gas.
I tried debugging and it said that "Oil" and "Gas" were undefined. Then I tried to put the data for "Oil" and "Gas" in the same file with the script. No more error, but still not working. I think I am missing something important in my code, but I can't seem to understand what. A little help would be more than welcomed!
Perhaps it only creates the charts on page load? Since it's only two charts, you could create them both on page load, and then hide and show the divs depending on the dropdown value for a quick fix.
Did you tried?
$('#menu').on( "change", function(evt){
Instade of:
$('#menu').change(function(evt){
Related
I have line-time-series chart (in ECharts). I need to keep a constant number of points, which moves from left to right with new data. However, when I add data using setOption, there is no shift, but each point just changes its position in the y direction.
Can someone please advise me what I'm doing wrong?
This example does exactly what I need. I think I have it the same, but it still behaves differently.
Thank you
<script src="https://unpkg.com/vue#2.6.12/dist/vue.js"></script>
<script src="https://unpkg.com/echarts#4.9.0/dist/echarts.js"></script>
<div id="app" style="width: 700px; height: 400px;">
<div ref="echart" style="width: 100%; height: 100%;" ></div>
<button type="button" #click="onClick"> Push data < /button></div>
new Vue({
el: '#app',
mounted() {
this.chart_data=[
['2020-09-01 15:14:13.0', 1],
['2020-09-01 15:14:14.0', 1.5],
['2020-09-01 15:14:15.0', 0.7],
['2020-09-01 15:14:16.0', 0.8],
['2020-09-01 15:14:17.0', 1.7]
]
this.chart=echarts.init(this.$refs.echart)
var option={
color: '#3283bb',
xAxis: {
type: 'time',
splitLine: {
show: false
}
},
yAxis: {
type: 'value',
splitLine: {
show: false
}
},
series: [{
showSymbol: false,
type: 'line',
areaStyle: {
opacity: 0.2
},
lineStyle: {
width: 1.5
},
data: this.chart_data,
hoverAnimation: false
}]
}
this.chart.setOption(option)
},
methods: {
onClick: function() {
this.chart_data.shift()
this.chart_data.shift()
this.chart_data.push(['2020-09-01 15:14:18.0', 2.5])
this.chart_data.push(['2020-09-01 15:14:19.0', 2.0])
this.chart.setOption({
series: [{
data: this.chart_data
}]
})
}
},
})
JSFiddle example
I was able to find out the answer directly from the ECharts developers. Therefore, if someone has a similar problem, the solution is as follows:
ECharts performs animates "shift" if it recognizes part of the old data in the newly added data. Currently, this can be done by adding a unique name to each value. Each value is then an object with a name and value property.
{name: '2020-09-01 15:14:18.0', value: ['2020-09-01 15:14:18.0', 2.5]}
I am attaching a modified jsfiddle https://jsfiddle.net/Clyde256/b2d4juzt/44/ from the previous post, where the shift already works.
I would like to add, that if you are using dataset functionality, you need to name your dimension and then in the series property use the encode block and set itemId to any dimension name that has unique values like so:
dataset: {
dimensions: ['value', 'ts'],
source: [],
},
series: [
{
name: 'some line',
type: 'line',
encode: {
x: 'ts',
y: 'value',
itemId: 'ts',
},
},
],
Then the chart renders with correct 'shift left' animation when new values are added and old ones are removed.
I've always use flot.js for common charting requirements, but I'd like to explore new ways to visualize data that might be beyond this charting library. I'd appreciate any advice or recommendations as to how others might programmatically render the custom display chart below. Maybe CSS?
I know you probably weren't looking for an answer spelling out how to implement this in flot, but it was a fun exercise.
Getting creative with hiding and stacking bars with the stack plugin allows you to represent your bounds. For each set of bounds, you'll need to create a hidden bar with your lower bound value and then create a visible bar with your upper bound value (and stack the two). Specifying which bars should stack on each other is easy by setting the stack option to the same key.
Once the bars are setup, the next step is to set the options of the chart. A grid marking handles displaying the current value. Hiding both axes effectively hides the grid.
The rest comes down to creating methods to append div elements to placeholder to show the bar values, labels, and marking value.
This is a basic implementation of your example image that really focuses on the flot component of the chart. With a bit more time, the extra appended div elements could be styled in such a way to more closely match your example.
This JSFiddle contains the code below for easier review.
$(function() {
var data = [{
data: [ [0, 21.51] ],
lines: { show: false },
bars: { show: false },
stack: 0,
label: 'Hidden'
},{
data: [ [1, 32.50] ],
lines: { show: false },
bars: { show: false },
stack: 1,
label: 'Hidden'
},{
data: [ [2, 47.14] ],
lines: { show: false },
bars: { show: false },
stack: 2,
label: 'Hidden'
},{
data: [ [0, 37.77] ],
stack: 0,
label: 'Last Year'
},{
data: [ [1, 24.65] ],
stack: 1,
label: 'Last Month'
}, {
data: [ [2, 7.67] ],
stack: 2,
label: 'Last Week'
}];
var options = {
series: {
bars: { show: true },
points: { show: false }
},
xaxis: { show: false },
yaxis: { show: false },
grid: {
show: true,
borderWidth: 0,
backgroundColor: null,
markings: [{
xaxis: { from: 0, to: 3 },
yaxis: { from: 48.01, to: 48.01 },
color: "#000000"
}]
},
legend: { show: false }
};
var plot = $.plot($('#graph'), data, options);
var plotData = plot.getData();
var markings = plot.getOptions().grid.markings;
displayBarValues(plotData);
displayBarLabels(plotData);
displayMarkingValues(markings);
// display values next to bars
function displayBarValues(plotData) {
$.each(plotData, function(i, data) {
var stackedValue = data.data[0][1];
if (data.bars.show) {
stackedValue = findStackedValue(plotData, data.stack);
}
var offset = plot.pointOffset({x: data.data[0][0], y: stackedValue});
$('<div class="data-point-value">-- $' + stackedValue + '</div>').css( {
left: offset.left + 30,
top: offset.top - 8,
}).appendTo(plot.getPlaceholder());
});
}
function findStackedValue(dataSeries, stackNumber) {
var stackedValue = 0;
for (var i =0; i < dataSeries.length; i++) {
if (dataSeries[i].stack === stackNumber) {
stackedValue = stackedValue + dataSeries[i].data[0][1];
}
}
return stackedValue;
}
// display a marking value
function displayMarkingValues(markings) {
$.each(markings, function(i, marking) {
var offset = plot.pointOffset({x: marking.xaxis.to, y: marking.yaxis.to });
$('<div class="data-point-value">------ $' + marking.yaxis.to + '</div>').css( {
left: offset.left,
top: offset.top - 8,
}).appendTo(plot.getPlaceholder());
});
}
function displayBarLabels(plotData) {
$.each(plotData, function(i, data) {
if (data.bars.show) {
var stackedValue = findStackedValue(plotData, data.stack);
var offset = plot.pointOffset({x: data.data[0][0], y: stackedValue});
$('<div class="data-point-label">' + data.label + '</div>').css({
left: offset.left - 35,
top: offset.top + 50,
}).appendTo(plot.getPlaceholder());
}
});
}
});
#graph {
margin: 0 auto;
text-align: center;
width: 100px;
height: 600px;
}
.data-point-value {
position: absolute;
white-space: nowrap;
font-size: 11px;
}
.data-point-label {
position: absolute;
white-space: nowrap;
width: 100px;
font-size: 11px;
text-align: right;
-webkit-transform: rotate(-90deg);
-moz-transform: rotate(-90deg);
-ms-transform: rotate(-90deg);
-o-transform: rotate(-90deg);
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/flot/0.8.3/jquery.flot.js"></script>
<script src="https://rawgit.com/emmerich/flot-orderBars/master/js/jquery.flot.orderBars.js"></script>
<script src="https://rawgit.com/flot/flot/master/source/jquery.flot.stack.js"></script>
<div id="graph"></div>
I have used Fusion Charts. Its pretty easy to customize and it works well in all browsers. Also have a look at Chart JS. Its pretty cool and its open source
I'v been using Chart.js for a while. While it is sweet at first glance, and you really can do super awesome stuff with it out of the box, it can be really limiting later on when you come across the need to do some simple/custom details that are not in documentation. For example: label outside the chart; turning off background for bar chart, doughnut bar with 1 value (for example - i have doughnut chart, with value 20%, i want the difference to be colored - you cant do that).
Of course all these stuff can be addressed and made with customizing .js file, and extending it but if you don't have time for that and you want out of the box solution, you can be stuck on simple detail so i suggest reading full docs to see if it is up to your expetations.
I would recommend D3.js with the caveat the the learning curve is steep; let me try to explain:
In something like chart.js, chartist,etc you provide the data, chart type and some configuration and you have your chart. In D3, it is a bit more complicated in the sense that D3 provides the framework for displaying and interacting with data via the Dom elements you design and specify.( Mostly svg's although you can also use divs,spans etc)
While it feels daunting at first and the documentation is basically an API Reference, there are hundreds of examples you can use as base or inspiration.
I'v been using (ChartJS, Morris, Inline Charts) for dashboard. It may help you much to customize the chart
I would recommend Chartist.js. It is fully responsive with great flexibility and DPI dependent.
you're able to style your charts with CSS in #media queries and lot of animation options. they have given examples for line chart, bar chart, pie chart with code. So it will definitely help you.
I like amCharts.
Can do all kinds of stuff and is free to use.
Google gives you an interesting charting library.
May want to try that but it requires you to be connected to Google for it to work (can't run it offline).
Here's a shot at it with HighCharts. I adapted the 'Stacked and grouped column' example at http://www.highcharts.com/demo/column-stacked-and-grouped.
Obviously there's work to be done in getting the labels and axes right, but I think this is a good start.
jsFiddle at http://jsfiddle.net/saevj2n4/1/
HTML:
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
<div id="container" style="min-width: 310px; height: 400px; margin: 0 auto"></div>
JavaScript
$(function () {
Highcharts.chart('container', {
chart: {
type: 'column',
width: 200,
height: 1000
},
title: {
text: 'Total fruit consumtion, grouped by gender'
},
xAxis: {
categories: ['Profit']
},
yAxis: {
allowDecimals: false,
min: 0,
title: {
text: 'Number of fruits'
}
},
tooltip: {
formatter: function () {
return '<b>' + this.x + '</b><br/>' +
this.series.name + ': ' + this.y + '<br/>' +
'Total: ' + this.point.stackTotal;
}
},
plotOptions: {
column: {
stacking: 'normal',
//groupPadding: .45,
pointPadding: 0,
//pointWidth: 40,
}
},
series: [{
name: 'Min',
data: [59.28 - 21.58 ],
stack: 'Last Year',
color: "#919191"
}, {
name: 'Max',
data: [21.58 ],
stack: 'Last Year',
color: "transparent"
}, {
name: 'Min',
data: [ 57.15 - 32.5 ],
stack: 'Last Month',
color: "#6095c9"
}, {
name: 'Max',
data: [32.50],
stack: 'Last Month',
color: "transparent"
}, {
name: 'Min',
data: [54.81 - 47.14 ],
stack: 'Last Week',
color: "#745f8e"
}, {
name: 'Max',
data: [47.14],
stack: 'Last Week',
color: "transparent"
}]
});
});
I am trying to create a donut chart with text in the center. I need the donut chart to look like below:
The total value is a variable that I am passing to the function that creates the chart. As of now this is what I have:
Code for the above chart is below:
new Chartist.Pie('.ct-chart', {
series: [{
value: 10,
className: 'pieChart1',
}, {
value: 6,
className: 'pieChart2',
}, {
value: 5,
className: 'pieChart3',
}]
}, {
donut: true,
donutWidth: 20,
width: '138px',
height: '138px',
showLabel: false
});
Can someone please help me create the text inside the donut?
It exist a plugin to do this !
http://gionkunz.github.io/chartist-js/plugins.html#filldonut-plugin
Implement ths dependences and add this code to your object definition params :
plugins: [
Chartist.plugins.fillDonut({
items: [{
content: '<h3>160<span class="small">mph</span></h3>'
}]
})
],
I'm attempting to combine a couple of different chart demos from Highcharts.
My examples are: Data classes and popup and Small US with data labels
I want the map from the first with the popup feature of the second. I need to connect the map to my own google spreadsheet but for now I'm just trying to get the data from the first example to work.
This is what I have so far but can't seem to get any data in the map. I thought I had a joinBy problem, and I may still, but when I set joinBy to null I thought "the map items are joined by their position in the array", yet nothing happened.
https://jsfiddle.net/9eq6mydv/
$(function () {
// Load the data from a Google Spreadsheet
// https://docs.google.com/a/highsoft.com/spreadsheet/pub?hl=en_GB&hl=en_GB&key=0AoIaUO7wH1HwdFJHaFI4eUJDYlVna3k5TlpuXzZubHc&output=html
Highcharts.data({
googleSpreadsheetKey: '0AoIaUO7wH1HwdDFXSlpjN2J4aGg5MkVHWVhsYmtyVWc',
googleSpreadsheetWorksheet: 1,
// custom handler for columns
parsed: function (columns) {
// Make the columns easier to read
var keys = columns[0],
names = columns[1],
percent = columns[10],
// Initiate the chart
options = {
chart : {
renderTo: 'container',
type: 'map',
borderWidth : 1
},
title : {
text : 'US presidential election 2008 result'
},
subtitle: {
text: 'Source: <a href="http://en.wikipedia.org/wiki/United_States_presidential_election,' +
'_2008#Election_results">Wikipedia</a>'
},
mapNavigation: {
enabled: true,
enableButtons: false
},
legend: {
align: 'right',
verticalAlign: 'top',
x: -100,
y: 70,
floating: true,
layout: 'vertical',
valueDecimals: 0,
backgroundColor: (Highcharts.theme && Highcharts.theme.legendBackgroundColor) || 'rgba(255, 255, 255, 0.85)'
},
colorAxis: {
dataClasses: [{
from: -100,
to: 0,
color: '#C40401',
name: 'McCain'
}, {
from: 0,
to: 100,
color: '#0200D0',
name: 'Obama'
}]
},
series : [{
data : data,
dataLabels: {
enabled: true,
color: '#FFFFFF',
format: '{point.code}',
style: {
textTransform: 'uppercase'
}
},
mapData: Highcharts.geojson(Highcharts.maps['countries/us/custom/us-small']),
joinBy: keys,
name: 'Democrats margin',
point: {
events: {
click: pointClick
}
},
tooltip: {
ySuffix: ' %'
},
cursor: 'pointer'
}, {
type: 'mapline',
data: Highcharts.geojson(Highcharts.maps['countries/us/custom/us-small'], 'mapline'),
color: 'silver'
}]
};
/**
* Event handler for clicking points. Use jQuery UI to pop up
* a pie chart showing the details for each state.
*/
function pointClick() {
var row = this.options.row,
$div = $('<div></div>')
.dialog({
title: this.name,
width: 400,
height: 300
});
window.chart = new Highcharts.Chart({
chart: {
renderTo: $div[0],
type: 'pie',
width: 370,
height: 240
},
title: {
text: null
},
series: [{
name: 'Votes',
data: [{
name: 'Obama',
color: '#0200D0',
y: parseInt(columns[3][row], 10)
}, {
name: 'McCain',
color: '#C40401',
y: parseInt(columns[4][row], 10)
}],
dataLabels: {
format: '<b>{point.name}</b> {point.percentage:.1f}%'
}
}]
});
}
// Read the columns into the data array
var data = [];
$.each(keys, function (i, key) {
data.push({
key: key,//.toUpperCase(),
value: parseFloat(percent[i]),
name: names,
row: i
});
});
// Initiate the chart
window.chart = new Highcharts.Map(options);
},
error: function () {
$('#container').html('<div class="loading">' +
'<i class="icon-frown icon-large"></i> ' +
'Error loading data from Google Spreadsheets' +
'</div>');
}
});
});
UPDATE:
I wanted to share with everyone my final solution. Although Ondkloss did a magnificent job answering my question the popup feature still didn't work and this is because I forgot to include the jQuery for the .dialog call. Once I included that I had an empty popup with a highchart error 17, this is because the highmaps.js code doesn't include the pie chart class. So I had to add the highcharts.js code and include map.js module afterward. You can see my final jsfiddle here.
Thanks again to Ondkloss for the excellent answer!
The problem here mostly comes down to the use of joinBy. Also to correct it there are some required changes to your data and mapData.
Currently your joinBy is an array of strings, like ["al", "ak", ...]. This is quite simply not an accepted format of the joinBy option. You can read up on the details in the API documentation, but the simplest approach is to have a attribute in common in data and mapData and then supply a string in joinBy which then joins those two arrays by that attribute. For example:
series : [{
data : data,
mapData: mapData,
joinBy: "hc-key",
]
Here the "hc-key" attribute must exist in both data and mapData.
Here's how I'd create the data variable in your code:
var data = [];
$.each(keys, function (i, key) {
if(i != 0)
data.push({
"hc-key": "us-"+key,
code: key.toUpperCase(),
value: parseFloat(percent[i]),
name: names[i],
row: i
});
});
This skips the first key, which is just "Key" (the title of the column). Here we make the "hc-key" fit the format of the "hc-key" in our map data. An example would be "us-al". The rest is just metadata that will be joined in. Note that you were referencing your data in the options prior to filling it with data, so this has to be moved prior to this.
This is how I'd create the mapData variable in your code:
var mapData = Highcharts.geojson(Highcharts.maps['countries/us/custom/us-small']);
// Process mapdata
$.each(mapData, function () {
var path = this.path,
copy = { path: path };
// This point has a square legend to the right
if (path[1] === 9727) {
// Identify the box
Highcharts.seriesTypes.map.prototype.getBox.call(0, [copy]);
// Place the center of the data label in the center of the point legend box
this.middleX = ((path[1] + path[4]) / 2 - copy._minX) / (copy._maxX - copy._minX);
this.middleY = ((path[2] + path[7]) / 2 - copy._minY) / (copy._maxY - copy._minY);
}
// Tag it for joining
this.ucName = this.name.toUpperCase();
});
The first part is your "standard map data". The rest is to correctly center the labels for the popout states, and gotten directly from the example.
And voila, see this JSFiddle demonstration to witness your map in action.
I suggest doing some console.log-ing to see how data and mapData have the hc-key in common and that leads to the joining of the data in the series.
I write because I go back to being stuck in a problem with Highcharts. I have a monthly chart that works fine except for one thing. The zoom level. The X axis is always shown me a value of 0 (today), so that the zoom level is incorrect. I am attaching a picture to try to explain it better. I need this column set in the graph.
I appreciate your help! Thank you!
The json returned by PHP is (correct results):
{"data":[[1401580800000,2],[1400025600000,0],[1400025600000,0],[1400025600000,0],[1400025600000,0],[1400025600000,0],[1400025600000,0],[1400025600000,0],[1400025600000,0],[1400025600000,0],[1400025600000,0],[1400025600000,0],[1400025600000,0],[1400025600000,0],[1400025600000,0],[1400025600000,0],[1400025600000,0],[1400025600000,0],[1400025600000,0],[1400025600000,0],[1400025600000,0],[1400025600000,0],[1400025600000,0],[1400025600000,0],[1400025600000,0],[1400025600000,0],[1400025600000,0],[1400025600000,0],[1400025600000,0],[1400025600000,0]]}
And Javascript file:
chart = new Highcharts.Chart({
chart: {
renderTo: 'divStatsGrupo',
plotBackgroundColor: null,
plotBorderWidth: null,
plotShadow: false
},
title: {
text: tituloMes
},
tooltip: {
formatter: function() {
return Highcharts.dateFormat('%d/%m/%Y',new Date(this.x)) + '<br/>' +'Alarmas: ' + this.y
}
},
xAxis: {
type: 'datetime',
dateTimeLabelFormats : {
day: '%e. %b',
labels: {
style: {
width: '200px','min-width': '100px'
},
useHTML : true,
}
}
},
yAxis: {
title: {
text: 'Total alarmas'
},
allowDecimals: false,
min: 0
},
series : [{
showInLegend: false,
name : 'Grafica Mensual',
type : 'column',
data: data.data,
dataLabels: {
enabled: true,
rotation: 0,
color: '#000000',
align: 'center',
y: 0,
style: {
fontSize: '14px',
fontFamily: 'Verdana, sans-serif',
}}
}]
});
}); ///cierra get
EDIT: I need a graphic for month (user select), but, the white area and Xaxis only appers info for the month selected. The PHP file return a correct JSON chain, but highcharts not fit the columns fine. Sorry for my english!
The problem is with your JSON, where you have duplicated values for the same timestamp. Just remove them.
Then! You have unsorted data, it should be sorted ascending by timestamp.
After fixed, it works fine, see: http://jsfiddle.net/4nCx3/
var data = {
"data": [
[1400025600000, 0],
[1401580800000, 2]
]
};