d3.js Multi-Series Graph with JSON - python

I have parsed JSON from those models in the view to a JsonResponse and now I am trying to my multi-line plot working using d3.js.
The example code I am trying to use is here.
I am not sure how to go about changing the tsv call or if I should change my JSON format.
d3.tsv("data.tsv", function(error, data) {
if (error) throw error;
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "date"; }));
data.forEach(function(d) {
d.date = parseDate(d.date);
});
var cities = color.domain().map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {date: d.date, temperature: +d[name]};
})
};
});
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([
d3.min(cities, function(c) { return d3.min(c.values, function(v) { return v.temperature; }); }),
d3.max(cities, function(c) { return d3.max(c.values, function(v) { return v.temperature; }); })
]);
And here is how my JSON is formatted where the Site name is top level, and the `Metric is one level deep.
{ "Site1":
[{"da": 1.0, "date": 2015-09-01},
{"da": 2.0, "date": 2015-09-04}],
"Site2":
[{"da": 1.0, "date": 2015-09-01},
{"da": 2.0, "date": 2015-09-04}
{"da": 5.0, "date": 2015-09-04}]
}
How can I setup d3.js to work with these nested JSON objects versus the top level JSON in the example?

Here is the full working code fiddle; I have added comments in the code to help you understand the code.
Fiddle
Full code snippet:
var margin = {
top: 20,
right: 80,
bottom: 30,
left: 50
},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var parseDate = d3.time.format("%Y-%m-%d").parse;
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var color = d3.scale.category10();
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var line = d3.svg.line()
.interpolate("basis")
.x(function (d) {
return x(d.date);
})
.y(function (d) {
return y(d.da);
});
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
//your dataset
var myData = {
"Site1": [{
"da": 1.0,
"date": "2015-09-01"
}, {
"da": 2.0,
"date": "2015-09-04"
}],
"Site2": [{
"da": 1.0,
"date": "2015-09-01"
}, {
"da": 2.0,
"date": "2015-09-04"
}, {
"da": 5.0,
"date": "2015-09-04"
}]
};
//make fulldataset to get the extent of x axis and yaxis
var fullDataSet = []
for (var key in myData) {
fullDataSet = fullDataSet.concat.apply(fullDataSet, myData[key]);
}
fullDataSet.forEach(function (d) {
d.date = parseDate(d.date);
d.da = +d.da;
});
//get the xaxis extent i.e. min max
x.domain(d3.extent(fullDataSet, function (d) {
return d.date;
}));
//get the yaxis extent i.e. min max
y.domain(d3.extent(fullDataSet, function (d) {
return d.da;
}));
//make the x axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
//make the y axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("DA ");
//iterate through your nested data and make the line graph
for (var key in myData) {
makeLine(myData[key], key);
}
//This function will make the line chart
function makeLine(data, title) {
svg.append("path")
.datum(data)
.attr("class", "line")
.style("stroke", function (d) {
return color(title);
}).attr("d", line);
}

Related

Serialized Data Displaying Letter by Letter Django

I'm learning to work with JSON and so I'm running a simple example to create a list item in my template for each object in my django model. My output looks like this:
So I wanted each <li> to show just the actual value in Name. How can I amend my code to achieve that?
views.py
def Ajax(request):
if request.is_ajax():
exporter = serializers.serialize("json", Proforma.objects.all())
print(exporter)
data = json.dumps(exporter)
return HttpResponse(data, content_type='application/json')
$("#populate").click(function() {
$.ajax({
url: "/ajax/more",
success: function(data) {
for(i = 0; i < data.length; i++){
$('ul').append('<li>'+data[i]+'</li>');
}
}
});
});
EDIT:
Here is the output from the console:
(index):739 [{"model": "Poseidon.proforma", "pk": 24, "fields": {"Name": "greg", "Shipment": 4, "Exporter": "greg", "QuoteNo": "jiojo", "Date": "ijoi", "Consignee": 10, "MethodOfDispatch": "ujhiuh", "TypeOfShipment": "iuhiu", "PortOfLoading": "huyg", "PortOfDischarge": "uioj", "Terms": "iugh", "ProductCode": "utyg", "DescriptionOfGoods": "iuhi", "UnitQty": "ug", "UnitType": "t", "Price": "iuh", "Amount": "iy", "BankDetails": "guyt", "AdditionalInfo": "gy", "InvoiceTotal": "tf", "Place": "uyg", "SignatoryCompanyBuyer": "uyf", "SignatoryCompany": "utfy", "NameSignerBuyer": "guyg", "NameSigner": "uy", "SignatureBuyer": "fy", "Signature": "trf", "CreatedBy": "uyg"}}]
the problem is the ajax because you cant print a whole object in the li tag:
try this(would print "Poseidon.proforma" on the li tag):
$("#populate").click(function() {
$.ajax({
url: "/ajax/more",
success: function(data) {
var data = JSON.parse(data); // parse the string response to JSON
for(i = 0; i < data.length; i++){
$('ul').append('<li>'+data[i]["model"]+'</li>');
}
}
});
});
if you want a to understand the problem i think w3schools may help

react-table not rendering server-side data in table (with manual pagination, filtering & sorting)

I'm having trouble getting data from the backend (Python API) to show in react-table manually. I've read the documentation and I'm trying to use the example here: https://react-table.js.org/#/story/server-side-data
I'm only seeing data in one column and only for 6 records which is really weird. It's probably the way I'm mixing in async/await syntax with the example code which uses a promise. I was able to create a simple react-table fetching data with the same async/await syntax, but when I added the server-side data code from the example (the requestData function) it wouldn't work.
I've spent days on this and looking all over Stackoverflow and the internet. I'm a newbie so please go easy on me. Here's what I have:
import React from 'react'
import { render } from 'react-dom'
import ReactTable from 'react-table'
import api from 'src/api'
import { orderBy } from 'lodash'
// importing react-table css would not work so I added it using cdn link
const requestData = async (pageSize, page, sorted, filtered) => {
// api is a wrapper for axios.create()
const rawData = await api.admin.exercise.feed()
return new Promise((resolve, reject) => {
let filteredData = rawData;
if (filtered.length) {
filteredData = filtered.reduce((filteredSoFar, nextFilter) => {
return filteredSoFar.filter(row => {
return (row[nextFilter.id] + "").includes(nextFilter.value);
});
}, filteredData);
}
const sortedData = orderBy(
filteredData,
sorted.map(sort => {
return row => {
if (row[sort.id] === null || row[sort.id] === undefined) {
return -Infinity;
}
return typeof row[sort.id] === "string"
? row[sort.id].toLowerCase()
: row[sort.id];
};
}),
sorted.map(d => (d.desc ? "desc" : "asc"))
);
const res = {
rows: sortedData.slice(pageSize * page, pageSize * page + pageSize),
pages: Math.ceil(filteredData.length / pageSize)
};
resolve(res);
});
};
export class ExerciseList extends React.Component {
constructor() {
super();
this.state = {
data: [],
pages: null,
loading: true
};
this.fetchData = this.fetchData.bind(this);
}
setLoading(loading) {
this.setState({ loading })
}
fetchData(state, instance) {
this.setLoading(true);
requestData(
state.pageSize,
state.page,
state.sorted,
state.filtered
).then(res => {
this.setState({
data: res.rows,
pages: res.pages,
loading: false
});
});
}
render() {
const { data, pages, loading } = this.state;
return (
<div>
<ReactTable
columns={[
{
Header: "Name",
accessor: "name"
},
{
Header: "Movement",
accessor: "movement"
},
{
Header: "Equipment",
accessor: "equipments"
},
{
Header: "Channel",
accessor: "channel"
},
{
Header: "Level",
accessor: "skill_level"
},
{
Header: "Duration",
accessor: "duration",
filterable: false
},
{
Header: "Injuries",
accessor: "injuries"
},
{
Header: "Is Substitute",
accessor: "has_video",
Cell: ({ value }) => (value? 'Yes': 'No'),
filterable: false
}
]}
data={data}
pages={pages}
loading={loading}
onFetchData={this.fetchData}
manual
filterable
defaultPageSize={10}
className="-striped -highlight"
/>
</div>
);
}
}
render(<ExerciseList />, document.getElementById('datatable'));
Please refer the link for server-side sorting, pagination and manual filtering within the grid
// Component related to methods for sorting, pagination server side and filtering manual filtering with in the grid
import React from 'react'
import 'react-table/react-table.css'
import ReactTable from 'react-table'
import autoBind from 'react-autobind'
import {filterCaseInsensitive} from '../../helper/commonMethods'
class ServerSideAtomGrid extends React.Component {
super(props)
const userDetails = getUserDetails()
this.state = {
page: 0,
pageSizeOptions: [500, 1000, 2000, 4000],
pageSize: 500,
totalRecords: 0,
nextCursor: '*',
cursorList: [{
page: 0,
cursor: '*'
}],
sortFields: {
field: 'created_dtm',
sort: 'desc'
},
columnData,
}
autoBind(this)
}
handlePageChange (page) {
const pageNumber = (page)
const cursorList = this.state.cursorList
let cusrsorMark = ''
_.each(cursorList, (list) => {
if (list.page === pageNumber) {
cusrsorMark = list.cursor
}
})
this.setState({
nextCursor: cusrsorMark,
page: pageNumber
}, () => this.searchData(cusrsorMark, pageNumber))
}
handleSizePerPageChange (pageSize) {
this.resetData(pageSize)
this.searchData('*', 0)
}
handleSorting = (state, instance) => {
const sorted = state
let field = 'created_dtm'
let sort = 'desc'
sorted && sorted.length > 0 && sorted.map(fld => {
field = fld.id
sort = fld.desc ? 'desc' : 'asc'
})
this.setState({
sortFields: {
field,
sort
}
}, () => this.searchData('*', 0))
}
////
searchData('*', 0) {
//Axios call you cna have
}
filterCaseInsensitive (filter, row) {
const id = filter.pivotId || filter.id
return row[id] ? row[id].toString().toLowerCase().includes(filter.value.toLowerCase()) : true
}
render () {
const {
classes, gridData, gridColumns, defaultFilter, totalRecords,
gridPageSizeOptions, gridPage, gridPages, gridPageSize, gridLoading
} = this.props
return (
<div>
<ReactTable
columns={gridColumns}
data={gridData}
onSortedChange={(state, instance) => {
this.handleSorting(state, instance)
}}
filterable={defaultFilter}
defaultFilterMethod={filterCaseInsensitive}
noDataText="Ops No result found!"
defaultPageSize={this.state.pageSize}
className="-highlight"
style={{height: `${totalRecords < 25 ? '' : `800px`}`, width: '100%', textAlign: 'center'}}
pageText={`Total Count : ${totalRecords.toLocaleString()} Page: `}
loading={gridLoading}
page={this.state.page}
pages={this.state.pages}
showPaginationTop
pageSize={this.state.pageSize}
pageSizeOptions={gthis.state.pageSizeOptions}
minRows={25}
manual
onPageChange={page => {
this.setState({page})
this.handlePageChange(page)
}}
onPageSizeChange={(pageSize, page) => {
this.setState({
page,
pageSize
})
this.props.handleSizePerPageChange(pageSize)
}}
showPageJump={false}
/>
</div>
)
}
}
export default (ServerSideAtomGrid)
My Fiddle: https://jsfiddle.net/gowthamguruju/o9ybxqaj/8/

Best way to refresh graph without page refresh (Python Django, ajax)

A bit of a general question - I am looking for ways to refresh a graph on a Django page based on user choices. The page has a graph, a few drop boxes where you can select parameters and a refresh button. Currently, I can capture the selections via ajax to my Django view and generate new data from database for the graph. I now need to feed that newly-generated data back into the graph and refresh it without a page refresh. Could anyone recommend the best methods of doing this?
Use JQuery to refresh graph without refreshing page.
I am using chart.js to create graph. first create a graph and on change event get updated data using Ajax URL call and assign values to chart data sets.
/** Graph Start Here */
window.chart = null;
$(document).on('change', '.graph-year-earning', function () {
var year = $(this).val();
$.get($('.graph-ajaxload-context').data('href'), { 'year': year, 'number': Math.floor(Math.random() * (1000000 - 10 + 1) + 10) }, function (response) {
window.chart.data.labels = response.labels;
window.chart.data.datasets[0].soldProductLabel = response.product_sold_label;
window.chart.data.datasets[0].totalCommissionLabel = response.monthly_commission_label;
window.chart.data.datasets[0].dataLabel = response.your_share_label;
if (response.total_commission == 0) {
window.chart.options.scales.yAxes[0].ticks.suggestedMin = 0;
window.chart.options.scales.yAxes[0].ticks.suggestedMax = 140000;
} else {
window.chart.options.scales.yAxes[0].ticks.suggestedMin = '';
window.chart.options.scales.yAxes[0].ticks.suggestedMax = '';
}
$.each(response.data, function (index, value) {
window.chart.data.datasets[0].soldProduct[index] = value[2];
window.chart.data.datasets[0].data[index] = Math.round(value[0]);
});
window.chart.update();
$(".txt-total-commission-by-year").html(response.total_commission)
$('.graph-ajaxload-context .inline-loader').hide();
});
});
if ($('.graph-ajaxload-context').length > 0) {
showLoader()
$('.graph-year-earning').trigger('change');
var ctx = $('#userEarningGraph');
window.chart = new Chart(ctx, {
type: 'bar',
data: {
labels: [],
datasets: [{
soldProductLabel: '',
soldProduct: [],
dataLabel: '',
data: [],
backgroundColor: '#ADAEB1',
hoverBackgroundColor: '#48C6B9'
}]
},
options: {
legend: {
display: false
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
maxTicksLimit: 8,
userCallback: function (value, index, values) {
value = value.toString();
value = value.split(/(?=(?:...)*$)/);
value = value.join(',');
var currency_code = ' ₩'
if ($('.graph-ajaxload-context').data('currency-code') && $('.graph-ajaxload-context').data('currency-code') != 'None') {
currency_code = $('.graph-ajaxload-context').data('currency-code')
}
return value + ' ' + currency_code;
}
},
}]
},
tooltips: {
mode: 'label',
callbacks: {
label: function (tooltipItem, data) {
var soldProduct = data.datasets[tooltipItem.datasetIndex].soldProduct[tooltipItem.index];
var soldProductLabel = data.datasets[tooltipItem.datasetIndex].soldProductLabel;
var dataPro = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
var dataLabel = data.datasets[tooltipItem.datasetIndex].dataLabel;
return [soldProductLabel + ':' + soldProduct, dataLabel + ':' + dataPro + ' ₩',];
}
}
}
}
});
}
$(document).on('click', '.showgraph', function (e) {
$('.graph-year-earning').trigger('change');
});
/** Graph End Here */

error 405 get method not allowed

Angularjs code
var app = angular.module('myApp', []);
app.factory('httpSend', ['$http', '$q', function($http, $q) {
var app = {};
app.sendToServer = function(data) {
$http({
method: "POST",
url: '/report',
data: data,
headers: {
'Content-type': 'application/x-www-form.urlencoded;'
}
}).then(function(response) {
debugger
var result = data;
});
}
app.getfromServer = function() {
var def = $q.defer();
$http.get('/report').then(function(data) {
console.log(data);
def.resolve(data);
}),
function(error) {
def.reject("Failed to get albums");
};
return def.promise;
}
return app;
}]);
app.controller('myCtrl', ['$scope', '$http', 'httpSend', '$filter', function($scope, $http, httpSend, $filter) {
$scope.names = ["ankit patidar", "adhishi ahari", "kritin joshi", "kautilya bharadwaj", "punita ojha", "manvi agarwal", "apeksha purohit", "shipra jain", "mansi nangawat", "praveen soni"];
$scope.data = [];
$scope.names.forEach(function(name) {
$scope.data.push({
name: name,
checkin: "",
checkout: ""
})
});
$scope.login = [];
$scope.check = function(name, doing) {
debugger
name[doing] = new Date();
name[doing] = $filter('date')(name[doing], 'dd-MM-yyyy hh:mm:ss');
$scope.login.push(angular.copy(name));
if (doing == "checkout") {
var q = JSON.stringify($scope.login);
httpSend.sendToServer(q);
}
}
$scope.getData = function() {
httpSend.getfromServer();
}
}]);
`
Python Code
def get(self):
logging.info('get is triggered')
obj = CheckIn.query().fetch()
emp_obj = []
for x in obj:
logging.info('I am inside for loop ')
emp_obj.append({
'name': x.name,
'Check_in': x.inDate,
'check_out': x.outDate
})
logging.info('I am inside emp_obj')
self.response.write(json.dumps(emp_obj))
i need to fetch all the data stored on ndb datastore on front end view thats why i m using http get method but error is showed method not allowed. can u please help e despite using query fetch and showing its response on python ad triggering get method, why error is coming, is there a mistake in control flow or something is missing in my get method, as for now i m able to post nd store data
Change your factory to the following. Don't use the same variable app that you are using for initialising your module for your controller logic.
app.factory('httpSend',['$http', '$q',function($http, $q){
return {
'sendToServer': function(data) {
var def = $q.defer();
$http({
method: "POST",
url: '/report',
data: data,
headers: {
'Content-Type': 'application/json'
}
}).then(function(response) {
debugger
var result = response.data;
def.resolve(result );
});
return def.promise;
},
'getfromServer': function() {
var def = $q.defer();
$http.get('/report').then(function(data) {
console.log(data);
def.resolve(data);
}),
function(error) {
def.reject("Failed to get albums");
};
return def.promise;
}
}
}]);

