I am very much new to Django and Ajax. I have had decent knowledge on Plotly and Dash, but unfortunately for my project we need login sessions, db etc so had to learn django for it.
My problem statement is I have a plotly bar chart, which displays top performing items based on sales. Also I have a dropdown that has categories , on changing the dropdown values aka categories, I would like the bar graph also to update. I have no prior knowledge on Ajax, but with some googling i was able to come up with the below code.
My Ajax Code :
$('#category').change(function(){
var category = $(this).val();
daterange = $('#daterange').val();
franchise = $('#franchise').val();
$.ajax({
headers: { "X-CSRFToken": token },
type:'POST',
url : 'test/',
data : {
'category':category,
'daterange':daterange,
'franchise':franchise
},
success: function (data) {
var perfBar_ajx = data.data_bstPerf_plt;
Plotly.newPlot(bstPerfbar, perfBar_ajx,layout_bstPerfBar,config);
console.log('Success')
}
});
My plotly JS code :
var categoryGraph = document.getElementById('categoryTrend');
var bstPerfbar = document.getElementById('bstPerfBarPlt');
var data_categoryGraph = {{data_categoryTrend_pl|safe}};
var layout_categoryGraph = {
title:'Category Trend',
//width: 1200,
//height: 400,
xaxis : {
automargin : true
},
yaxis : {
tickprefix : '₹',
tickformat:',.2f',
type:'log',
autorange : true
}
};
var data_bstPerfBar = {{data_bstPerf_plt|safe}};
var layout_bstPerfBar = {
title:'Top performing Items',
//width: 1200,
//height: 400,
xaxis : {
automargin : true
},
yaxis : {
tickprefix : '₹',
tickformat:',.2f',
type:'log',
autorange : true
}
};
var config = {responsive: true};
Plotly.newPlot(categoryGraph, data_categoryGraph,layout_categoryGraph,config);
Plotly.newPlot(bstPerfbar, data_bstPerfBar,layout_bstPerfBar,config);
My Django view :
def test(request):
if request.is_ajax():
category = request.POST.get('category')
daterange = request.POST.get('daterange').split('-')
franchise = request.POST.get('franchise')
startDate = dt.strptime(daterange[0].strip(),'%m/%d/%Y')
endDate = dt.strptime(daterange[1].strip(),'%m/%d/%Y')
df = at.readData()
flag = ut.determineFlag(startDate,endDate)
df = at.filter_df_daterange(df,startDate,endDate)
bstPerfDf = at.bstPerf(df,category,5)
data_bstPerf_plt = [{'type':'bar',
'x':bstPerfDf['S2PName'].unique().tolist(),
'y':bstPerfDf['totSale'].tolist(),
'marker':{'color':'rgba(75, 192, 192, 0.5)',
'line':{
'color':'rgba(75, 192, 192, 1)',
'width': 2
}
}
}]
return JsonResponse({'data_bstPerf_plt':data_bstPerf_plt})
else:
return HttpResponse('None!')
def dashboard(request):
df = at.readData()
if request.method == 'POST':
daterange = request.POST['daterange'].split('-')
franchise = request.POST['franchise']
startDate = dt.strptime(daterange[0].strip(),'%m/%d/%Y')
endDate = dt.strptime(daterange[1].strip(),'%m/%d/%Y')
else:
minDate = df['S2BillDate'].min()
maxDate = df['S2BillDate'].max()
startDate = (maxDate - timedelta(days=14))
endDate = maxDate
flag = ut.determineFlag(startDate,endDate)
df = at.filter_df_daterange(df,startDate,endDate)
df_categoryTrend = at.categoryTrend(df,flag)
xaxis_categoryTrend = df_categoryTrend['S2BillDate'].unique().tolist()
category_list = df_categoryTrend['S2PName-Category'].unique().tolist()
#xaxis_categoryTrend = [df_categoryTrend[df_categoryTrend['S2PName-Category']==cat]['S2BillDate'] for cat in category_list][0]
#xaxis_categoryTrend = xaxis_categoryTrend.tolist()
#below is for Chartjs graph
data_categoryTrend = [{'fill':'false','label': cat,'data': df_categoryTrend[df_categoryTrend['S2PName-Category']==cat]['totSale'].tolist(),'backgroundColor':df_categoryTrend[df_categoryTrend['S2PName-Category']==cat]['background_color'].tolist()[0],'borderColor':df_categoryTrend[df_categoryTrend['S2PName-Category']==cat]['border_color'].tolist()[0]} for cat in category_list]
#Below line ss for plotly graph
data_plt = [{'type' : 'scatter' ,
'x' : df_categoryTrend[df_categoryTrend['S2PName-Category']==cat]['S2BillDate'].tolist(),
'y' : df_categoryTrend[df_categoryTrend['S2PName-Category']==cat]['totSale'].tolist(),
'mode' : 'markers+lines',
'name' : cat,
'line' : {'color': df_categoryTrend[df_categoryTrend['S2PName-Category']==cat]['border_color'].tolist()[0]}
} for cat in category_list]
#Best performance Bar graph in chart js
bstPerfDf = at.bstPerf(df,'Food',5)
xaxis_bstPerfBar = bstPerfDf['S2PName'].unique().tolist()
dataset_bstPerf = [{'data':bstPerfDf['totSale'].tolist(),'borderWidth':2,'borderColor':bstPerfDf[bstPerfDf['S2PName-Category']=='Food']['border_color'].tolist()[0],'backgroundColor':bstPerfDf[bstPerfDf['S2PName-Category']=='Food']['background_color'].tolist()[0]}]
data_bstPerf_plt = [{'type':'bar',
'x':bstPerfDf['S2PName'].unique().tolist(),
'y':bstPerfDf['totSale'].tolist(),
'marker':{'color':'rgba(75, 192, 192, 0.5)',
'line':{
'color':'rgba(75, 192, 192, 1)',
'width': 2
}
}
}]
#Need to remove dicts belonging to chart.js
context = {'startDate':startDate.strftime('%m/%d/%Y'),'endDate':endDate.strftime('%m/%d/%Y'),
'xaxis_categoryTrend':xaxis_categoryTrend,
'data_categoryTrend':data_categoryTrend,
'data_categoryTrend_pl' : data_plt,
'category_list': category_list,
'dataset_bstPerf':dataset_bstPerf,
'xaxis_bstPerfBar':xaxis_bstPerfBar,
'data_bstPerf_plt':data_bstPerf_plt,
'df':df
}
return render(request,'home.html',context)
I have two questions,
In my dashboard view , i have done most of the analysis part like reading from csv etc. when I change the category with Ajax call (which is pointed to test/ view), should I repeat myself like reading the data file again and filtering based on new category? Is there a better way to do this activity? I thought of passing the entire dataframe while to front end and again take it back via Ajax call, but not sure if it is an acceptable practice.
How do I send back the processed value/graph details from test view(this processes the data received from ajax call) to front end and update my plotly graph ?
UPDATE : I tried passing JSON data and I was able to update the graph. But it took 2-3 seconds to update, probably because I had to read the csv file all again , perform all calculations once again for the ajax call.
Can any one point out a better alternative. Thanks!