I'm using chartkick gem to render a Google timeline graph. While this works very nicely out of the box, I read on the Google documentation, that I'm also able to include a bar label:
https://developers.google.com/chart/interactive/docs/gallery/timeline#labeling-the-bars
Is there an option to add that extra column to the datatable with the help of Chartkick?
I basically need this to be invoked before the Timeline is rendered:
dataTable.addColumn({ type: 'string', id: 'Name' });
Thanks
Code sample:
<%= timeline [
["Washington", "1789-04-29", "1797-03-03"],
["Adams", "1797-03-03", "1801-03-03"],
["Jefferson", "1801-03-03", "1809-03-03"]
] %>
This requires a change in the source, chartkick.js:
First, you need to add a line describing the new data column to the beginning of "this.renderTimeline" (i've called it Label):
...
var data = new google.visualization.DataTable();
data.addColumn({type: "string", id: "Label"});
data.addColumn({type: "string", id: "Name"});
data.addColumn({type: "date", id: "Start"});
data.addColumn({type: "date", id: "End"});
data.addRows(chart.data);
Second, you need to update the "processTime" function, by adding 1 to the array values (since we've increased the array size by 1):
function processTime(chart)
{
var i, data = chart.rawData;
for (i = 0; i < data.length; i++) {
data[i][2] = toDate(data[i][2]); // from data[i][1]
data[i][3] = toDate(data[i][3]); // from data[i][2]
}
return data;
}
Related
Full example:
https://jsfiddle.net/gbeatty/4byg0p2t/
data: {
table: 'datatable',
startRow: 0,
endRow: 6,
startColumn: 0,
endColumn: 3,
parsed: function (columns) {
columns.forEach(column => {
column.splice(1, 2);
});
}
},
What I'd like the chart to reference is only column 0 "Year" and column 3 "Group C" while keeping the entire table displayed below. Challenge is disregarding the 2 columns in the middle.
I am trying the parsed option but it seems the rows and columns are mixed up. I even tried setting the switchRowsAndColumns value to true. (https://api.highcharts.com/highcharts/data.seriesMapping)
You can also use complete function to modify your data.
Example code based on your config:
complete: function(options) {
let series = [];
series.push(options.series[2]);
options.series = series;
}
Demo:
https://jsfiddle.net/BlackLabel/tfs4ubcL/
API Reference:
https://api.highcharts.com/highcharts/data.complete
This is in a C# ASP.NET MVC 5 web application. jQuery version 1.10.2. DataTables jQuery plugin version 1.10.21.
A page in the web application uses a DataTable. The DataTable is configured for server-side processing mode. So, when it receives a response from the server, the data for a row in the table is an object like the following example. (It is not proper JSON syntax; I am trying to represent what I see in the watch window of the browser's debugger.) i.e., each row has a string name, and an array of grade objects.
row: {...}
Id: 42
Name: "Fred"
Grades: (3) [...]
0: {...}
Id: 101
Name: "Quiz 1"
Value: "A"
1: {...}
Id: 102
Name: "Homework 2"
Value: "B"
2: {...}
Id: 103
Name: "Exam 3"
Value: "C"
length: 3
In the DataTable, I want 4 columns: one for the name, and 3 for the several grades, like the following example.
Name Quiz 1 Homework 2 Exam 3
=========================================
Fred A B C
My problem is that I cannot determine the correct notation for the data source for each of the grade columns, so that when a cell in such a column is rendered that the callback function receives an object that contains data about the grade. The following is what I have tried in the CSHTML file for the page. (I provide the number of grades to the page via a ViewBag property.)
...
<table id="gradebook-table" class="table">
...
</table>
...
<script>
$( document ).ready( onPageReady );
function onPageReady()
{
var options = {};
options.serverSide = true;
options.ajax =
{
'url': '#Url.Content( "~/gradebook/load" )',
'type': 'POST',
};
var c = 0;
options.columnDefs = [
{ targets: c++, data: "Id", visible: false, searchable: false },
{ targets: c++, data: "Name" },
];
for ( var i = 0; i < #ViewBag.GradeCount; i++ )
{
var def = {};
def.targets = c++;
def.data = "Grades[" + i + "]";
def.render = renderGradeCell;
options.columnDefs.push( def );
}
$( '#gradebook-table' ).DataTable( options );
}
function renderGradeCell( data, type, row, meta )
{
if ( type === 'display' )
{
// I expect data to be an object containing grade properties.
return '<span>' + data.Value + '</span>';
}
return data;
}
</script>
When the data source for a grade column is "Grades[" + i + "]", the data that the renderGradeCell() function is given is not an object that I expected, but a string like the following. It is just "[object Object]0" repeated for as many items as there are in the Grades array in the data for the whole row.
"[object Object]0[object Object]0[object Object]0"
I changed the data source for a grade column to just "Grades[]". But then, the data that the renderGradeCell() function is given is the entire Grades array for that row.
Any suggestions are appreciated. Thanks.
I am able to create a table using the Google Docs Api. By default, each column is of equal width.
How is it possible to adjust the width of the columns using the Google Docs API?
I can see the updateTextStyle and updateParagraphStyle request types (batchUpdate methods) but there's currently no updateTable method, or any similar method that looks like it could do this. I'm using the reference documentation, here:
https://developers.google.com/docs/api/reference/rest/v1/documents/request
I'm using NodeJS / Javascript to interact with the API currently.
This is possible, in fact all the table operation that you can do on UI are possible.
1) Create table with following request:
def create_loc_table(doc_id, r, c, idx):
"""
r = number of rows,
c = number of columns,
idx = Start index where table needs to be created.
"""
request = [{
'insertTable': {
'rows': r,
'columns': c,
'location': {
'segmentId':'',
'index': idx
}
},
}
]
result = self.docs_service.documents().batchUpdate(documentId=doc_id, body={'requests': request}).execute()
print('Result {0}'.format(json.dumps(result, indent=4)))
2) Modify/update the table:
def modify_table(self, t_idx):
"""
t_idx = Table start index.
"""
request = [{
'updateTableColumnProperties': {
'tableStartLocation': {'index': t_idx},
'columnIndices': [0],
'tableColumnProperties': {
'widthType': 'FIXED_WIDTH',
'width': {
'magnitude': 100,
'unit': 'PT'
}
},
'fields': '*'
}
}
]
result = self.docs_service.documents().batchUpdate(documentId=doc_id, body={'requests': request}).execute()
print('Result {0}'.format(json.dumps(result, indent=4)))
3) Output would be
I'm using Bloodhound to fetch data from the database, then twitter typeahead to display the options below a search box.
Currently, the bloodhound part is finding the objects required, but the typeahead is not displaying them.
var artist_retriever = new Bloodhound({
// turns input query into string of tokens to send to database.
queryTokenizer: Bloodhound.tokenizers.whitespace,
remote: {
// URL to fetch information from
url: "/artists?query=%QUERY",
wildcard: '%QUERY',
// Manipulate the array of artists returned, for display to user.
transform: function(array_of_artists){
// array of artists is returned from DB.
// Put each artist into a readable string
array_of_artists = create_artist_descriptions(array_of_artists)
console.log(array_of_artists)
// Returns correctly:
// [
// { artist: "Joe" },
// { artist: "Bob" },
// { artist: "Smith" },
// { artist: "Tom" },
// ]
return array_of_artists
}
},
// turns return value into a string of results, with this 'key' before each result.
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('artist'),
});
// display:
// instantiate the typeahead UI
// https://github.com/twitter/typeahead.js/blob/master/doc/jquery_typeahead.md
searcher = $('.typeahead').typeahead(
// options:
{
hint: false
},
// datasets:
{
// Where to get data: User the bloodhound suggestion engine:
source: artist_retriever.ttAdapter(),
// Which attribute of each result from the database should be shown:
displayKey: 'artist',
templates: {
notFound: new_artist_option_template(),
footer: new_artist_option_template()
}
}
)
Update
It turns out that there's a weird bug in typeahead. It only seems to work with the "limit" attribute set to a maximum of 4. If you set "limit" to 5, the typeahead gives you nothing.
searcher = $('.typeahead').typeahead(
// options:
{
hint: false
},
// datasets:
{
// Where to get data: User the bloodhound suggestion engine:
source: artist_retriever.ttAdapter(),
// Which attribute of each result from the database should be shown:
displayKey: 'signature',
limit: 4, // This can do a max of 4! Odd.
templates: {
notFound: new_artist_option_template(),
footer: new_artist_option_template()
}
}
This issue has been solved. Please see update 2 directly.
I have reproduced this issue in this JSFIDDLE.
As you said, its a bug. You also reported that this bug goes away if you do limit:4.
Actually on my end, or in the FIDDLE, I have experienced that this issue comes when the number of results returned = value in limit.
To test this issue in the FIDDLE, do the following:
Note: Searching for 1947 returns exactly 5 rows.
When limit is set to 4:
Searching for 1947 returns 4 results.
When limit is set to 5:
Searching for 1947 returns nothing.
When limit is set to 6:
Searching for 1947 returns one 1 result - the first result.
Hence if you keep the limit set to 1 less than the actual number of results returned, then this will keep on working.
I have also submitted this issue in their github page. I will be keeping track of this issue and will keep updating this answer as need be.
Update 1:
Found a similar question on SO here. "Luciano GarcĂa Bes" seems to have figured the solution. Please direct all upvotes there.
Basically he says:
It's counting the number of rendered hints before appending them, so
if the number of hints equals the limit it'll append an empty array.
To prevent this I just switched lines 1723 and 1724 so it looks like this:
that._append(query, suggestions.slice(0, that.limit - rendered));
rendered += suggestions.length;
Update 2:
This issue has been fixed on pull 1212. Closing our own issue 1312. The bug was corrected the same way discussed in update 1.
I've created a chart that has an array of objects with named values like the following
data: [{
name: 'Point 1',
color: '#00FF00',
y: 0
}, {
name: 'Point 2',
color: '#FF00FF',
y: 5
}]
If I wanted to later look at back my data series later and get back the names "Point 1" and "Point 2", how would I do so?
I tried a function that iterates the data series like this:
var data = someSeries.data;
for ( var i = 0; i < data.length; i++ )
{
alert( data[i]['x'] );
}
which gets me each point, but obviously doesn't work since the x data is stored as a number (I tried doing an array with 2 values instead of the point configuration objects with similar results). 'name' is undefined for that data point as well.
Does the initial name that I entered when generating the series get saved anywhere for me to access? Am I looking at the wrong object?
If you are trying to reference data inside of the chart after initialization you need to reference the chart first. Then access the name property like you would with any other object property.
var myData = myChartName.series[0].data;
for ( var i = 0; i < myData.length; i++ )
{
alert( myData[i].name );
}