Django chart.js multi axis line chart - django

Hi Guys I have inspired from this Fiddle example to try to create a similar multi axis line chart in my django project.
I have in my views :
class dashboard(TemplateView):
template_name = 'users/dashboard.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['qs'] = DummyData.objects.all()
data = DummyData.objects.all()
years=[]
for i in range(data.count()) :
if data[i].year not in years :
years.append(data[i].year)
context['years'] = years
return context
in in my dashboard.html :
{% extends 'users/base.html' %} {% load static %} {% block content %}
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- semantic UI -->
<link rel="stylesheet" type='text/css' href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.14/semantic.min.css">
<!--Chart js-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.min.js" integrity="sha256-Uv9BNBucvCPipKQ2NS9wYpJmi8DTOEfTA/nH2aoJALw=" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.min.css" integrity="sha256-aa0xaJgmK/X74WM224KMQeNQC2xYKwlAt08oZqjeF0E=" crossorigin="anonymous" />
<!-- jQuery -->
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script>
$(document).ready(function (){
var ctx = document.getElementById('myChart');
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: [{% for year in years %} '{{year}}', {% endfor %}],
datasets: [{% for item in qs %}
{
label: '{{item.site}}',
yAxisID: '{{item.site}}',
data: [100, 96, 84, 76, 69] , {% endfor %}
]
},
options: {
scales: {
yAxes: [{
id: 'A',
type: 'linear',
position: 'left',
}, {
id: 'B',
type: 'linear',
position: 'right',
ticks: {
max: 1,
min: 0
}
}]
}
}
});
});
</script>
<canvas id="myChart" width="400" height="100"></canvas>
{% endblock content %}
When I copied the fiddle example it showed correctly in my dahsboard.html as follows :
But When I tried to change the datasets in the code as presented in my dashboard.html nothing shows up, labels are updated okay but this is what makes my chart not work :
datasets: [{% for item in qs %}
{
label: '{{item.site}}',
yAxisID: '{{item.site}}',
data: {{item.turn_over}}' , {% endfor %}
]
I am sure this is not how it is supposed to be done, I'm a beginner at chart.js , what I want to do is load how many sites I have in my Dummydata table and show their turn over
Thank you

Done It was a comma positioning mistake, I checked the console and the problem was that when my if condition was not being checked instead of skipping, it was adding an empty value, meaning that I was getting for example 1, , , , 2 , , , 3 instead of 1,2,3 and the chart was rendering the empty cells, anyway here is the how I was able to fix it for data :
data: {
labels: [{% for year in years %} '{{year}}', {% endfor %}],
datasets: [
{% for site in sites %}
{
label: '{{site.site}}',
yAxisID: 'y',
borderColor: '{{site.color}}',
backgroundColor: 'transparent',
data: [ {% for item in qs %}
{% if item.site == site.site %}
{{item.turn_over}} ,{% endif %} {% endfor %}
]
}, {% endfor %}
]
}

Related

Data not displaying in django admin - using chart.js (no errors)

I have created a changelist_view for displaying a chart.js visual in the Django admin.
I am not getting any errors, the chart outline is visible, but the data is not. Not sure what I'm missing. Info below:
admin.py model:
class MachineFaultAdmin(admin.ModelAdmin):
readonly_fields = [
'event_id',
'fault_type_id',
'position',
]
list_display = [
'event_id',
'fault_type_id',
'position',
]
def changelist_view(self, request, extra_context=None):
# Aggregate Faults
chart_data = (
MachineFault.objects.all()
.values('position')
.annotate(total=Count('fault_type_id'))
.order_by('total')
.filter(position__gte=10)
)
#Serialize and attach the chart data to the template context
as_json = json.dumps(list(chart_data), cls=DjangoJSONEncoder)
extra_context = extra_context or {"chart_data": as_json}
#Call the superclass changelist_view to render the page
return super().changelist_view(request, extra_context=extra_context)
def has_add_permission(self, request):
# Nobody is allowed to add
return False
def has_delete_permission(self, request, obj=None):
# nobody is allowed to delete
return False
# suit_classes = 'suit-tab suit-tab-faults'
empty_value_display = ''
list_filter = ('fault_type',)
search_fields = ('position',)
changelist_view html (admin override file)
<!--# machines/templates/admin/machines/machinefault/change_list.html-->
{% extends "admin/change_list.html" %}
{% load static %}
<!-- Override extrahead to add Chart.js -->
{% block extrahead %}
{{ block.super }}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.bundle.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
const ctx = document.getElementById('myChart').getContext('2d');
// Sample data
const chartData = {{ chart_data | safe }};
// Parse the dates to JS
chartData.forEach((d) => {
d.x = new Date(d.date);
});
// Render the chart
const chart = new Chart(ctx, {
type: 'bar',
data: {
datasets: [
{
label: 'Breaks ',
data: chartData,
backgroundColor: 'rgba(220,20,20,0.5)',
},
],
},
options: {
responsive: true,
scales: {
xAxes: [
{
type: 'time',
time: {
unit: 'day',
round: 'day',
displayFormats: {
day: 'MMM D',
},
},
},
],
yAxes: [
{
ticks: {
beginAtZero: true,
},
},
],
},
},
});
});
</script>
{% endblock %}
{% block content %}
<!-- Render our chart -->
<div style="width: 80%;">
<canvas style="margin-bottom: 5px; width: 50%; height: 15%;" id="myChart"></canvas>
</div>
<button id="reload" style="margin: 1rem 0">Reload chart data</button>
<!-- Render the rest of the ChangeList view -->
{{ block.super }}
{% endblock %}
But my chart is still blank - I have no errors.
Using latest Django, Python3.7
UPDATE: 2/14/2020
Can't be sure that this is the cause of your issue without seeing the HTML, but the way you are passing data to your chart JS is unsafe - don't do this:
const chartData = {{ chart_data | safe }};
It's very likely you are ending up with invalid JS as a result of this, because the output is not properly escaped. Instead, use the json_script filter to safely render your object, and then read this in JS. Something like this:
{{ chart_data|json_script:"chart-data" }}
<script>
const chartData = JSON.parse(document.getElementById("chart-data").textContent);
// initialise the chart as you currently do
</script>
Note - you need to stop encoding the data as JSON in your view - just pass it the original list which this filter will encode safely for you.
If this doesn't fix it then it's likely that the data structure itself is not what the chart library is expecting - perhaps if you post a sample of what chartData looks like we can see whether that looks right.

