SAPUI5 Combination Chart data and chart formatting - charts

I would like to create a SAPUI5 combination chart - a column chart with a line for a particular category for each month that will compare one year to another. There are about 11 possible categories that the user can choose but the chart would only show one category's information at a time.
It would be similar to the following for one category:
I can create the chart to show data but I am having trouble converting it to use the data based on a category. I would think I can do what I want but I think the issue is in how my data is supplied.
This is my json (I am showing two categories in the data for example - I would like to be able to apply a filter for the category the user chooses):
{
"bullet": [{
"field":"Products Classified",
"months":[{
"month":"1",
"current":"17",
"previous":"140"
} ,{
"month":"2",
"current":"37",
"previous":"66"
},{
"month":"3",
"current":"60",
"previous":"66"
},{
"month":"4",
"current":"41",
"previous":"121"
}]
}, {
"field":"Products Not Classified",
"months":[{
"month":"1",
"current":"7",
"previous":"25"
} ,{
"month":"2",
"current":"50",
"previous":"78"
},{
"month":"3",
"current":"55",
"previous":"56"
},{
"month":"4",
"current":"45",
"previous":"60"
}]
}]
}
Here is part of my controller....
var oModel = new JSONModel("ByYear_sum.json");
sap.ui.model.FilterOperator.EQ, filterText);
var oDataset = new FlattenedDataset({
dimensions: [{
name: "Month",
value: "{month}"
}],
measures: [{
name: "Start Year",
value: "{current}"
},{
name: "End Year",
value: "{previous}"
}],
data: {
path: "/bullet"
filters: [oFilter]
}
});
oVizFrame.setDataset(oDataset);
oVizFrame.setModel(oModel);
oVizFrame.setVizProperties({
plotArea: {
dataLabel: {
visible: true,
formatString: '#,##0'
}
},
valueAxis: {
title: {
visible: false
}
},
legend: {
title: {
visible: false
}
},
title: {
visible: true,
text: 'Year Comparison'
}
});
var feedValueAxis = new FeedItem({
'uid': "valueAxis",
'type': "Measure",
'values': ["Start Year", "End Year"]
}),
feedCategoryAxis = new FeedItem({
'uid': "categoryAxis",
'type': "Dimension",
'values': ["Month"]
});
The value of filterText would be used to show the chart information for the chosen category (for example Products classified or Products Not classified).
I tried putting /months/ in front of the values (for example "{/months/previous}") to get to the values for the category (i.e. Products classified) but it doesn't seem to find the data properly (I get no data).
I would also like to display the text value of the month, not the number, how can I apply a formatter to the value?
My example chart shows year numbers....The years being compared come from user input, I currently cannot figure out how to get the values of the years chosen to show - I had to put 'Start Year' and 'End Year'. Is there a way to make the legend and popover show the year values (so dynamic based on user input)? Everything I tried gave me errors and wouldn't display the chart - I think because the feeds needed to match the same text and when I tried using a value it couldn't match.

I was finally able to get this to work, with some guidance from others.
1) In the title, I was able to set and update the title properties when the user chose a different filter.
2) The path was incorrect as well....it should have been /bullet/0/months - the '0' changes depending on the filter. I just had to get the index of the category chosen and use that for the path.
3) I changed my data to return the month abbreviation, instead of the number.
4) I was finally able to get the years to show both in the legend and the popup if you click a data point. In the FlattenedDataSet definition, I put a variable name in that is passed in when creating the FlattenedDataSet - so example: name was name: sYr, where sYr was passed in and the value of the year. In the FeedItem creation, the values look like: 'values': [sYr, eYr] I thought I had tried these, but it seemed to work with all the other changes that were made. I just had to create new FlattenedDataSet and FeedItems (and remove the old FeedItems) and update the chart with the new values.

Related

agGrid with Angular, using agRichSelectCellEditor

