Related
I'm new in python and couldn't find any information about my problem. I parsed the site using the Scrapy library and then got a code like this:
var pickupMap = {};
var arBounds = {'112176':{'MIN':['51.534052','43.157633'],'MAX':['51.542724','43.203497']},'106812':{'MIN':['44.733254','33.845615'],'MAX':['44.75256','33.851458']},'58584':{'MIN':['50.575816','36.6502877'],'MAX':['50.5923938','36.667544']},'106799':{'MIN':['45.048373','34.597092'],'MAX':['45.062299','34.601114']},'66656':{'MIN':['59.413621','56.769687'],'MAX':['59.424759','56.816496']},'66674':{'MIN':['52.504677','85.144291'],'MAX':['52.54653','85.203761']},'267176':{'MIN':['48.782604','132.920081'],'MAX':['48.798244','132.939032']},'267212':{'MIN':['52.114018','23.669482'],'MAX':['52.126701','23.774195']},'66653':{'MIN':['56.880181','59.774094'],'MAX':['56.948651','60.01527']},'108135':{'MIN':['56.9659485','60.535173'],'MAX':['56.980787','63.2612845']},'106805':{'MIN':['47.527158','42.195092'],'MAX':['47.531131','42.233503']},'274097':{'MIN':['48.759037','44.771609'],'MAX':['48.79625','44.807619']},'66657':{'MIN':['60.694565','28.754'],'MAX':['60.707573','28.793622']},'58577':{'MIN':['57.576273','34.556255'],'MAX':['57.599057','34.565792']},'66655':{'MIN':['56.329635','37.526226'],'MAX':['56.369589','37.5746']},'106814':{'MIN':['45.198286','33.347581'],'MAX':['45.211952','33.354979']},'112174':{'MIN':['55.137207','59.665829'],'MAX':['55.173553','59.67374']},'58585':{'MIN':['56.985011','40.946888'],'MAX':['57.003985','41.009084']},'69383':{'MIN':['57.6628086','63.054499'],'MAX':['57.683928','63.0896845']},'':{'MIN':['51.191449','-0.001'],'MAX':['54.91634971','71463811.001']},'58572':{'MIN':['56.101544','69.423629'],'MAX':['56.135054','69.522743']},'66699':{'MIN':['54.730576','20.439212'],'MAX':['54.765194','20.56685']},'269484':{'MIN':['56.378167','61.932036'],'MAX':['56.413885','61.947573']},'69385':{'MIN':['53.789821','81.32014'],'MAX':['53.79303','81.354489']},'264806':{'MIN':['49.791049','73.099218'],'MAX':['49.82414','73.13433']},'106807':{'MIN':['45.299679','36.42221'],'MAX':['45.367979','36.509611']},'58588':{'MIN':['52.74497','32.236859'],'MAX':['52.760139','32.260894']},'102547':{'MIN':['55.11894','61.608049'],'MAX':['55.124538','61.640341']},'264974':{'MIN':['54.886978','61.343028'],'MAX':['54.904376','61.39714']},'66670':{'MIN':['56.601861','57.766682'],'MAX':['56.615693','57.807467']},'261955':{'MIN':['44.910851','37.985151'],'MAX':['44.947745','37.993287']},'58573':{'MIN':['56.14182','44.181597'],'MAX':['56.155776','44.204131']},'69417':{'MIN':['53.10206','46.543679'],'MAX':['53.123156','46.59776']},'66647':{'MIN':['55.424384','65.277092'],'MAX':['55.461665','65.372571']},'253903':{'MIN':['54.661021','86.167953'],'MAX':['54.682925','86.188486']},'170833':{'MIN':['52.618193','39.543683'],'MAX':['52.635198','39.665995']},'66648':{'MIN':['53.35057','58.936765'],'MAX':['53.447636','59.065544']},'275128':{'MIN':['40.427814','71.701713'],'MAX':['40.442153','71.728558']},'101457':{'MIN':['55.031217','60.114735'],'MAX':['55.1002966','60.1401356']},'225884':{'MIN':['53.8771353','30.362485'],'MAX':['53.945279','30.392657139']},'66661':{'MIN':['55.563608','41.997268'],'MAX':['55.587486','42.061936']},'66692':{'MIN':['55.368178','36.741326'],'MAX':['55.393465','36.766862']},'66675':{'MIN':['57.905372','59.932745'],'MAX':['57.927342','60.132348']},'66707':{'MIN':['55.753122','60.702335'],'MAX':['55.766314','60.716441']},'58586':{'MIN':['51.771529','55.0732827'],'MAX':['51.846521','55.198791']},'125994':{'MIN':['50.448833','40.14024'],'MAX':['53.31811','82.97458']},'106817':{'MIN':['45.438917','34.731514'],'MAX':['45.452296','34.750506']},'267215':{'MIN':['44.999903','38.926578'],'MAX':['45.00201','38.93406']},'58633':{'MIN':['53.209776','44.921834'],'MAX':['53.23547','45.064627']},'58615':{'MIN':['57.959669','55.928649'],'MAX':['58.102621','56.359388']},'66678':{'MIN':['58.03171','38.81444'],'MAX':['58.035264','38.892135']},'106806':{'MIN':['44.573511','33.437484'],'MAX':['44.62984','33.530163']},'66687':{'MIN':['64.540527','39.802964'],'MAX':['64.551171','39.832237']},'66673':{'MIN':['59.610436','60.577655'],'MAX':['59.613716','60.597765']},'106809':{'MIN':['44.91449','34.045459'],'MAX':['45.028682','34.156152']},'66700':{'MIN':['54.7672986','32.009223'],'MAX':['54.820036','32.049045']},'101869':{'MIN':['59.647538','56.692707'],'MAX':['59.704429','56.77617']},'106795':{'MIN':['43.4160732','39.7478507'],'MAX':['43.6347401','39.9517945']},'58592':{'MIN':['51.281895','37.788627'],'MAX':['51.329463','37.8778']},'66652':{'MIN':['56.893262','62.0229961'],'MAX':['56.8970501','62.052443']},'274263':{'MIN':['42.899291','71.334358'],'MAX':['42.930338','71.347661']},'58578':{'MIN':['58.218534','68.267755'],'MAX':['58.237297','68.335208']},'112171':{'MIN':['54.040707','61.508742'],'MAX':['54.085352','61.638697']},'58568':{'MIN':['57.110806','65.469278'],'MAX':['57.195362','65.63699']},'270647':{'MIN':['51.796016','107.602286'],'MAX':['51.84089','107.65223']},'234489':{'MIN':['45.219844','39.63721'],'MAX':['45.22275','39.71948']},'58567':{'MIN':['55.066308','61.279571'],'MAX':['55.269082','61.478051']},'66671':{'MIN':['56.080507','63.630436'],'MAX':['56.084287','63.663642']},'262107':{'MIN':['51.729026','75.295823'],'MAX':['51.748582','75.319621']}};
var storePlacemarks = {};
var pickupMapCollection = {};
var cityCenter = [39.767945, 64.421701];
var cityZoom = 10;
var cityIcon = '/local/templates/main/images/icons/placemark.svg';
//var countryCenter = [55.7123675178337, 101.99916095676001];
//var countryZoom = 2.5;
var countryCenter = [59.857900590951736, 50.062125866402454];
var countryZoom = 4;
var countryIcon = '/local/templates/main/images/icons/miniIcon.png';
var shop_list = $('#shop_list .store');
var cityID = 274859;
var h1 = $('.content h1.h1');
ymaps.ready(function(){
pickupMap = new ymaps.Map("map", {
flying: true,
center: cityCenter,
zoom: cityZoom,
controls: ['zoomControl']
});
pickupMapCollection = new ymaps.GeoObjectCollection();
storePlacemarks[2061] = new ymaps.Placemark([44.862148, 38.166802], new ymaps.data.Manager({
store_id: 2061,
clusterCaption: 'Brand1',
balloonContentBody: 'Somethin1'
}), {
iconLayout: 'default#image',
iconImageHref: '/local/templates/main/images/icons/placemark.svg',
iconImageSize: [48, 58],
iconImageOffset: [-24, -58]
});
pickupMapCollection.add(storePlacemarks[2061]);
storePlacemarks[2260] = new ymaps.Placemark([47.089910355788, 39.436331546436], new ymaps.data.Manager({
store_id: 2260,
clusterCaption: 'Brand2',
balloonContentBody: 'Something2'
}), {
iconLayout: 'default#image',
iconImageHref: '/local/templates/main/images/icons/placemark.svg',
iconImageSize: [48, 58],
iconImageOffset: [-24, -58]
});
pickupMapCollection.add(storePlacemarks[2260]);
storePlacemarks[2124] = new ymaps.Placemark([51.166561, 53.029105], new ymaps.data.Manager({
store_id: 2124,
clusterCaption: 'Brand3',
balloonContentBody: 'Something3'
}), {
iconLayout: 'default#image',
iconImageHref: '/local/templates/main/images/icons/placemark.svg',
iconImageSize: [48, 58],
iconImageOffset: [-24, -58]
});
pickupMapCollection.add(storePlacemarks[2124]);
My task is that, I have to cut out part of this code (js code), like this:
[
{
store_id: 2061,
clusterCaption: 'Brand1',
balloonContentBody: 'Somethin1'
},
{
store_id: 2260,
clusterCaption: 'Brand2',
balloonContentBody: 'Somethin2'
},
{
store_id: 2124,
clusterCaption: 'Brand3',
balloonContentBody: 'Somethin3'
},
]
You need to use regex because there is a lot of data.
My regex code:
r"(?<=ymaps\.data\.Manager\()(.*?)(?=\)\,*)"
P.s. Thanks for your help in advance
I've been scratching my head for quite a while on this so any help is much appreciated.
Let's say I have a model called Transaction.
class Transaction(models.Model):
time = models.DateTimeField(auto_now_add=True, blank=True)
client = models.ForeignKey(User , on_delete=models.Cascade)
value = models.IntegerField()
I want to generate a chart using chart.js.
So far i am able to do this for all the objects using this JS:
<script>
$(function () {
var $xChart = $("#xChart");
$.ajax({
url: $xChart.data("url"),
success: function (data) {
var ctx = $xChart[0].getContext("2d");
new Chart(ctx, {
type: 'line',
data: data,
options: {
responsive: true,
legend: {
position: 'top',
},
title: {
display: true,
text: 'xChart'
}
}
});
}
});
});
</script>
And this FBV for the ajax call:
def x_chart(request):
def random_color():
return "#"+''.join([choice('ABCDEF0123456789') for i in range(6)])
labels=[]
data=[]
enddate = datetime.now()
startdate = datetime.now().date() - relativedelta(days=3)
transactions = Transaction.objects.filter(time__range=[startdate,enddate])
grouped_transactions = transactions.values("time__day").annotate(total=Sum('value'))
for key in grouped_transactions:
labels.append(key['time__day'])
data.append(key['total'])
return JsonResponse(
data={
'labels': labels,
'datasets': [
{
'label': 'All Transactions,
'backgroundColor': str(random_color()),
'data': data,
}
],
}
)
I want to create a dataset from each Transaction.client field and then pass it as Json to the ajax request. How would i be able to do that since the lables are the dates and some clients don't have transactions in certain dates but some do.
Thanks
You need to specify the user in your filter. Use request.user.
def x_chart(request):
def random_color():
return "#"+''.join([choice('ABCDEF0123456789') for i in range(6)])
labels=[]
data=[]
enddate = datetime.now()
startdate = datetime.now().date() - relativedelta(days=3)
the_client = request.user
transactions = Transaction.objects.filter(client=the_client,time__range=[startdate,enddate])
grouped_transactions = transactions.values("time__day").annotate(total=Sum('value'))
for key in grouped_transactions:
labels.append(key['time__day'])
data.append(key['total'])
return JsonResponse(
data={
'labels': labels,
'datasets': [
{
'label': 'All Transactions,
'backgroundColor': str(random_color()),
'data': data,
}
],
}
)
I am trying reproduce this project that consists of an app with a back-end component in Flask and a front-end that uses vue-js. The back-end is the following:
from flask import Flask, request, jsonify
from flask_cors import CORS
import pandas as pd
app = Flask(__name__)
CORS(app)
#app.route('/')
def hello():
offset = request.args.get('offset', default = 1, type = int)
limit = request.args.get('limit', default = 1, type = int)
df = pd.read_csv('test_data.csv', skiprows=range(1, offset+1), nrows=limit, parse_dates=['X'])
cols = [col for col in df.columns if col.startswith('Y')]
configs = {
'Y1': {'color': '#483D8B', 'col_name': 'name_Y1'},
'Y2': {'color': '#f87979', 'col_name': 'name_Y2'},
'Y3': {'color': '#00BFFF', 'col_name': 'name_Y3'},
}
datasets = []
for k, c in enumerate(cols):
datasets.append({
'label': configs[c]['col_name'],
'borderColor': configs[c]['color'],
'backgroundColor': configs[c]['color'],
'borderWidth': 2,
'pointBorderColor': '#000000',
'lineTension': k*0.23, # line curve
'pointRadius': 2,
'pointBorderWidth': 1,
'fill': False,
'data': df[c].tolist()
})
chart = {
'labels': df['X'].dt.strftime('%H:%M:%S').tolist(),
'datasets': datasets
}
return jsonify({'chart_data': chart})
app.run()
where the csv file is generated with the following script:
import pandas as pd
from datetime import datetime, timedelta
import random
now = datetime.now()
configs = {
'Y1': (0, 250),
'Y2': (0, 500),
'Y3': (0, 750),
}
df_num_rows = 10000
y_vals = {i: [random.randint(*configs[i]) for j in range(df_num_rows)] for i in configs}
df = pd.DataFrame({
'X': ['{:%Y-%m-%d %H:%M:%S}'.format(now + timedelta(seconds=i)) for i in range(df_num_rows)],
**y_vals # ex: {**{'a': [1, 2, 3], 'b': [4, 5, 6]}}
})
df.to_csv('test_data.csv', index=False)y_vals = {i: [random.randint(*configs[i]) for j in range(df_num_rows)] for i in configs}
The html file is:
<div id="app">
<div style="width: 600px; height: 300px;margin: 0 auto;">
<line-chart v-bind:chart-data="chartData"></line-chart>
</div>
</div>
<script src="https://unpkg.com/vue"></script>
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script> -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.min.js"></script>
<script src="https://unpkg.com/vue-chartjs#3.4.0/dist/vue-chartjs.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-resource#1.5.1/dist/vue-resource.min.js"></script>
<script>
Vue.component('line-chart', {
extends: VueChartJs.Line,
//mixins: [VueChartJs.mixins.reactiveProp],
props: ['chartData'],
data: function() {
return {
options: {
tooltips: {
mode: 'index', // so all three tooltips appear
intersect: false, // so don't need to be precise with the cursor on the point
},
scales: {
xAxes: [{ // configs for our X axis
display: true,
scaleLabel: {
display: true,
labelString: 'Time'
}
}],
yAxes: [{ // configs for our Yaxis
display: true,
scaleLabel: {
display: true,
labelString: 'Value'
}
}]
},
responsive: true,
maintainAspectRatio: false,
}
}
},
watch: { // this will be our flag for update
'chartData.update_flag': function(new_val, old_val) {
this.$data._chart.update();
}
},
mounted() {
this.renderChart(this.chartData, this.options); // Initialize and render the chart
}
})
var vm = new Vue({
el: '#app',
data() {
return {
chartData: {
'update_flag': 0, // our flag for update
'labels': [], // our labels
'datasets': [] // our datasets
},
}
},
methods: {
fillData(limit, offset) {
Vue.http.get('http://127.0.0.1:5000/?limit=' +limit+ '&offset=' +offset).then(res => {
if (offset === 0) { // if first request let's receive 20 rows of data/labels
this.chartData.labels = res.body.chart_data.labels;
this.chartData.datasets = res.body.chart_data.datasets;
} else {
this.chartData.labels.splice(0, limit); // remove the first label
this.chartData.labels.push(...res.body.chart_data.labels); // like python unpack
for (var i = 0; i < res.body.chart_data.datasets.length; i++) {
this.chartData.datasets[i].data.splice(0, limit);
this.chartData.datasets[i].data.push(...res.body.chart_data.datasets[i].data);
}
}
this.chartData.update_flag ^= 1;
}, err => {
console.log(err);
}).then(() => { // this will happen always
setTimeout(this.fillData, 1000, 1, offset+limit); // preparing next request
});
}
},
created() {
this.fillData(20, 0); // let's ask for the first 20 rows
},
})
</script>
When I launch the app and perform a GET request through the web-browser (end point: localhost:5000?limit=100&offset=100 for example), the web-page shows a string corresponding to the json, i.e., it is not rendering the html page, because, I think, it does not know it has to render the file index.html. Nevertheless, the front-end is revceiving some data.
If I change the code to return flask.render_template('client.html', chart_data=jsonify({'chart_data': chart}, in the front-end I've noticed that this.chartData.labels has 0 length, as if the front-end is not receiving the data correctly, the same for this.chartData.datasets.
How to properly render the html file in such an application?
You should have two functions in flask - with two different URLs.
First function with url / should send only template - and this URL without limit=100&offset=100 you should load in browser.
Second function with url ie. /get_data should send JSON data - and Vue.http.get() should use it with limit=100&offset=100 like /get_data?limit=100&offset=100
If you want to do it with single url then you should use some if/else to detect if page is loaded by browser and send HTML - or by Vue and send JSON. Maybe you could use some HTTP header with informat that you expecte response with JSON. Accept: application/json
Full working code with two functions
from flask import Flask, request, jsonify, render_template_string
from flask_cors import CORS
import pandas as pd
app = Flask(__name__)
CORS(app)
def generate_data():
import pandas as pd
from datetime import datetime, timedelta
import random
now = datetime.now()
configs = {
'Y1': (0, 250),
'Y2': (0, 500),
'Y3': (0, 750),
}
df_num_rows = 10000
y_vals = {i: [random.randint(*configs[i]) for j in range(df_num_rows)] for i in configs}
df = pd.DataFrame({
'X': ['{:%Y-%m-%d %H:%M:%S}'.format(now + timedelta(seconds=i)) for i in range(df_num_rows)],
**y_vals # ex: {**{'a': [1, 2, 3], 'b': [4, 5, 6]}}
})
df.to_csv('test_data.csv', index=False)
#y_vals = {i: [random.randint(*configs[i]) for j in range(df_num_rows)] for i in configs}
# ------
#app.route('/')
def index():
return render_template_string('''
<div id="app">
<div style="width: 600px; height: 300px;margin: 0 auto;">
<line-chart v-bind:chart-data="chartData"></line-chart>
</div>
</div>
<script src="https://unpkg.com/vue"></script>
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script> -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.min.js"></script>
<script src="https://unpkg.com/vue-chartjs#3.4.0/dist/vue-chartjs.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-resource#1.5.1/dist/vue-resource.min.js"></script>
<script>
Vue.component('line-chart', {
extends: VueChartJs.Line,
//mixins: [VueChartJs.mixins.reactiveProp],
props: ['chartData'],
data: function() {
return {
options: {
tooltips: {
mode: 'index', // so all three tooltips appear
intersect: false, // so don't need to be precise with the cursor on the point
},
scales: {
xAxes: [{ // configs for our X axis
display: true,
scaleLabel: {
display: true,
labelString: 'Time'
}
}],
yAxes: [{ // configs for our Yaxis
display: true,
scaleLabel: {
display: true,
labelString: 'Value'
}
}]
},
responsive: true,
maintainAspectRatio: false,
}
}
},
watch: { // this will be our flag for update
'chartData.update_flag': function(new_val, old_val) {
this.$data._chart.update();
}
},
mounted() {
this.renderChart(this.chartData, this.options); // Initialize and render the chart
}
})
var vm = new Vue({
el: '#app',
data() {
return {
chartData: {
'update_flag': 0, // our flag for update
'labels': [], // our labels
'datasets': [] // our datasets
},
}
},
methods: {
fillData(limit, offset) {
Vue.http.get('http://localhost:5000/get_data?limit=' +limit+ '&offset=' +offset).then(res => {
if (offset === 0) { // if first request let's receive 20 rows of data/labels
this.chartData.labels = res.body.chart_data.labels;
this.chartData.datasets = res.body.chart_data.datasets;
} else {
this.chartData.labels.splice(0, limit); // remove the first label
this.chartData.labels.push(...res.body.chart_data.labels); // like python unpack
for (var i = 0; i < res.body.chart_data.datasets.length; i++) {
this.chartData.datasets[i].data.splice(0, limit);
this.chartData.datasets[i].data.push(...res.body.chart_data.datasets[i].data);
}
}
this.chartData.update_flag ^= 1;
}, err => {
console.log(err);
}).then(() => { // this will happen always
setTimeout(this.fillData, 1000, 1, offset+limit); // preparing next request
});
}
},
created() {
this.fillData(20, 0); // let's ask for the first 20 rows
},
})
</script>
''')
#app.route('/get_data')
def get_data():
offset = request.args.get('offset', default = 1, type = int)
limit = request.args.get('limit', default = 1, type = int)
df = pd.read_csv('test_data.csv', skiprows=range(1, offset+1), nrows=limit, parse_dates=['X'])
cols = [col for col in df.columns if col.startswith('Y')]
configs = {
'Y1': {'color': '#483D8B', 'col_name': 'name_Y1'},
'Y2': {'color': '#f87979', 'col_name': 'name_Y2'},
'Y3': {'color': '#00BFFF', 'col_name': 'name_Y3'},
}
datasets = []
for k, c in enumerate(cols):
datasets.append({
'label': configs[c]['col_name'],
'borderColor': configs[c]['color'],
'backgroundColor': configs[c]['color'],
'borderWidth': 2,
'pointBorderColor': '#000000',
'lineTension': k*0.23, # line curve
'pointRadius': 2,
'pointBorderWidth': 1,
'fill': False,
'data': df[c].tolist()
})
chart = {
'labels': df['X'].dt.strftime('%H:%M:%S').tolist(),
'datasets': datasets
}
return jsonify({'chart_data': chart})
if __name__ == '__main__':
generate_data()
app.run()
I'm trying to visualize my data to a graph using chart.js!
However, I have no idea how that's done...
Could you program experts help me with this, please?
Here's the code I had so far
model.py
class MarksInputOne(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True)
date = models.DateTimeField(auto_now_add=True)
mark = models.CharField(max_length=200)
def __str__(self):
return self.mark
views.py
def courseOne(request):
marks = MarksInputOne.objects.filter(user=request.user)
total_assign = TodoList.objects.filter(user=request.user)
total = total_assign.count()
this = total_assign.filter(category__name="MAT292H1").count()
return render(request, 'courses/firstcourse.html', {'marks': marks, 'total_assign': total_assign, 'total': total,
'this': this})
def lineChart(request):
labels =[]
data = []
queryset = MarksInputOne.objects.values('mark').filter(category__name='MAT292H1').order_by('date')
for entry in queryset:
labels.append(entry['date'])
data.append(entry['mark'])
return JsonResponse(data={
'labels': labels,
'data': data,
})
and finally, chart.html, this is actually an example code from chart.js
<div class="col">
<div class="col-md">
<h5>Graph</h5>
<hr>
<div class="card card-body">
<canvas id="chart" width="800" height="400"></canvas>
<script>
var ctx = document.getElementById('chart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: [{{data}}],
datasets: [{
label: 'Academic Performance',
data: [{{ labels }}],
fill: false,
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)'
],
borderColor: [
'rgb(255,99,132)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)',
'rgba(255, 159, 64, 1)'
],
borderWidth: 1
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
</script>
</div>
</div>
</div>
Please help me to implement the data on the chart!
I've been searching through internet for so long, couldn't find anything :((
Thank you for your help!!
All that chart.js cares about is a list of labels, and a list of values. So you'll have to somehow provide it with that. Your lineChart view function responds with a list of labels and a list of datapoints so it suits our needs exactly. What you'll need to do is have your web page send a request to your django server to request the data it should display. When a response is received, you can feed in your data to chart.js and build your chart. Here's a stripped-down code of how all of this fits together from the client's side and from the server's side:
Server Side
def lineChart(request):
return JsonResponse(data = {
'labels': ["Red Label", "Yellow Label"],
'data': [5, 6],
})
Client Side
<canvas id="chart"></canvas>
<script>
let ctx = document.getElementById('chart');
$.ajax({
url: '/lineChart/',
success: function(response){
new Chart(ctx, {
type: 'line',
data: {
labels: response.labels,
datasets: [{
data: response.data
}]
}
});
}
});
</script>
One thing I should point out are the different languages we are dealing with here and how they interact. Django renders an HTML page. During this rendering process, it has access to python variables called context variables. After it's done rendering, it sends that final HTML page to the client. On the client's side is chart.js which is a JavaScript library, it needs JavaScript variables to work with. So using Django's context variables wouldn't really work. ...unless... you use django to render its context variables into the html page as hard-coded javascript-vaild values. I'm guilty of doing this in the past but I would not recommend this approach. It smells awful!
I'm making a project about pull a user github API like this one https://octoprofile.now.sh/user?id=nathannewyen
I don't know how to pass an data to another function in django
Here is my views.py:
def user(req, username):
username = str.lower(username)
# Get User Info
with urlopen(f'https://api.github.com/users/{username}') as response:
source = response.read()
data = json.loads(source)
# Get Limit Call API
with urlopen(f'https://api.github.com/rate_limit') as response:
source = response.read()
limit_data = json.loads(source)
# Get User Repo Info
with urlopen(f'https://api.github.com/users/{username}/repos') as response:
source = response.read()
sorted_by_stars = json.loads(source)
sorted_by_forks = json.loads(source)
sorted_by_size = json.loads(source)
# Sorted by stars
def sort_user_repo_by_stars(sorted_by_stars):
return sorted_by_stars['stargazers_count']
sorted_by_stars.sort(key=sort_user_repo_by_stars, reverse=True)
# Sorted by forks
def sort_user_repo_by_forks(sorted_by_forks):
return sorted_by_forks['forks']
sorted_by_forks.sort(key=sort_user_repo_by_forks, reverse=True)
# Sorted by size
def sort_user_repo_by_size(sorted_by_size):
return sorted_by_size['size']
sorted_by_size.sort(key=sort_user_repo_by_size, reverse=True)
created_at = data['created_at']
created_at = datetime.datetime.strptime(created_at, "%Y-%m-%dT%H:%M:%SZ")
created_at = created_at.strftime("%B %d, %Y")
context = {
'username': username,
'data': data,
'created_at': created_at,
'limit_data': limit_data,
'sorted_by_stars': sorted_by_stars[:8],
'sorted_by_forks': sorted_by_forks[:8],
'sorted_by_size': sorted_by_size[:8],
}
return render(req, 'user.html', context)
class ChartData(APIView):
authentication_classes = []
permission_classes = []
def get(self, request, format=None):
labels = ["Blue", "Yellow", "Green", "Purple", "Orange"]
default_items = [23, 2, 3, 12, 2]
data = {
"labels": labels,
"default": default_items,
}
return Response(data)
and here is my urls.py:
from django.urls import path
from . import views
from .views import ChartData
urlpatterns = [
path('', views.index),
path('search', views.searchUser),
path('<username>', views.user),
path('api/chart/data/', ChartData.as_view(), name='api-data'),
]
and here is my templates index.html:
<script>
var endpoint = '/api/chart/data/'
var defaultData = []
var labels = [];
$.ajax({
method: "GET",
url: endpoint,
success: function (data) {
labels = data.labels
defaultData = data.default
setChart()
},
error: function (error_data) {
console.log("error")
console.log(error_data)
}
})
function setChart() {
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'pie',
data: {
labels: labels,
datasets: [{
label: '# of Votes',
data: defaultData,
backgroundColor: [
'rgba(255, 99, 132, 1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)',
'rgba(255, 159, 64, 1)'
],
borderColor: [
'rgba(255,99,132,1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)',
'rgba(255, 159, 64, 1)'
],
borderWidth: 1
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
}
</script>
<div class="card shadow">
<div class="card-body">
<h4 class="card-title">Top Languages</h4>
<div class="line"></div>
<p class="card-text">
<canvas id="myChart" width="150" height="150"></canvas>
</p>
</div>
</div>
I want to make an Top languages used chart like the link that I linked below.
How can I do that in python django?
I really appreciate it
To make your backend and your frontend communicate, you can use some sort of REST API between the two. This is a whole topic on its own so here is a solution to achieve what you want in a simple way.
Your django server is serving HTML files to your client. Those HTML files are called "templates" in the django world because they are rendered by your server. Sadly, once served to the client, you cannot execute python on those pages anymore... Hou have to find another way. Here is an idea:
As you can type JavaScript in an HTML file, you can make django render your data as something JavaScript can understand. JSON for example, or even directly JavaScript code. Keep in mind that this is often seen as a bad practice though, as it will make bugs harder to find.
In our case, we only need two things: x and y values.
Here is how to generate those in python, so that it can be turned into JavaScript:
labels = ['a', 'b', 'c', 'd', 'e']
values = [0, 0, 0, 0, 0]
return render('our_template.html', {
'x': json.dumps(labels),
'y': json.dumps(values),
})
This what we can write in our template to store the data as plain JavaScript variables:
let x = {{ x|safe }}; // this is django template markup language right here
let y = {{ y|safe }}; // it will get evaluated before returning the template to the client
The code above will get rendered as:
let x = ['a', 'b', 'c', 'd', 'e'];
let y = [0, 0, 0, 0, 0];
And here is how you will use them to make a simple bar chart:
window.addEventListener("DOMContentLoaded", event => {
let label = "My chart";
let ctx = document.getElementById('my-chart').getContext('2d');
let accessLogChart = new Chart(ctx, {
type: 'bar',
data: {
labels: x,
datasets: [{
label: label,
data: y,
}]
},
});
});