Grouped Stacked Bar/Column Chart with Chartkick on Ruby on Rails - ruby-on-rails

I have two datasets containing data gathered automatically by AI and another data gathered manually by humans. I currently display these into two separate column charts using Chartkick for Rails:
As shown above, the AI data is displayed as a stacked column chart that shows the breakdown of the confirmed, rejected, and unverified data because we still do confirmation checks to see the accuracy of our AI while the Human Operated Data is displayed as is, hence, no need to use a stacked column chart.
Now, what I want to achieve is to display the AI and Human Operated Data side by side (grouped), while maintaining the stacked property of the AI Data. So it should look like this:
The code that I currently have for the two separate charts are:
controller
# Data for Stacked Column Chart
#ai_operated_data = [
{
name: "Confirmed",
data: PotentialViolator.where(confirmation_status: 1).group_by_week(:capture_time).count
},
{
name: "Rejected",
data: PotentialViolator.where(confirmation_status: 0).group_by_week(:capture_time).count
},
{
name: "Unverified",
data: PotentialViolator.where(confirmation_status: -1).group_by_week(:capture_time).count
}
]
# Data for Single Column Chart
#human_operated_data = [
{
name: "Human Operated Data",
data: ManuallyCaughtViolator.group_by_week(:capture_time).count
}
]
view
<div class="ui container">
<h1>Performance Analytics</h1>
<div class="ui divider"></div>
<%= column_chart #ai_operated_data, stacked: true %>
<%= column_chart #human_operated_data %>
</div>

I was able to find the an example from the Chartkick.js examples and found out that there's just the stack option which you can pass as a parameter to specify if a series will be a part of the stack or not.
My final code in my view now looks like:
<%= column_chart [
{
name: "Confirmed AI-PWD Operated Data",
data: PotentialViolator.where(confirmation_status: 1).group_by_week(:capture_time).count,
stack: "stack 1"
},
{
name: "Rejected AI-PWD Operated Data",
data: PotentialViolator.where(confirmation_status: 0).group_by_week(:capture_time).count,
stack: "stack 1"
},
{
name: "Unverified AI-PWD Operated Data",
data: PotentialViolator.where(confirmation_status: -1).group_by_week(:capture_time).count,
stack: "stack 1"
},
{
name: "PWD-Operated Data",
data: ManuallyCaughtViolator.group_by_week(:capture_time).count,
stack: "stack 2"
}
], stacked: true
%>
So it produces this chart:

Related

applying *ngFor on <li> only shows list with empty data, while fetching data from api on ngOnInit()?

To show data obtained from Api, I applied *ngFor directive on li tag. Then, I used interpolation to show the data inside the li tag. But I am not getting any data in the list. However, the list does show exactly the same number of empty list items as the number of items available in the data obtained from API. If I log the data inside the subscribe method browser logs data obtained from api but when I log the data outside subscribe method browser logs undefined object. I have attached my codes. I will appreciate any form of help and advice.
I tried appplying *ngIf condition to only make the list visible once the data is already subscribed in ngOnInit parent ul tag of li as suggested in one of the other posts.
branch-list.component.ts
constructor(private service : BranchService) { }
ngOnInit() {
this.service.getAll()
.subscribe((data: Branch[]) => {
this.branches = data;
console.log(this.branches);
});
console.log(this.branches);
};
branch-list.component.html
<ul class="list-group-flush" *ngIf="branches">
<li *ngFor="let branch of branches; let serialNo = index" class="list-group-item">
<span hidden>{{branch.Id}}</span>
{{ serialNo+1 }}. {{ branch.BranchCode }} {{ branch.Description }}
</li>
</ul>
<ul>
console of browser
Angular is running in the development mode. Call enableProdMode() to enable the production mode.
undefined
(7) [{…}, {…}, {…}, {…}, {…}, {…}, {…}]
0: {id: 1, branchCode: "KTM", description: "Kathmandu"}
1: {id: 2, branchCode: "PKH", description: "Pokhara"}
2: {id: 3, branchCode: "HTD", description: "Hetauda"}
3: {id: 4, branchCode: "MHN", description: "Mahendranagar"}
4: {id: 5, branchCode: "JHP", description: "Jhapa"}
5: {id: 6, branchCode: "KTM", description: "Kathmandu"}
6: {id: 7, branchCode: "PTN", description: "PTN"}
length: 7
__proto__: Array(0)
The list is supposed to show the data as logged in the console.Console logs data as expected. But in the page, empty list is shown. The empty list only updates and shows the value of serial no but both branchcode and descriptions are blank.
Initially set branches = null;
Instead of performing API call in ngOnInIt try in ** ngAfterViewInit** - place where DOM is rendered
ngAfterViewInit() {
this.service.getAll()
.subscribe((data: Branch[]) => {
this.branches = [...data];
console.log(this.branches);
});
};
<ul class="list-group-flush" *ngIf="branches && branches.length">
<li *ngFor="let branch of branches; let serialNo = index" class="list-group-item">
{{ serialNo+1 }}. {{ branch.BranchCode }} {{ branch.Description }}
</li>
</ul>
<ul>
With my understanding i think would work try and update