Chart JS Manual Bar Chart YAxis

I am working on a project that will use ratings from 1-10. The automatic scaling in ChartJs is causing issues where data is not displayed due to it not being in range.
How can I remove the automatic scaling of a bar chart yxais and manually set the scales to 1-10 ?
<canvas id="bar-chart-grouped" width="800" height="350"></canvas>
<script>
new Chart(document.getElementById("bar-chart-grouped"), {
type: 'bar',
data: {
labels: [{% for result in results %}
"{{result.title}}",
{% endfor %}],
datasets: [
{
label: "Rating",
backgroundColor: "#3e95cd",
data: [{% for result in results %}
"{{result.w_average}}",
{% endfor %}]
}, {
label: "My Rating",
backgroundColor: "#3cba9f",
data: [{% for result in results %}
"{{result.rating}}",
{% endfor %}]
}
]
},
options: {
title: {
display: true,
text: 'Movie Ratings'
}
}
});
</script>

NVD3 Chart won't render in Django

I'm having trouble getting my nvd3 pie chart to render.
I'm using a template tag (simple tag) to return the data required to construct the pie chart.
Already verified:
All static files are loading
The template tag is passing the correct dictionary to the template
All templates are loading
No errors
The chart appears to be loading in the source code header
color-id.html (template for just the pie chart)
{% load static %}
<link media="all" href="{% static 'nvd3/build/nv.d3.css' %}" type="text/css" rel="stylesheet" />
<script type="text/javascript" src='{% static 'd3/d3.min.js' %}'></script>
<script type="text/javascript" src='{% static 'nvd3/build/nv.d3.min.js' %}'></script>
{% load nvd3_tags %}
{% load basic_deck_stats %}
<head>
{% include_chart_jscss %}
{% color_id deck as data %}
{% load_chart data.charttype data.chartdata data.chartcontainer data.extra %}
</head>
<body>
<h3>Color Identity</h3>
{% include_container "asdf" 400 400 %}
charttype: {{ data.charttype }}<br>
chartdata: {{ data.chartdata }}<br>
chartcontainer: {{ data.chartcontainer }}<br>
extra: {{ data.extra }}
</body>
basic_deck_stats.py (template tag)
from django import template
from card_search.views import Card, Deck, Quantity
from django.shortcuts import render_to_response
register = template.Library()
#register.simple_tag
def color_id(deck):
black=blue=red=white=green = 0
queryset = Quantity.objects.filter(deck__deck_name=deck.deck_name).all()
for item in queryset:
if item.card.mana_cost:
black += item.card.mana_cost.count("{B}") * item.qty
blue += item.card.mana_cost.count("{U}") * item.qty
red += item.card.mana_cost.count("{R}") * item.qty
white += item.card.mana_cost.count("{W}") * item.qty
green += item.card.mana_cost.count("{G}") * item.qty
xdata = ["Black", "Blue", "Red", "White", "Green"]
ydata = [black, blue, red, white, green]
chartdata = {'x': xdata, 'y': ydata}
charttype = 'pieChart'
chartcontainer ='piechart_container'
data = {
'charttype': charttype,
'chartdata': chartdata,
'chartcontainer': chartcontainer,
'extra': {
'x_is_date': False,
'x_axis_format': '',
'tag_script_js': True,
'jquery_on_ready': False,
}
}
return data
Then I'm calling the pie chart template from the deck.html template
{% include "../charts/color-id.html" %}
Hope that's enough detail.
Any help would be much appreciated!
Alex