I have an agGrid populated with Employee records in JSON format from my web service.
[
{
id: 123,
firstName: 'Mike',
lastName: 'Jones',
countryId: 1001,
DOB: '1980-01-01T00:00:00',
. . .
}
I have a second web service returning a list of country codes:
[
{ id: 1000, name: 'France' },
{ id: 1001, name: 'Spain' },
{ id: 1002, name: 'Belguim' }
]
What I'm trying to do is get my agGrid to have a column showing the user's details, including the name of their country, and when they edit this cell, a list of country codes will appear, where they can select one, and it'll update the record with the id of that country.
Basic stuff, no ?
But has anyone managed to get agGrid to successfully use the "agRichSelectCellEditor" to do this successfully ?
{ headerName: 'Country', width: 120, field: 'countryId', editable: true,
cellEditor:'agRichSelectCellEditor',
cellEditorParams: {
// This tells agGrid that when we edit the country cell, we want a popup to be displayed
// showing (just) the names of the countries in our reference data
values: listOfCountries.map(s => s.name)
},
// The "cellRenderer" tells agGrid to display the country name in each row, rather than the
// numeric countryId value
cellRenderer: (params) => listOfCountries.find(refData => refData.id == params.data.countryId)?.name,
valueSetter: function(params) {
// When we select a value from our drop down list, this function will make sure
// that our row's record receives the "id" (not the text value) of the chosen selection.
params.data.countryId = listOfCountries.find(refData => refData.name == params.newValue)?.id;
return true;
}
},
My code seems to be almost correct.. it manages to:
display the country name in each row of the agGrid
display a popup, listing the country names, from our "list of countries" array
when I select an item in the popup, it successfully updates the countryId field with the (numeric) id value of my chosen country
The only problem is that at the top of the popup, it shows the countryId value, rather than the user's current country name.
Has anyone managed to get this to work ?
The only workaround I could come up with was to override the CSS on this popup and hide that top element:
.ag-rich-select-value
{
display: none !important;
}
It works... but you no longer get to see what your previously selected value was.
(I really wish the agGrid website had some decent, real-life, working Angular examples... or at least let developers post comments on there, to help each other out.)
The solution was to use a valueGetter, rather than a cellRenderer:
{
headerName: 'Country', width: 120, field: 'countryId', editable: true,
cellEditor:'agRichSelectCellEditor',
cellEditorParams: {
// This tells agGrid that when we edit the country cell, we want a popup to be displayed
// showing (just) the names of the countries in our reference data
values: listOfCountries.map(s => s.name)
},
valueSetter: function(params) {
// When we select a value from our drop down list, this function will make sure
// that our row's record receives the "id" (not the text value) of the chosen selection.
params.data.countryId = listOfCountries.find(refData => refData.name == params.newValue)?.id;
return true;
},
valueGetter: function(params) {
// We don't want to display the raw "countryId" value.. we actually want
// the "Country Name" string for that id.
return listOfCountries.find(refData => refData.id == params.data.countryId)?.name;
}
},
I hope this is useful...
I was able to get my similar situation (id:name pairs in a list, but not using Angular though) working without the problem you mentioned above, and without a valueGetter/valueSetter and only a renderer. The benefit is that you don't need to double click the cell to see the list, the cell appears as a selection box always, and you avoid a bug should the user double click the cell when the list is displayed.
The renderer is a lot clunkier than I was wanting (one line like yours) and it didn't seem that aggrid had built in support for this pretty basic function (and I already have spent enough time on this).
Anyway, this is what I had, which at least works, but keen to see further improvements on it. (You will need to at least change 2 lines for the option related code since my defaultValue object is specific to me).
The column definition:
{field: 'defaultValueID', headerName: "Default Value", cellEditor:'agRichSelectCellEditor', cellRenderer: defaultValueRenderer}
And the renderer code:
function defaultValueRenderer(params) {
var input = document.createElement("select");
// allow it to be cleared
var option = document.createElement("option");
option.innerHTML = '[None]';
option.value = null;
input.appendChild(option);
for (var i=0; i < defaultValueList.length; i++) {
var option = document.createElement("option");
option.innerHTML = defaultValueList[i].name;
option.value = defaultValueList[i].gltID;
input.appendChild(option);
}
input.value = params.value;
input.onchange = function() {
params.setValue(this.value);
params.data.defaultValueID = this.value;
}
input.style="width: 100%; height: 100%"; // default looks too small
return input;
}
Here Is Example Of agRichSelectCellEditor...
{
headerName: 'Dropdown', field: 'dropdown',
cellEditor: 'agRichSelectCellEditor',
width: 140,
editable: true,
cellEditorParams: (params) => {
values: Get All Dropdown List Like ["Hello","Hiii","How Are You?"]
},
valueSetter: (params) => {
if (params.newValue) {
params.data.dropdown= params.newValue;
return true;
}
return false;
}
}
Much simpler solution: use cellEditorParams formatValue, along with valueFormatter
{
field: 'foo',
cellEditor: 'agRichSelectCellEditor',
cellEditorParams: {
values: [1,2,3, 4, other ids... ],
formatValue: (id: number): string => this.getLabelFromId(value)
},
valueFormatter: (params: ValueFormatterParams): string => this.getLabelFromId(params.value as number)
}

creating a pie charts using string like 'used' and 'not used'

actually I'm doing this internship for my school i need to use the information on a very large database to actually draw a pie chart on the website i am developing for them. they want to know the number of ports used versus not used also they want to know for each equipment the number of ports used versus not used in such way that any new data entered can automatically change the graph. the only values present are "used" and "not used" how do i use these information to draw the pie chart?. thank you
Since you don't list the database structure here is a generic SQL query:
SELECT status, COUNT(*)
FROM yourTable
GROUP BY status
Here status refers to the column that states "used" or "not used" and yourTable is, well, the table that contains this info. Once you have this you can create a pie chart in highcharts via:
Highcharts.chart('container', {
chart: {
plotBackgroundColor: null,
plotBorderWidth: null,
plotShadow: false,
type: 'pie'
},
title: {
text: 'Ports in use'
},
tooltip: {
pointFormat: '{series.name}: <b>{point.percentage:.1f}%</b>'
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: 'pointer',
dataLabels: {
enabled: true,
format: '<b>{point.name}</b>: {point.percentage:.1f} %',
style: {
color: (Highcharts.theme && Highcharts.theme.contrastTextColor) || 'black'
}
}
}
},
series: [{
name: 'Brands',
colorByPoint: true,
data: [{
name: 'used',
y: 56 // from the SQL query
}, {
name: 'not used',
y: 24, // from the SQL query
sliced: true,
selected: true
}]
}]
});
Live demo.
To have this chart updated I would recommend a timer to re-query the database on an interval and refresh the data in the chart. Because you do not mention any other dependencies I am just going to link out to how to update a highcharts chart. If you provide more info like what libraries you are using or what framework the webpage is using then a more detailed answer can be provided.

