I have implemented chart JS 2.5 into my django application version 1.11 but I am able to see only the canvas but not any bar chart, besides,the web browser console does not display any error, so this is becoming quite difficult for me to trace the mistake.
statistics.html and views.py are my main files where I am currently trying to debug this problem. The urls.py and header.html files were not touched recently and I put them at the end.
statistics.html file:
Graph implementation and retrieval of the JSON object
{% extends "personal_website/header.html"%}
<script>
{% block jquery %}
var endpoint = '/statistics/data'
var defaultData = []
var labels = []
$.ajax({
method: "GET",
url: endpoint,
dataType: 'json',
success: function(data){
labels = data.labels
defaultData = data.default
var ctx = document.getElementById("myChart")
var myChart = new Chart(ctx, {
type:'bar',
data: {
labels: labels,
datasets : [{
label: '# of votes',
data: defaultData,
}]
}
})
},
error: function(error_data){
console.log("error on data")
console.log(error_data)
}
})
{% endblock %}
</script>
{% block content %}
<div class ='row'>
<div class="col-sm-12" url-endpoint='{% url "get_data" %}'>
<h1>Statistics for week 21</h1>
<canvas id="myChart" width="400" height="400"></canvas>
</div>
</div>
{% endblock content %}
Views.py
get_data() was used to test if I could receive the JSON object through the web browser console.
from django.shortcuts import render
from django.views.generic import View
from django.http import JsonResponse
from django.template.loader import render_to_string
from rest_framework.views import APIView
from rest_framework.response import Response
def index(request):
return render(request, 'personal_website/home.html')
def statistics(request):
return render(request, 'personal_website/statistics.html',{})
def get_data(request, *args, **kwargs):
response_data = {}
response_data["customers"] = 100
response_data["sales"] = 40 *12
return JsonResponse(response_data)
class ChartData(APIView):
def get(self,request,format=None):
labels = ["Red","Blue","Yellow","Green","Purple","Orange"]
default_items = [22,35,12,8,10,9]
data = {
"labels": labels,
"default": default_items,
}
return Response(data)
urls.py
from django.conf.urls import url, include
from . import views
from .views import ChartData, get_data
urlpatterns = [
url(r'^$', views.index, name='index'), # home
url(r'^statistics/$', views.statistics, name='statistics'),
url(r'^statistics/data$', get_data, name='get_data'),
url(r'^statistics/chart-data$', ChartData.as_view()), # API View working) ]
header.html
<head>
<title>Statistics</title>
<meta charset="utf-8" />
{% load staticfiles %}
<meta name="viewport" content="width=device=width, initial-scale=1.0">
</head>
<body class="body" style="background-color:#f6f6f6">
<div class="container-fluid" style="min-height:95%; ">
<div class="row">
<div class="col-sm-10">
<h3>Statistics</h3>
</div>
</div><hr>
<div class="well bs-sidebar" id="sidebar">
<ul class="nav nav-pills nav-stacked">
<li><a href='/'>Home</a></li>
<li><a href='/statistics/'>Statistics</a></li>
</ul>
</div>
</div>
<footer>
<!-- no content for the moment-->
</footer>
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js">
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js">
</script>
</html>
Lastly, the only part that I see that changes is is the label: '# of votes' from the dataset.
What is missing in the code, so I can see the displayed bar charts?
Any help, suggestion, improvement, question is welcome.
Related
I'm trying to display pie and bar chart using Flask API on html page using chart.js. I am able to display pie chart but bar chart is getting below error.
"cannot read property of undefined (reading 'offsetWidth')" under "/nutrition_analysis" route.
Please find below Python main.py code,
# importing the necessary dependencies
from flask import Flask, render_template, request,jsonify
from flask_cors import CORS, cross_origin
import pandas as pd
from flask import send_file
#import matplotlib.pyplot as plt
#%matplotlib inline
import logging
from datetime import datetime
app = Flask(__name__) # initializing a flask app
#app.route('/', methods=['GET', 'POST']) # route to display the home page
#cross_origin()
def homePage():
return render_template("home.html")
#app.route('/form_fill',methods=['GET','POST']) # route to display the home page
#cross_origin()
def form_fill():
return render_template("form_fill.html")
#app.route('/download_file',methods=['GET','POST']) # route to display the home page
#cross_origin()
def download_file():
path = 'Daily Nutrition Requirement.xlsx'
return send_file(path, as_attachment=True)
#app.route('/nutrition_analysis',methods=['POST','GET']) # route to show the predictions in a web UI
#cross_origin()
def nutrition_analysis():
if request.method == 'POST':
try:
# reading the inputs given by the user
name = (request.form['name'])
age = float(request.form['age'])
weight = float(request.form['weight'])
reference = (request.form['reference'])
phone = float(request.form['phone'])
emailid = (request.form['emailid'])
file = request.form['customer_data']
customer_data = pd.read_excel(file)
RDA = pd.read_excel('Recommended_Nutrition.xlsx')
df = pd.concat([RDA, customer_data], ignore_index=True)
df_Carbs = df[df["Nutrients"] == "Carbohydrate"]
df_Fat = df[df["Nutrients"] == "Fats"]
df_Prot = df[df["Nutrients"] == "Proteins"]
df_Fbr = df[df["Nutrients"] == "Fiber"]
df_Macros = pd.concat([df_Carbs, df_Fat, df_Prot, df_Fbr])
df_Macros_Exp = df_Macros[df_Macros["Category"] == "Exp"]
# df_Macros_Obs = df_Macros[df_Macros["Category"] == "Obs"]
# plt.pie(df_Macros_Exp["Value"], labels=df_Macros_Exp["Nutrients"], autopct='%1.1f%%')
# plt.title("Expected Macros as per RDA", fontweight='bold')
# plt.savefig('chart.png')
values = df_Macros_Exp["Value"].tolist()
labels = df_Macros_Exp["Nutrients"].tolist()
colors = ["#F7464A", "#46BFBD", "#FDB45C", "#FEDCBA"]
# Bar Chart
df_stack = pd.merge(RDA,customer_data[['Nutrients','Value']],on='Nutrients', how='left')
df_stack1=df_stack[['Nutrients','Value_x','Value_y']].copy()
df_stack1["RDA"]=100
df_stack1["Intake"]=((df_stack1["Value_y"] - df_stack1["Value_x"])/df_stack1["Value_x"])*100
df_stack1.drop(["Value_x", "Value_y"], axis = 1, inplace = True)
def color(x):
if x < 0 or x > 50 :
return '#F7464A'
else:
return '#46BFBD'
df_stack1["Color"]=df_stack1["Intake"].apply(color)
values_bar = df_stack1["Intake"].tolist()
labels_bar = df_stack1["Nutrients"].tolist()
colors_bar = df_stack1["Color"].tolist()
#dt=datetime.now()
# showing the prediction results in a UI
return render_template('nutrition_analysis.html',s1=name,s2=age,s3=weight,s4=reference,s5=phone,s6=emailid,set=zip(values, labels, colors),set2=zip(values_bar,labels_bar,colors_bar))
except Exception as e:
print('The Exception message is: ',e)
logging.debug(e)
return 'something is wrong'
# return render_template('results.html')
else:
return render_template('home.html')
if __name__ == "__main__":
logging.basicConfig(filename='Nutrition_Analysis.log', level=logging.DEBUG)
app.run(host='127.0.0.1', port=8001, debug=True)
#app.run(debug=True) # running the app
Please find html page which need to be rendered below,
<head>
<meta charset="utf-8" />
<title>Macro Analysis</title>
<script src='https://cdnjs.cloudflare.com/ajax/libs/Chart.js/1.0.2/Chart.min.js'></script>
</head>
<body>
<div class="item active" style="display: flex; height: 100px;">
<div style=" width: 30%;">
<h1><p>Liv365 Nutrition Analysis Report :</p></h1>
<br>name : {{s1}}</br>
<br>age : {{s2}}</br>
<br>weight : {{s3}}</br>
<br>reference : {{s4}}</br>
<br>phone : {{s5}}</br>
<br>emailid : {{s6}}</br>
</div>
<div style=" width: 30%;">
<h1>Macro Analysis</h1>
<canvas id="chart" width="400" height="200"></canvas>
<script>
var pieData = [
{% for values, labels, colors in set %}
{
value: {{values}},
label: "{{labels}}",
color : "{{colors}}"
},
{% endfor %}
];
// draw pie chart
new Chart(document.getElementById("chart").getContext("2d")).Pie(pieData);
</script>
</div>
<div style=" width: 40%;">
<h1>Micro Analysis</h1>
<canvas id="bar" width="400" height="200"></canvas>
<script>
var barData = [
{% for values_bar, labels_bar, colors_bar in set2 %}
{
value: {{values_bar}},
label: "{{labels_bar}}",
color : "{{colors_bar}}"
},
{% endfor %}
];
new Chart(document.getElementById("bar"), {
type: 'bar',
data: {
labels: barData["label"],
datasets: [
{
label: "Population (millions)",
backgroundColor: barData["color"],
data: barData["value"]
}
]
},
options: {
legend: { display: false },
title: {
display: true,
text: 'Total Confirmed Cases of COVID in May'
}
}
});
</script>
</div>
</div>
</body>
</html>
Please help me resolve this issue.
Thanks in advance!!!
Regards,
Rohan
I am using https://github.com/fengyuanchen/cropper/blob/master/README.md as the cropper function. However, I want to submit field objects (in this case the title) and the cropped image. But I got an error on the admin. And of course, I have done the makemigrations and migrate before running the server
Error Picture
admin.py
from django.contrib import admin
from .models import Image
# Register your models here.
class ImageAdmin(admin.ModelAdmin):
pass
admin.site.register(Image, ImageAdmin)
models.py
from django.db import models
# Create your models here.
class Image(models.Model):
title = models.CharField(max_length=10)
image = models.ImageField(upload_to='images')
def __str__(self):
return str(self.pk)
forms.py
from django import forms
from .models import Image
class ImageForm(forms.Form):
image = forms.ImageField()
title = forms.CharField(
max_length=10,
widget=forms.TextInput(
attrs={
"class": "form-control",
"placeholder": "Title",
},
),
required=True
)
views.py
from django.shortcuts import render, redirect
from .models import Image
from .forms import ImageForm
from django.http import JsonResponse
from django.http import HttpResponseRedirect
def main_view(request):
form = ImageForm()
if request.method == "POST":
form = ImageForm(request.POST, request.FILES)
if form.is_valid():
addimage = Image(
title=form.cleaned_data['title'],
image = form.cleaned_data['image'],
)
addimage.save()
else:
form = ImageForm()
context = {'form': form}
return render(request, 'photo_list.html', context)
photo_list.html
{% extends "base.html" %}
{% block javascript %}
<script>
console.log("Hello");
const imageBox = document.getElementById("image-box");
const confirmButton = document.getElementById("confirm-button")
const input = document.getElementById("id_image");
const csrf = document.getElementsByName("csrfmiddlewaretoken")
const imageForm = document.getElementById("image-form")
input.addEventListener("change", () => {
console.log("change")
const img_data = input.files[0]
const url = URL.createObjectURL(img_data)
imageBox.innerHTML = `<img src="${url}" id="image" width="500px">`
var $image = $('#image');
$image.cropper({
aspectRatio: 16 / 9,
crop: function (event) {
console.log(event.detail.x);
console.log(event.detail.y);
console.log(event.detail.width);
console.log(event.detail.height);
console.log(event.detail.rotate);
console.log(event.detail.scaleX);
console.log(event.detail.scaleY);
}
});
// Get the Cropper.js instance after initialized
var cropper = $image.data('cropper');
confirmButton.addEventListener('click', () => {
cropper.getCroppedCanvas().toBlob((blob) => {
const fd = new FormData()
fd.append('csrfmiddlewaretoken', csrf[0].value)
fd.append('image', blob, 'my-image.png')
console.log("append pass")
$.ajax({
type: "POST",
url: imageForm.action,
enctype: 'multipart/form-data',
data: fd,
success: function (response) {
console.log(response)
},
error: function (error) {
console.log(error)
},
cache: false,
contentType: false,
processData: false,
})
})
})
});
</script>
{% endblock %}
{% block page_content %}
<form action="/cropimage/" id="image-form" method="POST">
{% csrf_token %}
{{form}}
{% comment %} <button class="btn" id="confirm-button"> confirm </button> {% endcomment %}
<input class="btn btn-lg btn-primary btn-block" type="submit" value="Submit" id="confirm-button">
</form>
<div id="image-box" class="mb-3"> </div>
{% endblock %}
I was following this tutorial https://www.youtube.com/watch?v=oWd7SAuCIRM
Basically, I am making an album of images recorded with title, but this time with cropperjs. Any solutions or suggestions would be appreciated :).
Ahh silly me, after a week of finding solutions, I finally realize that I did not put and after deleting some of the database cache.
fd.append('title', $("input[name='title']").val())
on the getCroppedCanvas()
For those who had the same problem, please..
Ref :
How to append more data in FormData for django?
OperationalError, no such column. Django
https://developer.mozilla.org/en-US/docs/Web/API/FormData/append
I have a form that when it is posted the content of console.html gets changed. for refreshing the page I used the following code but this does not refresh console.html
javascript
function autorefresh() {
// auto refresh page after 1 second
setInterval('refreshPage()', 1000);
}
function refreshPage() {
var container = document.getElementById("console");
container.innerHTML= '<object type="text/html" data="../../templates/snippets/console.html" ></object>';
//this line is to watch the result in console , you can remove it later
console.log("Refreshed");
}
index.html
<script>autorefresh()</script>
<div id="console" >
{% include 'snippets/console.html' %}
</div>
view.py
def index(request):
if request.method == "GET":
return render(request, 'index.html')
if request.method == "POST": # If the form has been submitted...
form=InputForm(request)
form.do_function()
return render(request, 'index.html')
I rewrote html with the help of jquery:
<script type="text/javascript" src="{% static "js/jquery.js" %}"></script>
<script>
function autorefresh() {
// auto refresh page after 1 second
setInterval('refreshPage()', 1000);
}
function refreshPage() {
$.ajax({
url: '{% url 'console' %}',
success: function(data) {
$('#console').html(data);
}
});
}
</script>
.
.
.
<script>autorefresh()</script>
<div id="console" ></div>
view.py
def console(request):
data=
return render(request, 'snippets/console.html',{"data": data})
console.html
{% for line in data %}
{{ line }}
{% endfor %}
and finally add console to urls.
urls.py
urlpatterns = [
path('', views.index, name='index'),
path('console', views.console, name='console'),
]
I hope you don't spend a day finding the solution :))
I have a problem displaying data into a mixed bar and line chart from an API designed using the Django Rest Framework. Here is the model for the readings from the pressure and flowrate sensors
models.py
from django.db import models
# Create your models here.
class ReadingQuerySet(models.QuerySet):
pass
class ReadingManager(models.Manager):
def get_queryset(self):
return ReadingQuerySet(self.model, using=self._db)
class Reading(models.Model):
date = models.DateField(auto_now=True)
pressure =models.IntegerField(default=0)
flowrate =models.IntegerField(default=0)
timestamp =models.TimeField(auto_now_add=True)
objects = ReadingManager()
def __str__(self):
return str(self.timestamp) + ' ' + 'Pressure: ' + str(self.pressure) + ' ' + 'Flowrate: ' + str(self.flowrate)
The code for the serializer is here.
serializers.py
from rest_framework import serializers
from app.models import Reading
class ReadingSerializer(serializers.ModelSerializer):
class Meta:
model = Reading
fields = ['id','date','timestamp','pressure','flowrate']
the serializer is in an api folder i placed within a django app. the code for the APIview is below.
views.py
from rest_framework import generics, mixins
from rest_framework.response import Response
from .serializers import ReadingSerializer
from app.models import Reading
class ReadingChartAPIView(mixins.CreateModelMixin, generics.ListAPIView):
permission_classes = []
authentication_classes = []
serializer_class = ReadingSerializer
def get(self, request, *args, **kwargs):
qs = Reading.objects.all()
data = {
'timestamp':qs.values('timestamp'),
'pressure':qs.values('pressure'),
'flowrate':qs.values('flowrate'),
'update':qs.values('pressure', 'flowrate').last()
}
return Response(data)
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
and this is the data i receive from the APIview
{"timestamp":[{"timestamp":"12:44:11.487901"},{"timestamp":"14:12:58.410520"},{"timestamp":"01:56:56.485449"},{"timestamp":"01:57:14.184429"},{"timestamp":"01:57:34.366559"},{"timestamp":"13:12:43.469454"}],"pressure":[{"pressure":45},{"pressure":35},{"pressure":79},{"pressure":52},{"pressure":89},{"pressure":27}],"flowrate":[{"flowrate":56},{"flowrate":67},{"flowrate":83},{"flowrate":14},{"flowrate":74},{"flowrate":46}],"update":{"pressure":27,"flowrate":46}}
The issue is in my html file when i am extracting this data. Here is my HTML.I am stuck and open to any solutions. i am trying to push the data labels for to datasets every after 5 seconds starting from the first one.
{% extends "layouts/base.html" %}
{%load static %}
{% block title %} Dashboard {% endblock %}
<!-- Specific Page CSS goes HERE -->
{% block stylesheets %}{% endblock stylesheets %}
{% block content %}
{% block jquery %}
<script type="text/javascript">
var counter = 0
var limit = 6
var chart = $('#myChart')
var endpoint = '/api/chart'
var pressures = []
var flowrates = []
var timestamps = []
var pressure_new = []
var flowrate_new = []
$.ajax({
method: 'GET',
url: endpoint,
success: function(data){
console.log(data)
}
})
var getData =
$.ajax({
method: 'GET',
url: endpoint,
success: function(data){
timestamps = data.timestamp.map(b => b.timestamp);
pressures = data.pressure.map(a => a.pressure);
flowrates = data.flowrate.map(c => c.flowrate);
myChart.data.labels.concat(timestamps[counter]);
myChart.data.datasets[0].data.concat(pressures[counter]);
myChart.data.datasets[1].data.concat(flowrates[counter]);
counter++;
myChart.update();
}
});
setInterval(getData, 3000)
</script>
{% endblock %}
<div class="container-fluid">
<div class="page-header row no-gutters py-4">
<div class="col-12 col-sm-4 text-center text-sm-left mb-0">
<span class="text-uppercase page-subtitle">Dashboard</span>
<h3 class="page-title">Overview</h3>
</div>
</div>
<div class="row">
<div class="col-lg-8 col-md-12 col-sm-12 mb-4">
<div class="card" width = '18rem' height = '10rem'>
<div class="card-header border-bottom">
<h5 class="card-title">Pressure and Flowrate</h5>
<h6 class="card-subtitle mb-1 text-muted">Real-time Readings of Pressure and Flowrate</h6>
</div>
<div class="card-body">
<canvas id="myChart"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.js"></script>
<script>
function setChart(){
var ctx = document.getElementById('myChart');
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: labels,
datasets: [{
label: 'Pa',
data:[],
backgroundColor:'rgba(255, 99, 132, 0.2)',
borderColor:'rgba(255, 99, 132, 1)',
borderWidth: 1
}, {
label: 'cm3/min',
data:[],
backgroundColor:'rgba(54, 162, 235, 0.2)',
borderColor:'rgba(54, 162, 235, 1)',
type: 'line',
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
};
setChart()
</script>
</div>
</div>
</div>
I require a small fix. I simply need to POST my data (comments) to the datastore (GAE) using angularjs but it's not happening just yet. What's wrong with the following angularjs "post" or html?
ANGULAR:
$scope.addComment = function() {
var form_comment = $scope.formFields.comment
var payload = {
comment: form_comment
}
$http({
method: 'POST',
url: '/exp'
}).then(function successCallback(response) {
$scope.comments.push(payload);
}, function errorCallback(response) {
});
};
HTML:
{% extends "home.html"%}
{% block content %}
<div ng-controller="commentController" class="formcontent">
<div class ="container">
<form ng-submit="addComment()" method="post" id="frmComment">
<textarea ng-model="formFields.comment" id="comment" name="commento" class="form-control status-box sameline" rows="2" placeholder="Recommend Colin"></textarea>
</form>
<div class="button-group pull-right sameline">
<p class="counter">140</p>
<button form ="frmComment"class="btn btn-primary" type="submit">Post</button>
</div>
</div>
<div>
<ul class="posts">
<li ng-repeat = "c in comments">
{< c.comment >}
</li>
</ul>
</div>
</div>
{% endblock %}
PYTHON:
class expHandler(webapp2.RequestHandler):
def get(self):
title="Colin_MK: Experience"
recommendations = Recommendation.query()
self.response.out.write(json.dumps([rec.to_dict() for rec in recommendations]))
template_vars = {'title': title, 'recommendations': recommendations}
template = JINJA_ENVIRONMENT.get_template('/exp.html')
self.response.out.write(template.render(template_vars))
def post(self):
r = json.loads(self.request.body)
new_comment = Recommendation(comment=r['comment'])
new_comment.put()
app = webapp2.WSGIApplication([
('/', MainHandler),
('/bio', bioHandler),
('/exp', expHandler)
], debug=True)
The signature to the post method is the following:
post(url, data, [config]);
so you should also include the payload. Try something like this:
$http.post('/exp', payload).then(...)
Also, on the then() method of the promise, you should send a reference to the method:
.then(function(response) {
$scope.comments.push(payload);
}, function(response) {
});