something wrong in presenting highcharts using django

I was stuck in passing dict's data to highchart using django
here's my views.py code. My thought is trying to pass the database's data to dictionary data , then pass its to user_chart.html's highchairs
def user_chart(request):
user_data = User_Data.objects.filter(user=request.user.username)
data = {'words':[], 'click_times':[]}
for i in user_data:
data['words'].append(i.word)
data['click_times'].append(i.click_times)
xAxis = {"title": {"text": 'ss'}, 'categories': data['words']}
yAxis = {"title": {'text': 'fdfd'}}
series = [
{"name": 'dfdf', "data": data['click_times']}
]
content = {'xAxis': xAxis, 'yAxis': yAxis, 'series': series}
return render(request, 'yigu/user_chart.html', content)
user_chart.html's code. I want to achieve a goal that highchart receives the data then present its as chart.
{% extends 'yigu/base_charts.html' %}
{% block body_block %}
<div class="container">
<div class="row">
<div class="col-md-1"></div>
<div class="col-md-1"></div>
<div class="col-md-1"></div>
<div class="col-md-1">
<div id="chart1" style="width:450px">
</div>
</div>
<div class="col-md-4"></div>
</div>
</div>
<script>
var xAxis = {{ xAxis|safe }}
var yAxis = {{ yAxis|safe }}
var series = {{ series|safe }}
</script>
<script>
$(document).ready(function(){
$("#chart1").highcharts({
chart: {
type: 'column'
},
title: {
text: '搜索频率'
},
xAxis: xAxis,
yAxis: yAxis,
series: series
});
});
</script>
{% endblock %}
But i just got the blank response, the chart didn't show up. Anyone could give me a hand?
After reading http://blogs.law.harvard.edu/rprasad/2011/08/30/highcharts-django-admin/ I noticed categories: [ '{{ categories|join:"','" }}'] And i thought that maybe i should try this type. Then i change my template into something like below
<script>
$(document).ready(function(){
$("#chart1").highcharts({
chart: {
type: 'column'
},
title: {
text: '搜索频率'
},
xAxis: {
title:{
text: '词条',
},
categories: [ '{{ data.words|join:"','"}}']
},
yAxis: {
title:{
text: '次数'
}
},
series:[{
name:'搜索次数',
data:[{{ data.click_times|join:"," }}]
}]
});
});
</script>
Then everything went right. I was so surprised. I hope the solution would help someone.

Django: Using DataTables