Google Visualization Meteor Implementation

help me in upper or lower code problem must be appreciated
i want to make a bar chart and populate it from my collection from meteor i
want to print exercises with there status
but when i return one record from db it is working well graph is coming but
when coming two records its not working kindly help in it
Just help me that how i can make a correct JSON format for "google visualization graph" from meteor mongodb
function drawChart() {
var status=Session.get('status');
var graphData=Session.get("graphId");
console.log("graphData==========",graphData)
patientLog.find({patientId: graphData},{fields:
{patientExerciseName:1,status:1,_id:0}}).forEach(function (myDoc) {
var data = new google.visualization.DataTable();
data.addColumn({ type: 'string', id: 'Room' });
data.addColumn({ type: 'string', id: 'Name' });
data.addRows([
[ myDoc.status, myDoc.patientExerciseName]
])
var options = {
chart: {
title: 'Company Performance',
subtitle: 'Sales, Expenses, and Profit: 2014-2017',
},
bars: 'vertical' // Required for Material Bar Charts.
};
var chart = new google.charts.Bar(document.getElementById('barchart_material'));
chart.draw(data, options);
})
}
Note : Foreach function when return two rows from database it not works
as i also try this
when i give JSON to my graph it is giving error "Invalid data table format:
must have at least 2 columns".
how i can make a JSON format which support Google visualization charts
please help me mine code is there
function drawChart() {
var status=Session.get('status');
var graphData=Session.get("graphId");
patientLog.find({patientId: graphData},{fields:
{patientExerciseName:1,status:1,_id:0}}).forEach(function (myDoc) {
var Mydoc=JSON.stringify(myDoc)
var data = new google.visualization.DataTable(Mydoc)
var options = {
chart: {
title: 'Company Performance',
subtitle: 'Sales, Expenses, and Profit: 2014-2017',
},
bars: 'vertical' // Required for Material Bar Charts.
};
var chart = new
google.charts.Bar(document.getElementById('barchart_material'));
chart.draw(data, options);
})
}
1) Check that the data is received: in Meteor it is sometimes tricky as publications may not be ready when you draw your chart. You need to make sure you wait for the publication to be ready. (Use console log to log the data and see if it's there, as within the debugger the data will be there by the time you look it up
2) once you are sure the data is there, read the GoogleChart docs: it is a fairly extensive library with lots of examples, so just make sure you data matches the right format.
this question and answer should help:
Building array and formatting JSON for Google Charting API

