How to use Ajax to update pandas dataframe and change plotly graph accordingly

Viewed 443

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,

  1. 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.

  2. 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!

0 Answers
Related