Skip to content

Commit

Permalink
Simple Data Grapher: Integration + Research Note + Tests (#6113)
Browse files Browse the repository at this point in the history
* New Table for CsvFiles

* belongs_to for CSV files

* CSV controller code

* routes for simple-data-grapher

* has_many relation for users

* view files for csvfiles

* user data display

* Added simple-data-grapher package

* Delete Gemfile

* Gemfile

* code climate

* Climate 2

* climate 3

* fix code climate issues

* Update schema.rb.example

* Fixing changes

* Error Handling

* Fixed the errors

* linting

* minor fix in alert

* more linting

* work on research note

* Publish as a Research Note Ready!

* updating schema

* Tests for Csvfiles controller for Simple Data Grapher

* Bug Fixes

* Schema's time stamp

* climate fixes

* cc

* return statement

* refactor graph details method

* Update node_shared.rb

* Adding line break

* Refactored and changes Power tag

* removing spacing in rich.html.erb

* trying to fix cyclomatic complexity (code climate)

* Updating SDG version with new UI

* refactoring js code

* linting fixes

* linting errors

* more linting fixes

* removing log statements

* index

* Changing routes

* system test

* fixing test
  • Loading branch information
IshaGupta18 authored and jywarren committed Aug 20, 2019
1 parent 3a0e974 commit 6b9d93b
Show file tree
Hide file tree
Showing 22 changed files with 1,442 additions and 28 deletions.
1 change: 1 addition & 0 deletions app/assets/javascripts/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
//= require leaflet_helper
//= require grids.js
//= require graph.js
//= require simple-data-grapher.js
//= require wikis.js
//= require header_footer.js
//= require keybindings.js
Expand Down
72 changes: 72 additions & 0 deletions app/assets/javascripts/simple-data-grapher.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
function determineType2(graphType){
if (graphType === "Horizontal" || graphType === "Vertical"){
return "bar";
}
else if (graphType === "Pie" || graphType === "Doughnut" || graphType === "Radar" ){
return "pie";
}
else {
return "scatter";
}
}
function layoutMaker(graphType){
let layout = {};
if (graphType === "Horizontal" || graphType === "Vertical"){
layout["barmode"] = "group";
}
return layout;
}
function traceMaker(graphType){
let trace = {};
trace["type"] = determineType2(graphType);
if (graphType === "Horizontal"){
trace["orientation"] = "h";
}
else if (graphType === "Doughnut"){
trace["hole"] = 0.5;
}
else if (graphType === "Basic"){
trace["mode"] = "lines";
}
else if (graphType === "Point"){
trace["mode"] = "markers";
}
else if (graphType === "Stepped"){
trace["mode"] = "lines+markers";
trace["line"] = { "shape": 'hv' };
}
return trace;
}
function keyDeterminer(graphType){
let keys = ["x", "y"];
if (graphType === "Pie" || graphType === "Doughnut"){
keys[1] = "values";
keys[0] = "labels";
}
else if (graphType === "Horizontal"){
keys[0] = "y";
keys[1] = "x";
}
return keys;
}
function plotGraph2(dataHash, length, graphType, divId){
let layout = layoutMaker(graphType);
let data = [];
let keySet = keyDeterminer(graphType);
for (let i = 0;i < length;i++){
let new_trace = traceMaker(graphType);
new_trace[keySet[0]] = dataHash['x_axis_labels'];
new_trace[keySet[1]] = dataHash['y_axis_values' + i];
new_trace["name"] = dataHash['labels'][1][i];
data.push(new_trace);
}
Plotly.newPlot(divId, data, layout);
}
function graphMaker(data, divId){
let obj = data["sdgobject"];
let actualHash = JSON.parse(obj);
let dataHash = actualHash["hash"];
let length = actualHash["length"];
let graphType = actualHash["graphType"];
plotGraph2(dataHash, length, graphType, divId);
}
54 changes: 54 additions & 0 deletions app/controllers/csvfiles_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
class CsvfilesController < ApplicationController
before_action :require_user, only: %i(delete user_files)

def setter
@csvfile = Csvfile.new(
uid: params[:uid],
filetitle: params[:filetitle],
filedescription: params[:filedescription],
filepath: params[:object],
filename: "file" + Time.now.to_i.to_s,
filestring: params[:filestring]
)
render json: @csvfile if @csvfile.save
end

def prev_files
@allfile = Csvfile.where(uid: params[:uid])
render json: @allfile
end

def user_files
@user_files = Csvfile.where(uid: params[:id])
end

def add_graphobject
@newfile = Csvfile.new(
uid: params[:uid],
filetitle: params[:filetitle],
filedescription: params[:filedescription],
filepath: params[:object],
filename: "file" + Time.now.to_i.to_s,
filestring: params[:filestring],
graphobject: params[:graphobject]
)
@newfile.save
render json: { uid: params[:uid], id: @newfile.id }
end

def delete
return unless params[:id] && params[:uid].to_i == current_user.uid
file = Csvfile.where(id: params[:id].to_i)
if file.destroy(params[:id].to_i)
flash[:notice] = "Deleted the file"
else
flash[:error] = "Could not delete the file"
end
redirect_to "simple-data-grapher/data/#{params[:uid]}"
end

def fetch_graphobject
@graphobject = Csvfile.where(id: params[:id].to_i, uid: params[:uid].to_i)
render json: { sdgobject: @graphobject[0].graphobject }
end
end
1 change: 1 addition & 0 deletions app/helpers/application_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ def insert_extras(body)
body = NodeShared.people_grid(body, @current_user || nil) # <= to allow testing of insert_extras
body = NodeShared.graph_grid(body)
body = NodeShared.wikis_grid(body)
body = NodeShared.simple_data_grapher(body)
body
end

Expand Down
2 changes: 2 additions & 0 deletions app/helpers/csvfiles_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module CsvfilesHelper
end
17 changes: 17 additions & 0 deletions app/models/concerns/node_shared.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,23 @@ def self.graph_grid(body, _page = 1)
end
end

def self.simple_data_grapher(body, _page = 1)
body.gsub(/(?<![\>`])(\<p\>)?\[simple-data-grapher\:(\S+)\]/) do |_tagname|
ids = Regexp.last_match(2)
a = ActionController::Base.new
randomSeed = rand(1000).to_s
output = a.render_to_string(template: "grids/_simple-data-grapher",
layout: false,
locals: {
ids: ids,
randomSeed: randomSeed,
idName: 'sdg-graph-' + randomSeed,
type: "graph"
})
output
end
end

# rubular regex: http://rubular.com/r/hBEThNL4qd
def self.notes_grid(body, _page = 1)
body.gsub(/(?<![\>`])(\<p\>)?\[notes\:(\S+)\]/) do |_tagname|
Expand Down
3 changes: 3 additions & 0 deletions app/models/csvfile.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class Csvfile < ApplicationRecord
belongs_to :user, foreign_key: :uid
end
1 change: 1 addition & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ module Frequency

has_many :images, foreign_key: :uid
has_many :node, foreign_key: 'uid'
has_many :csvfiles, foreign_key: :uid
has_many :node_selections, foreign_key: :user_id
has_many :revision, foreign_key: 'uid'
has_many :user_tags, foreign_key: 'uid', dependent: :destroy
Expand Down
152 changes: 152 additions & 0 deletions app/views/csvfiles/new.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.4.1.js" integrity="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-3-typeahead/4.0.2/bootstrap3-typeahead.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/PapaParse/4.6.3/papaparse.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.3/Chart.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/plotly.js/1.33.1/plotly-basic.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.8.2/css/all.min.css">
<link href="https://gitcdn.github.io/bootstrap-toggle/2.2.2/css/bootstrap-toggle.min.css" rel="stylesheet">
<script src="https://gitcdn.github.io/bootstrap-toggle/2.2.2/js/bootstrap-toggle.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.3/FileSaver.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.14.3/xlsx.full.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.8.2/css/all.min.css">
<%= javascript_include_tag('/lib/simple-data-grapher/dist/PublicLab.Grapher.js')%>
<%= stylesheet_link_tag '/lib/simple-data-grapher/examples/upload_file.css'%>
<div id='first'></div>
<script>
var headerContainer = document.getElementsByClassName('body-container')[0];
SimpleDataGrapherObject = new SimpleDataGrapher('first');
var value = '<%= current_user %>';
<% if current_user %>
SimpleDataGrapherObject.view.createButtons('yes');
var saveButton = SimpleDataGrapherObject.view.elementId + '_save_CSV';
var prevFile = SimpleDataGrapherObject.view.elementId + '_prev_file';
var saveFlag = false;
$('#' + saveButton).click(function(){
saveFlag = true;
});
$('#' + SimpleDataGrapherObject.view.plotGraphId).click(function(){
if (saveFlag){
var arr = {};
arr['completeCsvMatrix'] = SimpleDataGrapherObject.view.csvParser.completeCsvMatrix;
arr['csvHeaders'] = SimpleDataGrapherObject.view.csvParser.csvHeaders;
arr['csvSampleData'] = SimpleDataGrapherObject.view.csvParser.csvSampleData;
arr['csvValidForYAxis'] = SimpleDataGrapherObject.view.csvParser.csvValidForYAxis;
arr['completeCsvMatrixTranspose'] = SimpleDataGrapherObject.view.csvParser.completeCsvMatrixTranspose;
let csvStringMatrix = SimpleDataGrapherObject.view.csvParser.completeCsvMatrixTranspose;
let csvStringForDownload = encodeURI('data:text/csv;charset=utf-8,' + csvStringMatrix.map(e => e.join(',')).join('\n'));
$.ajax({
url: '/graph/object',
type: 'post',
data: { object: JSON.stringify(arr),
uid: <%= current_user.id %>,
filetitle: SimpleDataGrapherObject.view.fileTitle,
filedescription: SimpleDataGrapherObject.view.fileDescription,
filestring: csvStringForDownload },
success: function(data){
let divAlert = document.createElement('div');
divAlert.classList.add('alert');
divAlert.classList.add('alert-success');
divAlert.innerHTML = 'File save successfully!';
headerContainer.appendChild(divAlert);
},
error: function(XMLHttpRequest, textStatus, errorThrown){
console.log(errorThrown);
let divAlert = document.createElement('div');
divAlert.classList.add('alert');
divAlert.classList.add('alert-danger');
divAlert.innerHTML = 'There was some error in saving the file.';
headerContainer.appendChild(divAlert);
}
});
}
});

$('#' + prevFile).click(function(){
$.ajax({
url: '/graph/prev_file',
type: 'get',
data: { uid: <%= current_user.id %> },
success: function(data){
displayPreviousFiles(data);
},
error: function(XMLHttpRequest, textStatus, errorThrown){
console.log(errorThrown);
let divAlert = document.createElement('div');
divAlert.classList.add('alert');
divAlert.classList.add('alert-danger');
divAlert.innerHTML = 'There was some error in retrieving the file.';
headerContainer.appendChild(divAlert);
}
});
});

function displayPreviousFiles(data){
var table=document.createElement('table');
for (let i = 0;i<data.length;i++){
let tr = document.createElement('tr');
let td = document.createElement('td');
let radio = document.createElement('input');
radio.type = 'radio';
radio.value = i;
radio.name = data[0]['csvfile']['uid'] + 'user_id';
td.appendChild(radio);
td.appendChild(document.createTextNode(data[i]['csvfile']['filetitle']));
tr.appendChild(td);
table.appendChild(tr);
}
let div = document.getElementById(SimpleDataGrapherObject.view.upload_button_container);
div.appendChild(table);
selectFile(data);
}
function selectFile(data){
$('#' + SimpleDataGrapherObject.view.uploadButtonId).click(function(){
let name = data[0]['csvfile']['uid'] + 'user_id';
let index = $('input[name=' + name + ']:checked').val();
let allfiles = JSON.parse(data[index]['csvfile']['filepath']);
SimpleDataGrapherObject.view.usingPreviouslyUploadedFile();
SimpleDataGrapherObject.view.csvParser.completeCsvMatrix = allfiles['completeCsvMatrix'];
SimpleDataGrapherObject.view.csvParser.csvHeaders = allfiles['csvHeaders'];
SimpleDataGrapherObject.view.csvParser.csvSampleData = allfiles['csvSampleData'];
SimpleDataGrapherObject.view.csvParser.csvValidForYAxis = allfiles['csvValidForYAxis'];
SimpleDataGrapherObject.view.csvParser.completeCsvMatrixTranspose = allfiles['completeCsvMatrixTranspose'];
SimpleDataGrapherObject.view.continueViewManipulation('prevfile');
});
}
$('#' + SimpleDataGrapherObject.view.elementId + '_publish').click(function(){
var arr = {};
arr['completeCsvMatrix'] = SimpleDataGrapherObject.view.csvParser.completeCsvMatrix;
arr['csvHeaders'] = SimpleDataGrapherObject.view.csvParser.csvHeaders;
arr['csvSampleData'] = SimpleDataGrapherObject.view.csvParser.csvSampleData;
arr['csvValidForYAxis'] = SimpleDataGrapherObject.view.csvParser.csvValidForYAxis;
arr['completeCsvMatrixTranspose'] = SimpleDataGrapherObject.view.csvParser.completeCsvMatrixTranspose;
let csvStringMatrix = SimpleDataGrapherObject.view.csvParser.completeCsvMatrixTranspose;
let csvStringForDownload = encodeURI('data:text/csv;charset=utf-8,' + csvStringMatrix.map(e => e.join(',')).join('\n'));
var dataObject = {};
dataObject['hash'] = SimpleDataGrapherObject.view.plotlyjsPlotter.dataHash;
dataObject['graphType'] = SimpleDataGrapherObject.view.plotlyjsPlotter.graphType;
dataObject['length'] = SimpleDataGrapherObject.view.plotlyjsPlotter.length;
$.ajax({
url: '/graph/note/graphobject',
type: 'post',
data: { object: JSON.stringify(arr),
uid: <%= current_user.id %>,
filetitle: SimpleDataGrapherObject.view.fileTitle,
filedescription: SimpleDataGrapherObject.view.fileDescription,
filestring: csvStringForDownload,
graphobject: JSON.stringify(dataObject) },
success: function(data){
window.location = '/post?body=%5Bsimple-data-grapher:i/' + data['uid'] + '/' + data['id'] + '%5D';
},
error: function(XMLHttpRequest, textStatus, errorThrown){
console.log(errorThrown);
}
});
});

<% end %>
setTimeout("$('.alert-success .alert-danger').fadeOut('slow')", 7000)
</script>

Loading

0 comments on commit 6b9d93b

Please sign in to comment.