Kendo Chart Missing CategoryAxis Text for multiple series

I am creating a kendo chart that can have multiple datasets.
I am creating a chartOptions object that is only being manipulated by referencing the properties and is not manipulated through Kendo functionality. This is done by the following code:
var chartOptions = {
theme: "",
seriesDefaults: {
type: "line"
},
title: {
text: ""
},
legend: {
position: "bottom"
},
series: "",
categoryAxis: {
field: "category"
}
};
function createChart() {
$("#chart").kendoChart(
$.extend(true, {}, chartOptions)
);
}
I also have the user defining which datasets they want. The choose their datasets and create their chart. The chart is then rendered but missing its categoryAxis data.
I am setting the series data (the data comes from the server, but is available for example) in the following way:
dataSetContents.Series = {"Series":[{"name":"2009 Data","data":[{"category":"2008","value":18159},{"category":"2007","value":315},{"category":"2009","value":8}]},{"name":"2008-2010","data":[{"category":"2010","value":750},{"category":"2009","value":2980},{"category":"2008","value":4135},{"category":"2007","value":55}]}]}
chartOptions.series = dataSetContents.Series;
I figured out the reason why I was losing my categories. It has to do with the multiple series, the way to fix this by setting the categoryAxis. This can be done by passing the array of categories like this:
chartOptions.categoryAxis = { categories: [2007,2008,2009,2010] };

Extjs grid with multiselect feature to retrieve value of selected lists

Let's say I have a grid with multiselect option on, when user selects 4 lists and wants to get the values ( alerted on screen) how would I do that? And how would I disable buttons untill at least one list is selected?
All questions you've asked are answered many times already. Also there are good ExtJS examples on sencha.com. For example list view grid shows multiple select and editable grid with writable store shows button enable on click. But THE MOST important is documentation! Let me explain functionality on following code. Most of it is from list view example.
This grid gets JSON from list.php which has following structure
{"authors":[{"surname":"Autho1"},{"surname":"Autho2"}]}
And the grid:
Ext.require([
'Ext.grid.*',
'Ext.data.*',
'Ext.panel.*'
]);
Ext.onReady(function(){
// Here i've definned simple model with just one field
Ext.define('ImageModel', {
extend: 'Ext.data.Model',
fields: ['surname']
});
var store = Ext.create('Ext.data.JsonStore', {
model: 'ImageModel',
proxy: {
type: 'ajax',
url: 'list.php',
reader: {
type: 'json',
root: 'authors'
}
}
});
store.load();
var listView = Ext.create('Ext.grid.Panel', {
id: 'myPanel', // Notice unique ID of panel
width:425,
height:250,
collapsible:true,
renderTo: Ext.getBody(),
store: store,
multiSelect: true,
viewConfig: {
emptyText: 'No authors to display'
},
columns: [{
text: 'File',
flex: 50,
// dataIndex means which field from model to load in column
dataIndex: 'surname'
}],
dockedItems: [{
xtype: 'toolbar',
items: [{
// This button will log to console authors surname who are selected
// (show via firebug or in chrome js console for example)
text: 'Show selected',
handler: function() {
// Notice that i'm using getCmp(unique Id of my panel)
// to get panel regerence. I could also use
// this.up('toolbar').up('myPanel')
// see documentation for up() meaning
var selection = Ext.getCmp('myPanel').getSelectionModel().getSelection();
for (var i=0; i < selection.length; i++) {
console.log(selection[i].data.surname);
}
}
},{
text: 'Disabled btn',
id: 'myHiddenBtn', // Notice unique ID of my button
disabled: true // disabled by default
}]
}]
});
// Here i'm waiting for event which is fired
// by grid panel automatically when you click on
// any item of grid panel. Then I lookup
// my button via unique ID and set 'disabled' property to false
listView.on('itemclick', function(view, nodes){
Ext.getCmp('myHiddenBtn').setDisabled(false);
});
});
I didn't knew how to do this from top of my head, but I used documentation and the result works ;-). See Grid panel docs for more information.