I want to introduce filtering and sorting functionality to my table using ajax. From what I found, DataTables seamed to be the best option. but, I can't seem to get it working! The first thing I tried was using it just how they have it set up with there demos. But I could not seam to get the search form to generate and the sorting wont work either. I then tried to use one of the many packages created to implement that functionality. However, I found that the documentation was usually not very clear and difficult to follow, or even when I did follow it, I would be left with the table rendering fine, but the search and sort would still not be available. So I've decided to go back to my original and see if someone might know what I'm doing wrong. The page does render the table correctly, and if I view page source, the javascript is properly linked.
Here is the html:
<pre>
<code>
{% extends "theme_bootstrap/base.html" %}
{% load staticfiles %}
{% block extra_style %}
<script src="{% static "js/jquery.js" %}"></script>
<script src="{% static "js/jquery.dataTables.js" %}"></script>
<script type="text/javascript" charset="utf-8">
$(document).ready(function() {
$('#test').dataTable();
});
</script>
{% endblock %}
{% block body %}
{{ store.StoreName}}
{% if liquors.count > 0 %}
<h1>liquors</h1>
<table id="test">
<thead>
<tr>
<th>Liquor Code</th>
<th>Brand Name</th>
<th>Vendor Name</th>
</tr>
</thead>
<tbody>
{% for liquor in liquors %}
<tr>
<td>{{ liquor.LiquorCode }}</td>
<td>{{ liquor.BrandName }}</td>
<td>{{ liquor.VendorName }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p>None to show!</p>
{% endif %}
{% endblock %}
</code>
</pre>
Here is also my view. Perhaps I've done something wrong here.
def liquors(request, store_id):
args = {}
args.update(csrf(request))
a = Store.objects.get(StoreID=store_id)
args['liquors'] = Liquor.objects.all()
args['a'] = a
return render(request, 'liquors.html', args)
I did this on a project I worked on a while back. Here's how I defined the table in my template:
$(document).ready( function () {
var ticketTable = $('#ticket-table').dataTable( {
"fnDrawCallback": function() {
// Initialize popovers anytime new data is loaded into the table
$('a[rel=tooltip]').tooltip({
placement: 'left'
});
},
"bServerSide": true,
"bAutoWidth": false,
"sPaginationType": "bootstrap",
"sAjaxSource": "{% url get_tickets_list %}",
"aaSorting": [[ 2, "desc" ]],
"iPageLength": 25,
"bLengthChange": false,
"bStateSave": true,
"bFilter": true,
"sDom": "<'length-change'><'row'<'span6'l><'span6'f>r>t<'row'<'span6'i><'length-change'><'span6'p>>",
"oLanguage": {
"sSearch": ""
},
"aoColumns": [
{ "bSortable": false, "sWidth": "14px", "bSearchable": false },
{ "sWidth": "160px", "bSearchable": true },
{ "sWidth": "60px", "bSearchable": true },
{ "bSearchable": true },
{ "bSortable": false, "sWidth": "14px", "bSearchable": false },
{ "sWidth": "50px", "sClass": "center", "bSearchable": false },
{ "bSearchable": true },
{ "sWidth": "70px", "sClass": "center", "bSearchable": false },
{ "sWidth": "75px", "bSearchable": true }
] } ).fnSetFilteringDelay(500);
Key is this line in the table options which defines the source URL for the AJAX request from the DataTable:
"sAjaxSource": "{% url get_tickets_list %}",
Then, you'll also need a view to return the AJAX requests:
def get_tickets_list(request, queryset=Ticket.objects.all()):
"""
AJAX calls for DataTable ticket list.
"""
#columnIndexNameMap is required for correct sorting behavior
columnIndexNameMap = { 0: 'link', 1 : 'created', 2: 'priority', 3: 'client', 4: 'client_email', 5: 'sites', 6: 'problem',7: 'updates', 8: 'state' }
#path to template used to generate json (optional)
jsonTemplatePath = 'json_tickets.txt'
#call to generic function from utils
return get_datatables_records(request, queryset, columnIndexNameMap, jsonTemplatePath)
As I said, this was a while ago and may not work anymore with the latest versions of DataTable, but maybe it will set you in the right direction.