Antd Using <Table> as Array Form Input

i currently building a react app with ant-design UI. I have a problem regarding form. So far, i already able to create and submit normal form. But as i tried to create a more complex form, i faced these problem:
I want to create a form with input like this:
code: string,
name: string,
order: {
itemid: number,
qty: number
}
the 'order' part is an array, which means i can have more than 1 order in one form. I want to create that part of the form by using component in antd, where i can render the column like this:
{ title: L('Item Id'), width: 150, render: (text: string, item: any, index: any) => (
<Form.Item {...formItemLayout}>
{getFieldDecorator('order[' + index + '].itemid', {
rules: [{
required: true, message: 'Please select id!'
}]
})(
<ItemIdSelectInput/>
)}
</Form.Item>
) }
Can i use the table like that?
Also, as far as i know, component must have a 'datasource' in order to be used, while i want to create a 'Create' form where has no initial value (empty). Is there any reference or a better way to create this kind of form in antd? Thanks in advance!

ui-grid how to get columns and headers to line up and span full width of the grid

I've just started testing with ui-grid to see if I can use it in some of my projects. The problem I am having is when it renders the columns are of various sizes and do not line up with the column headers.
Within my controller I am defining the gridOptions as follows:
var vm = this;
vm.smtGridOptions = {
columnDefs:
[{ field: 'smtTypeCodeText', displayName: 'Type' },
{ field: 'description', displayName: 'Description' },
{ field: 'location', displayName: 'Location' },
{ field: 'dateEntered', displayName: 'Date Entered' }
]
}
the data is bound further down using
vm.smtGridOptions.data = vm.detail.smts;
In my html I have the grid added as follows:
<div ng-show="name.detail.smts.length > 0" scroll-to-section>
[![enter image description here][1]][1]<hr style="clear: both; margin-bottom: 5px !important;"/>
<a class="anchorOffset" id="smts"></a>
<p>
<strong><em>SMTs</em></strong>
</p>
<div id="smtGrid" ui-grid="name.smtGridOptions" class="uigrid"></div>
</div>
As a note, I'm using ui-router in this project so name represents the ControllerAs for the current view.
Options and data binding are working but when the application renders. I get a grid rendered like this:
Is there a setting or CSS setting that will allow the grid columns to span (almost in a justified manner) the width of the grid. Currently it appears that it valuates the data in the grid and renders the column to match regardless of column definition.
Thanks in advance
I had the same problem. I'm using ui-router and ui-bootstrap. My grids were in a uib-tab element from the ui-bootstrap project. When switching between tabs I was experiencing the rendering you're seeing.
What worked for me was injecting 'ui.grid.autoResize' into my module and adding the ui-grid-auto-resize directive to my grid div.
On the the ui-grid tutorial page here: http://ui-grid.info/docs/#/tutorial/108_hidden_grids There is a link to this Plunker: http://plnkr.co/edit/fwdXMamTBrR1yKVwcohZ?p=preview which has a similar setup that I followed.
var app = angular.module('app', ['ui.grid', 'ui.bootstrap', 'ui.grid.autoResize']);
<div id="grid1" ui-grid="gridOptions" ui-grid-auto-resize class="grid"></div>