How to draw a scatterplot with superimposed pics?

I'm not a web programmer, but forced to deliver some kind of presentation. The task is as follows: I have a .csv with 2D points in each row, and these points have one-to-one mapping to some pictures by URL or integer index.
I need to draw a scatter plot these point in browser so that I plot associated pictures instead of plain points.
Very complex example is shown here just to get the idea of what I mean:
http://www.nytimes.com/interactive/2013/02/20/movies/among-the-oscar-contenders-a-host-of-connections.html
Again, all I want is to draw a scatterplot, in which there are rectangular pictures instead of plain points. Interactive zooming is preferred.
My candidates so far are D3 and Bokeh ( because I'm primarily Pythoniac man )
However, the better would be to take some existing solution as a template and then hack it to make suitable.
UPD: If it seems that I will hardly find something like that, it's okay to draw a plain points, but being able to hover over them with a mouse and displaying associated pictures for a point under mouse.
Again, thanks in advance!
I used D3
Here is an example of scatter chart with images:
http://plnkr.co/edit/A60Pv8I7tqSVGKU64bgr?p=preview
src code:
// Code goes here
var h = 500;
var w = 750;
var padding = 50;
//set your images and data here
var monthlySales = [{
'stock': 'GOOG',
'count': 500,
'img': "https://encrypted-tbn3.gstatic.com/images?q=tbn:ANd9GcTccGK4ZWQcI3WB--hytI1DFaeZ8ii-6euDWrm-baUtAxR7w9OrWg"
}, {
'stock': 'MSFT',
'count': 250,
'img': "http://tr1.cbsistatic.com/fly/171-fly/bundles/techrepubliccore/images/icons/standard/icon-user-default.png"
}, {
'stock': 'FB',
'count': 50,
'img': "https://cdn1.iconfinder.com/data/icons/industry-2/96/Mine-512.png"
}, {
'stock': 'AAPL',
'count': 100,
'img': "https://cdn1.iconfinder.com/data/icons/industry-2/96/Mine-512.png"
}, {
'stock': 'EBAY',
'count': 5,
'img': "https://cdn1.iconfinder.com/data/icons/industry-2/96/Mine-512.png"
}, {
'stock': 'BABA',
'count': 37,
'img': "https://cdn1.iconfinder.com/data/icons/industry-2/96/Mine-512.png"
}];
var xScale = d3.scale.linear().domain([65, 450]).range([0, w]).nice();
var yScale = d3.scale.linear().domain([0, d3.max(monthlySales, function(d) {
return d.count;
})]).range([h, 0 + padding]).nice();
var radiusScale = d3.scale.linear().domain([0, d3.max(monthlySales, function(d) {
return d.count;
})]).range([10, 100]).nice();
var opacityScale = d3.scale.linear().domain([0, d3.max(monthlySales, function(d) {
return d.count;
})]).range([1, 0.1]).nice();
function ordinalValue(item) {
var strLen = item.length;
var total = 0;
for (var i = 0; i < strLen; i++) {
total += item.charCodeAt(i);
}
console.log(total);
return total;
}
var svg = d3.select('body').append('svg').attr({
width: w,
height: h,
style: "outline: thin solid blue"
});
var dots = svg.selectAll('g')
.data(monthlySales)
.enter()
.append("g");
dots.append('circle')
.attr({
cx: function(d) {
var ordValue = ordinalValue(d.stock);
return xScale(ordValue);
},
cy: function(d) {
return yScale(d.count);
},
r: function(d) {
return radiusScale(d.count);
},
fill: function(d) {
return '#' + Math.random().toString(16).substr(-6);
}
}).style({
"fill-opacity": function(d) {
return opacityScale(d.count);
},
"stroke": function(d) {
return '#' + Math.random().toString(16).substr(-6);
}
});
//adding an image to the group
dots.append("svg:image")
.attr("xlink:href",function(d) {return d.img})
.attr("height", "20")
.attr("width", "20")
.attr({
x: function(d) {
var ordValue = ordinalValue(d.stock);
return xScale(ordValue)-10;
},
y: function(d) {
return yScale(d.count)-10;
},
});

Categories