change data on chart by selecting the year in dropdowns - javascript
i am displaying a chart in an angular app. I have two dropdowns to select starting year and ending year and i need my chart do display values based on the years picked. The X axis is composed by 18 cities, and the Y axis is the range "IAP" values. My data set is composed by "imob" and "rend" values, i.e. to calculate my "IAP" values for each city i need to do this operation:
IAP of city x from year 1 to year 2 = (imob.endingyear/imob.startingyear)/(rend.endingyear/rend.startingyear)
For example, when i select the starting year 2013 and the ending year 2018, the chart has to display the IAP values of each city in that interval of time. I hope my explanation is not too much confusing.
So far i have my dropdown in iapchart.controller.html file and it looks like this:
<div ng-controller="YearpickerController">
<form name="myForm">
<label for="singleSelect"> Ano Início: </label><br>
<select name="singleSelect" ng-model="data.singleSelect">
<option value="option-1i">2011</option>
<option value="option-2i">2012</option>
<option value="option-3i">2013</option>
<option value="option-4i">2014</option>
<option value="option-5i">2015</option>
<option value="option-6i">2016</option>
<option value="option-7i">2017</option>
<option value="option-8i">2018</option>
<option value="option-9i">2019</option>
<option value="option-10i">2020</option>
</select><br>
</form>
</div>
<div ng-controller="YearpickerController">
<form name="myForm">
<label for="singleSelect"> Ano Fim: </label><br>
<select name="singleSelect" ng-model="data.singleSelect">
<option value="option-1f">2011</option>
<option value="option-2f">2012</option>
<option value="option-3f">2013</option>
<option value="option-4f">2014</option>
<option value="option-5f">2015</option>
<option value="option-6f">2016</option>
<option value="option-7f">2017</option>
<option value="option-8f">2018</option>
<option value="option-9f">2019</option>
<option value="option-10f">2020</option>
</select><br>
</form>
</div>
To build my chart i have used Highcharts and so far its looking like this
But the dropdowns are not working, i need some sort of event listener right? I am new to angular js and i dont know how to go from here.
My code in iapchart.component.ts is looking like this so far:
#Component({
selector: 'app-widget-iapchart',
templateUrl: './iapchart.component.html',
styleUrls: ['./iapchart.component.scss']
})
export class IAPchartComponent implements OnInit, OnDestroy {
title = 'app';
imobsListSubs: Subscription;
imobsList: Imob[];
chartOptions;
Highcharts = Highcharts;
constructor(private imobsApi: ImobsApiService) { }
ngOnInit(): void{
this.imobsListSubs = this.imobsApi
.getImobs()
.subscribe(res => {
this.imobsList = res;
},
console.error
);
this.chartOptions = {
chart: {
type: 'column'
},
title: {
text: 'Índice Valorização'
},
xAxis: {
type: 'category',
labels: {
rotation: -45,
style: {
fontSize: '13px',
fontFamily: 'Verdana, sans-serif'
}
}
},
yAxis: {
min: 0,
title: {
text: 'Valorização'
}
},
legend: {
enabled: false
},
tooltip: {
pointFormat: 'Valor IAP: <b>{point.y:.1f} </b>'
},
credits: {
enabled: false
},
exporting: {
enabled: true,
},
series: [{
name: 'Valor IAP',
data: [
['Aveiro', 1.2],
['Beja', 0.8],
['Braga', 1.2],
['Bragança', 1.7],
['Castelo Branco', 1.1],
['Coimbra', 0.7],
['Évora', 1.4],
['Faro', 1.2],
['Guarda', 1.0],
['Leiria', 0.7],
['Lisboa', 1.5],
['Portalegre', 1.2],
['Porto', 1.4],
['Santarém', 1.2],
['Setúbal', 0.6],
['Viana do Castelo', 0.9],
['Vila Real', 1.3],
['Viseu', 0.8]
],
dataLabels: {
enabled: true,
rotation: 0,
color: '#000000',
align: 'right',
format: '{point.y:.1f}', // one decimal
y: -20, // 10 pixels down from the top
style: {
fontSize: '13px',
fontFamily: 'Times New Roman, sans-serif'
}
}
}]
};
HC_exporting(Highcharts);
setTimeout(() =>{
window.dispatchEvent(
new Event('resize')
);
}, 300);
}
ngOnDestroy() {
this.imobsListSubs.unsubscribe();
}
The data I provided there is only an example of IAP values, i also need to know how to write my dataset there without making the code very big...
The functionality that you are looking for is already built into the Highcharts stock, the only difference is that instead of the dropdown list you can use the range selector input to manipulate the axis range. Range selectors are using the axis.setExtremes() method under the hood, so to make it work you would need to call the axis.setExtremes() method with ranges given in the ms.
API references:
https://api.highcharts.com/class-reference/Highcharts.Axis#setExtremes
Live demo:
https://stackblitz.com/edit/highcharts-angular-basic-line-brzswa?file=src/app/app.component.ts
Related
Highcharts update x-axis categories dynamically
i'm looking for help with updating the x-axis categories on a Highcharts chart with periodically received data. The chart is defined in a file called forecastgraph.html. It is loaded to index.php, the webpage where I want it displayed, by means of <?php require("widget/forecastgraph.html"); ?>. The chart renders as expected. Live data which is handled via a js script (called mqtt.js) that receives incoming mqtt data in json format and using jquery updates various parts of index.php in this way: $("#elementid").html(a.b.c);. I load mqtt.js in the head of index.php using <script src="./js/mqtt.js"></script> This again works flawlessly. What I am struggling with is how to pass incoming data from mqtt.js to the chart to update it as new data comes in. Specifically, I am trying to update the xAxis categories and the corresponding value pairs. Periodically, mqtt.js receives a new weather forecast and so the xAxis categories need to be updated with the new time period that the forecast applies to and the data needs to be updated to reflect the new high and low temperatures for the respective forecast periods. The code for the chart is posted below. Any help would be appreciated. Baobab <script type="text/javascript"> $(function () { $('#forecastgraph').highcharts({ chart: { type: 'columnrange', backgroundColor: 'rgba(0,0,0,0)', borderWidth: 0, margin: [12, 6, 36, 20] }, title: { text: null, }, exporting: { enabled: false }, credits: { enabled: false }, xAxis: { categories: [1,2,3,4], labels: { y: 30, style: { color: 'white', fontSize: '10px', fontWeight: 'bold' } } }, yAxis: { title: { enabled: false, x: -14, }, labels: { align: 'left' }, maxPadding: 0.5, plotLines: [{ value: 10, //normmax width: 2, color: '#FF0000' },{ value: 2, //normmin width: 2, color: '#009ACD' }] }, tooltip: { enabled: false }, plotOptions: { columnrange: { dataLabels: { enabled: true, style: { textOutline: 'none' }, crop: false, overflow: 'none', formatter: function () { var color = this.y === this.point.high ? '#33C4FF' : 'red'; return '<span style="font-size: 12px; font-family:helvetica; font-weight:normal; text-shadow: none; color:' + color + '">' + this.y + '°</span>'; } } } }, legend: { enabled: false }, series: [{ name: 'Temperatures', data: [ [20, -3], [5, -2], [6, -2], [8, -15] ], color: '#b9deea', borderColor: '#92cbde', borderRadius: 4 }] }); }); </script> EDIT: Additional Information. The incoming json data looks like this: [{ "period": "Monday", "condition": "Cloudy", "high_temperature": "7", "low_temperature": "-2" "icon_code": "10", "precip_probability": "20" }, { "period": "Tuesday", "condition": "A mix of sun and cloud", "high_temperature": "6", "low_temperature": "-2" "icon_code": "02", "precip_probability": "20" }, { "period": "Wednesday", "condition": "A mix of sun and cloud", "high_temperature": "3", "low_temperature": "-5" "icon_code": "02", "precip_probability": "20" }, { "period": "Thursday", "condition": "A mix of sun and cloud", "high_temperature": "1", "low_temperature": "-10" "icon_code": "02", "precip_probability": "20" }] The function responsible for the incoming json formatted data in the mqtt.js script loaded to index.php handles the incoming data in this way (mqtt.js is started when index.php is loaded): function onMessageArrived(message) { console.log("onMessageArrived: " + message.payloadString); //Env Canada forecast if (message.destinationName == "myHome/ec/json_data_ec") { var data = JSON.parse(message.payloadString); $("#forecast_period_1").html(data[0].period); // update div forecast_period_1 in index.php for debugging purposes and show that data is coming in forecast_period_1 = (data[0].period); // assign to global var forecast_period_1_high = (data[0].high_temperature); // global var forecast_period_1_low = (data[0].low_temperature); // global var Updating various html elements throughout index.php with the incoming data works great and is stable. What I have attempted to do, but with no success, is to update the chart using the data placed in the global variables (declared as global at he beginning of the script) by the mqtt.js script. In the example above, forecast_period_1 needs to be used as the first of the four xAxis categories and forecast_period_1_high and forecast_period_1_low, to update the respective hi and lo values in the chart's data.
Is this an output that you want to achieve? In the below demo, I wrote a function that takes a high and low temperatures value and next is triggered on the button. The new data is attached to the chart via using the series.update feature. Demo: https://jsfiddle.net/BlackLabel/he768cz3/ API: https://api.highcharts.com/class-reference/Highcharts.Series#update
I have found a solution for it. First, you have to store the chart in a variable then after you are able to update chart data. Like below var chart = $('#forecastgraph').highcharts({ ...option }) Update xAxis or series data // Update xAxis data label chart.update({ xAxis: { categories: [1,2,3,4] } }); // Update series data chart.series[0].update({ data: [ [20, -3], [5, -2], [6, -2], [8, -15] ] });
Is there a stable way to set echarts axis limits from html id value
I'm writing an electron.js app where I'm using echart.js to display a heatmap. Two html input tags are used to let the user set the axis limits for the heatmap. <span> <input type="number" id="min_limit" value= 1> <input type="number" id="max_limit" value= 2> </span> In the javascript code I'm simply using the following to get this content: data_min = document.getElementById('min_limit').value; data_max = document.getElementById('max_limit').value; The problem occurs when I try to use these two variables within the echart option: option = { ... visualMap: { min: data_min, max: data_max, ... } } I get the following error: "Uncaught DOMException: Failed to execute 'addColorStop' on 'CanvasGradient': The value provided ('undefined') could not be parsed as a color." The interesting thing is that the program works when I try any of the following (only one of the input values respectively but not both at the same time): option = { ... visualMap: { min: 0, max: data_max, ... // No errors } } option = { ... visualMap: { min: data_min, max: 1, ... // No errors } } option = { ... visualMap: { min: 0, max: 1, ... // No errors } } And calling*: myChart.setOption(option); To display the chart. Any suggestions? I'm new to html and JavaScript so there may be an obvious error that I'm missing. *EDIT: Forgot to mention that I'm using "setOption" to change the appearance.
You can't set echarts option directly. Need to use setOption for add data, see documentation. Update Your implementation does not work because Echarts not understand what need do with inputs. Getting value you in fact calling the getter (special built-in function) of input component. The Echarts does't know how to call getter, it's expecting just value. With regard to the implementation I would have the following way. Define function that read value for inputs. Define function that update Echart's min/max. Attach event listener to body element for listen inputs change event. And then after receive the event call the update Echarts. var myChart = echarts.init(document.getElementById('main')); var hours = ['12a', '1a', '2a', '3a', '4a', '5a', '6a', '7a', '8a', '9a','10a','11a', '12p', '1p', '2p', '3p', '4p', '5p', '6p', '7p', '8p', '9p', '10p', '11p']; var days = ['Saturday', 'Friday', 'Thursday', 'Wednesday', 'Tuesday', 'Monday', 'Sunday']; var data = [[0,0,5],[0,1,1],[0,2,0],[0,3,0],[0,4,0],[0,5,0],[0,6,0],[0,7,0],[0,8,0],[0,9,0],[0,10,0],[0,11,2],[0,12,4],[0,13,1],[0,14,1],[0,15,3],[0,16,4],[0,17,6],[0,18,4],[0,19,4],[0,20,3],[0,21,3],[0,22,2],[0,23,5],[1,0,7],[1,1,0],[1,2,0],[1,3,0],[1,4,0],[1,5,0],[1,6,0],[1,7,0],[1,8,0],[1,9,0],[1,10,5],[1,11,2],[1,12,2],[1,13,6],[1,14,9],[1,15,11],[1,16,6],[1,17,7],[1,18,8],[1,19,12],[1,20,5],[1,21,5],[1,22,7],[1,23,2],[2,0,1],[2,1,1],[2,2,0],[2,3,0],[2,4,0],[2,5,0],[2,6,0],[2,7,0],[2,8,0],[2,9,0],[2,10,3],[2,11,2],[2,12,1],[2,13,9],[2,14,8],[2,15,10],[2,16,6],[2,17,5],[2,18,5],[2,19,5],[2,20,7],[2,21,4],[2,22,2],[2,23,4],[3,0,7],[3,1,3],[3,2,0],[3,3,0],[3,4,0],[3,5,0],[3,6,0],[3,7,0],[3,8,1],[3,9,0],[3,10,5],[3,11,4],[3,12,7],[3,13,14],[3,14,13],[3,15,12],[3,16,9],[3,17,5],[3,18,5],[3,19,10],[3,20,6],[3,21,4],[3,22,4],[3,23,1],[4,0,1],[4,1,3],[4,2,0],[4,3,0],[4,4,0],[4,5,1],[4,6,0],[4,7,0],[4,8,0],[4,9,2],[4,10,4],[4,11,4],[4,12,2],[4,13,4],[4,14,4],[4,15,14],[4,16,12],[4,17,1],[4,18,8],[4,19,5],[4,20,3],[4,21,7],[4,22,3],[4,23,0],[5,0,2],[5,1,1],[5,2,0],[5,3,3],[5,4,0],[5,5,0],[5,6,0],[5,7,0],[5,8,2],[5,9,0],[5,10,4],[5,11,1],[5,12,5],[5,13,10],[5,14,5],[5,15,7],[5,16,11],[5,17,6],[5,18,0],[5,19,5],[5,20,3],[5,21,4],[5,22,2],[5,23,0],[6,0,1],[6,1,0],[6,2,0],[6,3,0],[6,4,0],[6,5,0],[6,6,0],[6,7,0],[6,8,0],[6,9,0],[6,10,1],[6,11,0],[6,12,2],[6,13,1],[6,14,3],[6,15,4],[6,16,0],[6,17,0],[6,18,0],[6,19,0],[6,20,1],[6,21,2],[6,22,2],[6,23,6]]; data = data.map(function (item) { return [item[1], item[0], item[2] || '-']; }); option = { tooltip: { position: 'top' }, animation: false, grid: { height: '50%', top: '10%' }, xAxis: { type: 'category', data: hours, splitArea: { show: true } }, yAxis: { type: 'category', data: days, splitArea: { show: true } }, visualMap: { min: 0, max: 10, calculable: true, orient: 'horizontal', left: 'center', bottom: '15%' }, series: [{ name: 'Punch Card', type: 'heatmap', data: data, label: { show: true }, emphasis: { itemStyle: { shadowBlur: 10, shadowColor: 'rgba(0, 0, 0, 0.5)' } } }] }; function updateChart(values){ myChart.setOption({ visualMap: values }) }; document.body.addEventListener('change', (event) => { var targets = document.querySelectorAll('.changeable'); var new_values = [...targets].map(target => { var key_name = target.id.split('_')[0]; return { [key_name]: target.value }; }); var new_values = Object.assign(new_values[0], new_values[1]); updateChart(new_values); }); myChart.setOption(option); <script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/4.7.0/echarts.min.js"></script> <span> <input type="number" class="changeable" id="min_limit" value= 1> <input type="number" class="changeable" id="max_limit" value= 5> </span> <div id="main" style="width: 600px;height:400px;"></div>
HighMaps Not displaying Country Data
I am using Highcharts Js to display the Highmaps map bubble data. but the problem is that the Chart not plotting the bubble on Kosovo Country . For Example if I have a JSON Data as Follows . [ {"Country":"kosovo","persons":"2","CountryCode":"XK"}, {"Country":"india","persons":"2","CountryCode":"IN"} ] The Map is being displayed with only India Country Data. and shows nothing of Kosovo Country. This is The Javascript i used : var data_country = [{"Country":"kosovo","persons":"2","CountryCode":"XK"}, {"Country":"india","persons":"2","CountryCode":"IN"} ] ; data_country = data_country.map(function(el){ return {name: el.Country, z: parseInt(el.persons), 'iso-a2': el.CountryCode} }) Highcharts.mapChart('world-map', { chart: { plotBorderWidth: 1, plotBorderColor: '#ffffff', borderColor: "#ffffff", plotBackgroundColor: '#FFFFff', map: 'custom/world' }, title: { text: "" , enabled: false }, credits: { enabled: false }, exporting:{ enabled: false }, legend: { enabled: false }, mapNavigation: { enabled: true, buttonOptions: { verticalAlign: 'bottom' } }, series: [{ name: 'Countries', color: '#E0E0E0', states: { inactive: { opacity: 1 } }, enableMouseTracking: false }, { type: 'mapbubble', name: '', joinBy: 'iso-a2',//'iso-a3', 'code3'], data: data_country, minSize: '4%', color: '#577ba8', marker: { fillOpacity: 0.9 }, maxSize: '4%', tooltip: { pointFormat: '{point.properties.name}' } }] }); Please Tell me If I am missing something or is this an Highmaps error.
I see you are using the unofficial country code, as it has no official ISO country code: The unofficial 2 and 3-digit codes are used by the European Commission and others until Kosovo is assigned an ISO code. I also see that using KV in Highmaps seems to work. I'm not sure why they are using this partical country code. For example, from you code (JSFiddle): var data_country = [{"Country":"kosovo","persons":"2","CountryCode":"KV"}, {"Country":"india","persons":"2","CountryCode":"IN"} ]; data_country = data_country.map(function(el){ return {name: el.Country, z: parseInt(el.persons), 'iso-a2': el.CountryCode} });
Angular ng-options value DOES NOT update when scope changes
I'm having problems creating a select option dropdown using ng-options. Scope structure vm.filters = { perPage: 10, settings: { perPage: { intervals: [ { label: 'All', value: null }, { label: 10, value: 10 }, { label: 25, value: 25 }, { label: 50, value: 50 }, { label: 100, value: 100 } ] } } } Dom Element (angular generates the option tags) <select name="selectPerPage" data-ng-model="vm.filters.perPage" data-ng-options="interval.value as interval.label for interval in vm.filters.settings.perPage.intervals"> <option label="All" value="object:null">All</option> <option label="10" value="number:10" selected="selected">10</option> <option label="25" value="number:25">25</option> <option label="50" value="number:50">50</option> <option label="100" value="number:100">100</option> </select> When I change the value property of the first object in the intervals array from null to an actual number, scope for the option elements do not update. Why? How can I get it to update? It's almost like ng-model isn't referencing when scope updates.
If you use ng-options, you should not hard-coded options as you did in your select. You can only hard one (generally a null value). <select ng-model="vm.filters.perPage" ng-options="interval.value as interval.label for interval in vm.filters.settings.perPage.intervals"> <option label="All" value="">All</option> </select> I don't know what type interval.value is (array, object, string?), but it should be saved in vm.filters.perPage (supposing vm.filters exists).
you can try with ng-repeat, this will update the options dynamically. But unfortunately if the first element is selected when you update the data, the ng-change event won't be fired which means the value binded with ng-model won't be updated and you have to update it manually. angular.module("app", []) .controller("myCtrl", function($scope) { $scope.filters = { perPage: { intervals: [{ label: 'All', value: null }, { label: 10, value: 10 }, { label: 25, value: 25 }, { label: 50, value: 50 }, { label: 100, value: 100 }] } }; $scope.update = function() { $scope.filters.perPage.intervals[0].value = 1000; }; }); <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> <div ng-app="app" ng-controller="myCtrl"> <!--<select name="selectPerPage" data-ng-model="perPage" data-ng-options="interval.value as interval.label for interval in filters.perPage.intervals"> --> <select name="selectPerPage" data-ng-model="perPage"> <option ng-repeat="interval in filters.perPage.intervals" value="{{interval.value}}">{{interval.label}}</option> </select> {{perPage}} <button ng-click="update()">Update</button> </div>
Using Kendo Dataviz Vertical Bullet Graph, How to add labels similar to Bar Graph?
Trying to Style up the Bullet Graph to be exactly as Marketing desires. The desired Graph looks like: How do you add the labels at the top of the bars? I've tried to set the labels property from the Kendo Documentation: labels: { visible: true, format: "{0}", font: "14px Arial", }, Here is my script that isn't working: $barChart = $("#bar-chart").empty(); $barChart.kendoChart({ theme: global.app.chartsTheme, renderAs: "svg", legend: { position: "bottom" }, seriesDefaults: { type: "column" }, series: [ { type: "verticalBullet", currentField: "score", targetField: "average", target: { color: "#444", dashType: "dot", line: { width: 1, } }, labels: { visible: true, format: "{0}", font: "14px Arial", }, data: [ { score: 93.7, average: 65.2, }, { score: 80.2, average: 22.2, }, { score: 60.8, average: 35.2, }, { score: 82.1, average: 45.2, }, { score: 74.2, average: 55.2, } ] } ], categoryAxis: { labels: { rotation: -45 }, categories: ["Sales & Contracting", "Implementation & Training", "Functionality & Upgrades", "Service & Support", "General"], line: { visible: false }, color: "#444", axisCrossingValue: [0, 0, 100, 100] }, tooltip: { visible: false } }).data("kendoChart"); Any help would be greatly appreciated.
Because this is not a supported feature, any attempt to do this is by it's nature a hack. I had a look at kendo demo and noticed that there is a tooltip element with class k-tooltip that contains the total for a bar on mouseover. You should take a look into that mouseover to display the totals.
What you're attempting to do is possible. I've created an example on our Try Kendo UI site here: http://trykendoui.telerik.com/#jbristowe/aDIf/7
To recap, bullet charts don't support that type of label you need, and bar charts don't support the visual you need (the special line on the chart). You could switch back to bar charts and write a custom visual. However, an easier way is to use a plotband on the value axis: https://docs.telerik.com/kendo-ui/api/javascript/dataviz/ui/chart/configuration/valueaxis.plotbands <div id="chart"></div> <script> $("#chart").kendoChart({ valueAxis: { plotBands: [ { from: 1, to: 2, color: "red" } ] }, series: [ { data: [1, 2, 3] } ] }); </script> If you make a very narrow band, it will work pretty. It won't be dotted as in your reference image, and it will be behind the bar, which might be a problem... To go deeper, you would need a custom visual, and it's going to be involved: https://docs.telerik.com/kendo-ui/api/javascript/dataviz/ui/chart/configuration/series.visual