Grails dynamic rendering of map-injected g:select

I have the following Grails (2.3.6) controller:
class WidgetController {
def index() {
Map<String, List<String>> widgetMap = getSomehow()
render (
view: "widgets",
model: [ widgetMapping: widgetMap ]
)
}
}
And the following GSP:
<!DOCTYPE html>
<html>
<head>
<!-- Omitting a bunch of stuff for brevity -->
</head>
<body>
<h3>Widget Mappings</h3>
<g:select name="widgetMapping" from="${widgetMapping}"/>
<div id="widgetMapping">
</div>
</body>
</html>
I am trying to accomplish the following:
For each key in the widgets map, display an <option/> in the dropdown <select/>
When a user selects one of those <option/>s (or when the page first loads with the default option), the <div id="widgetMapping"> section should be populated with a <ul> list, where each <li> in the list corresponds to one of the elements in the List<String> that the selected widget is mapped to
In other words, if the widgetMap (above, in the controller) looks like this at runtime:
Map<String, List<String>> widgetMap = []
List<String> colors = []
List<String> pets = []
colors << "Red"
colors << "Blue"
colors << "Green"
pets << "Dog"
pets << "Cat"
widgetMap.put("Colors", colors)
widgetMap.put("Pets", pets)
...then in the rendered HTML I would expect to see a <select> with 2 <option> children: "Colors" and "Pets". When you select "Colors" you should see a bulleted (<ul>) list enumerating "Red", "Blue", "Green"; and if you select "Pets" you would see any previous list clear and then display a list of "Dog" and "Cat" in its stead. Thus, making any new selection from the dropdown should clear the currently-displayed list and display the correct list for that option's respective key in the map.
Given the GSP code I have above, this behavior is simply not happening. Any ideas as to what I need to do?
Based on what you have mentioned, you have a couple of different options.
Pass the entire map back to the client and store the values in a javascript value. I don't like this because it doesn't scale very well. In your example, you only have a couple of keys with a couple of values in each list, but this could grow pretty quickly, and I don't think you should necessarily be storing all of that data in memory on the client side.
Make subsequent Ajax calls to simply return the list for each key. This could be accomplished by listening for a change event on the drop-down, then replacing the contents of the div with a GSP rendered template. I like this option much better as it scales. Sure it makes more calls to the server, but the amount of data per call is minimal and your user experience will actually improve overall as the initial page-load will be reduced.
Controller:
class WidgetController {
def index() {
def widgetKeys = getSomehow()
render (
view: "widgets",
model: [ widgets: widgetKeys ]
)
}
def widgetList (String key) {
def widgetList = getSomehow(key)
render (
template: "widgetTemplate",
model: [ widgetList: widgetList ]
)
}
}
Template:
<ul>
<g:each in="${widgetList}">
<li>${it}</li>
</g:each>
</ul>
Javascript:
$(function () {
$('#selectId').on('change', function(){
var select = this;
$.ajax({
url: 'widgetList', //might have to play with this so it is not hardcoded
data: { 'key': select.value },
success: function (list) {
$('#widgetMapping').html(list);
}
});
})
});
I'm not guaranteeing that this will get you exactly what you want, but this should at least get you on the right track. There is a wealth of documentation for JQuery and several examples around the web, so I suggest you look around if you think you want to do something different.

Binding an ExtJs combobox form field's selected item

I've just started working with extjs 4 and I'm trying to use it alongside asp.net MVC 3. I'm having trouble setting up a typical form for editing a record where one of the fields uses a ComboBox. I cant seem to find an elegant way to bind the initial selected value to the value of a property on my model. Does anyone have any suggestions. I would think this should be simple to accomplish. Here's my form so far... Thanks in advance.
{
xtype: 'form',
items: [
{
xtype: 'combobox',
fieldLabel: 'Group',
displayField: 'Name',
valueField: 'GroupId',
store: 'GroupStore',
allowBlank: false,
forceSelection: true,
editable: false,
queryMode: 'local'
},
{
xtype: 'textfield',
name: 'Description',
fieldLabel: 'Description'
}
]
}

Resources