Python Django交互式web绘图

Python Django交互式web绘图,python,django,plot,interactive,Python,Django,Plot,Interactive,我只是想知道使用Django为网站创建交互式情节的最佳方法是什么。当用户更改方程式参数时,绘图需要交互更改。有推荐的套餐吗 我会使用Highcharts,然后您需要创建django后端,以便将数据存储到数据库或其他东西中 下面是我在学校用它做的一个例子: glucose.html: {% extends "base.html" %} {% block title %}Blood Glucose{% endblock %} {% block appmedia %}{{glucose_form.

我只是想知道使用Django为网站创建交互式情节的最佳方法是什么。当用户更改方程式参数时,绘图需要交互更改。有推荐的套餐吗

我会使用Highcharts,然后您需要创建django后端,以便将数据存储到数据库或其他东西中

下面是我在学校用它做的一个例子:

glucose.html

{% extends "base.html" %}

{% block title %}Blood Glucose{% endblock %}

{% block appmedia %}{{glucose_form.media}}{% endblock %}

{% block sidebar %}
    <li data-toggle="collapse" data-target="#reading" class="collapsed">
        <a href="#">Add New Reading</a>
    </li>
    <ul class="sub-menu collapse" id="reading">
        <form id="glucose_form" action="/glucose/submit" method="POST">
            {% csrf_token %}
            {{ glucose_form.as_p }}
        </form>
        <button type="submit" id="glucose_submit">Submit</button>
    </ul>
    <li data-toggle="collapse" data-target="#settings" class="collapsed">
        <a href="#">Update Alert Settings</a>
    </li>
    <ul class="sub-menu collapse" id="settings">
        <form id="glucose_boundary_form" action="/glucose/goals" method="POST">
            {% csrf_token %}
            {{ glucose_boundary_form.as_p }}
        </form>
        <button type="submit" id="glucose_goals">Submit</button>
    </ul>
{% endblock %}

{% block content %}
{{ glucose_result }}
    <div id="glucose_chart" style="width:100%; height:75%;"></div>

    <script type="text/javascript" >
        var chart = $('#glucose_chart').highcharts({
            chart: {
                type: 'line'
            },
            title: {
                text: 'Blood Glucose'
            },
            xAxis: {
                type: 'datetime',
                dateTimeLabelFormats: {
                    minute: '%l:%M %p',
                    hour: '%l %p',
                    day: '%b %d<br>%Y',
                    week: '%b %d<br>%Y',
                    month: '%b %Y',
                    year: '%Y'
                },
                title:{
                    text: null
                },
            },
            yAxis: {
                type: 'integer',
                title:{
                    text: null
                },
                min: 0,
                max: {{ glucose_boundary.upper_bound }} * 1.5,
                ceiling: {{ glucose_boundary.upper_bound }} * 1.5,
                gridLineWidth: 0,
                plotBands: [{
                    id: 'upper_bound',
                    color: 'red',
                    from: '{{ glucose_boundary.upper_bound }}',
                    to: {{ glucose_boundary.upper_bound }} * 1.5,
                },
                {
                    id: 'lower_bound',
                    color: 'red',
                    from: '{{ glucose_boundary.lower_bound }}',
                    to: 0,
                }],
                plotLines: [{
                    id: 'goal_line',
                    color: 'lime',
                    value: '{{ glucose_boundary.glucose_goal }}',
                    width: 2
                }]
            },
            plotOptions: {
                series: {
                    states: {
                        hover: {
                            enabled: false
                        }
                    }
                },
                spline: {
                    marker: {
                        enabled: true
                    }
                }
            },
            series: [{
                color: 'blue',
                showInLegend: false,
                data: [
                    {% for result in glucose_results %}
                        {
                            'name': 'Result',
                            'x': Date.UTC(
                                {{result.date_time.year}},
                                ({{result.date_time.month}} - 1),
                                {{result.date_time.day}},
                                {{result.date_time.hour}},
                                {{result.date_time.minute}}
                            ),
                            'y': {{result.glucose}},
                        },
                    {% endfor %}
                ]
            }],
            tooltip: {
                formatter: function() {
                foods = this.point.name.replace(new RegExp('&lt;br&gt;', 'g'), '<br>');
                timestamp = new Date(this.point.x).toLocaleFormat('%b %d, %Y');
                return '<b><i>' + timestamp + ': ' + this.point.y + ' Calories</i></b><br><br>' + foods;
              }
            },
            credits: {
                enabled: false
            }
        });
        $('button#glucose_submit').click(function() {
            $.ajax({
                url:'glucose/submit',
                type: 'POST',
                data: $('form#glucose_form').serialize(),
                success: function(data) {
                    document.getElementById("glucose_form").reset();
                }
            });
        });
        $('button#glucose_goals').click(function() {
            $.ajax({
                url:'glucose/goals',
                type: 'POST',
                data: $('form#glucose_boundary_form').serialize(),
                success: function(data) {
                    var chart = $('#glucose_chart').highcharts();
                    chart.yAxis[0].removePlotBand('upper_bound')
                    chart.yAxis[0].addPlotBand({
                        id: 'upper_bound',
                        color: 'red',
                        from: document.getElementById('id_upper_bound').value,
                        to: document.getElementById('id_upper_bound').value * 1.5,
                    });
                    chart.yAxis[0].removePlotBand('lower_bound')
                    chart.yAxis[0].addPlotBand({
                        id: 'lower_bound',
                        color: 'red',
                        from: document.getElementById('id_lower_bound').value,
                        to: 0,
                    });
                    chart.yAxis[0].removePlotLine('goal_line')
                    chart.yAxis[0].addPlotLine({
                        id: 'goal_line',
                        color: 'lime',
                        value: document.getElementById('id_glucose_goal').value,
                        width: 2
                    });
                    chart.redraw();
                }
            });
        });
        // ajax components
        function getCookie(name) {
            var cookieValue = null;
            if (document.cookie && document.cookie != '') {
                var cookies = document.cookie.split(';');
                for (var i = 0; i < cookies.length; i++) {
                    var cookie = jQuery.trim(cookies[i]);
                    // Does this cookie string begin with the name we want?
                    if (cookie.substring(0, name.length + 1) == (name + '=')) {
                        cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                        break;
                    }
                }
            }
            return cookieValue;
        };
        var csrftoken = getCookie('csrftoken');
        function csrfSafeMethod(method) {
            // these HTTP methods do not require CSRF protection
            return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
        }
        $.ajaxSetup({
            beforeSend: function(xhr, settings) {
                if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
                    xhr.setRequestHeader("X-CSRFToken", csrftoken);
                }
            }
        });
    </script>
        <style>
        #sidebar {background-color: d46a6a; width: 18%; border-radius: 10px; margin: 10px}
        a{color: #ffffff !important}
        .container-fluid {background-color: d46a6a !important; border-color: d46a6a !important}
        label{color: #ffffff}
        body{background-color: #aa3939}
        .navbar-header {background-color: d46a6a!important, border-color:d46a6a !important}
        #content{background-color: white; border-radius: 10px}
    </style>
{% endblock %}
    from bgpal.models import *
from bgpal.forms import *
from datetime import datetime
from django.db import transaction
from django.shortcuts import render
from django.core.urlresolvers import reverse
from django.shortcuts import get_object_or_404
from django.http import HttpResponse, HttpResponseRedirect
from django.contrib.auth.decorators import login_required

# Create your views here.
def home(request):
    if not request.user.is_authenticated():
        return HttpResponseRedirect(reverse('loginregistration.views.login'))
    return HttpResponseRedirect('glucose')

@login_required
def glucose(request):
    if request.method == 'GET':
        glucose_boundary = __get_glucose_boundary_or_create_initial(request)
        glucose_results = __get_glucose_points(request)
        glucose_boundary_data = {'upper_bound':glucose_boundary.upper_bound,
                                 'lower_bound':glucose_boundary.lower_bound,
                                 'glucose_goal':glucose_boundary.glucose_goal}
        glucose_boundary_form = BloodGlucoseBoundForm(initial=glucose_boundary_data)
        glucose_form = BloodGlucoseForm()
        payload = {'glucose_boundary':glucose_boundary, 'glucose_results':glucose_results,
                   'glucose_boundary_form':glucose_boundary_form, 'glucose_form':glucose_form}
        return render(request, 'glucose.html', payload)

@login_required
def glucose_submit_result(request):
    if request.method == 'POST':
        with transaction.atomic():
            try:
                glucose = request.POST['glucose']
                insulin_dosage = request.POST['insulin_dosage']
                date_time = __get_datetime(request, 'date_time')
                glucose_result = BloodGlucoseModel(user=request.user, glucose=glucose,
                                                insulin_dosage=insulin_dosage, date_time=date_time)
                glucose_result.save()
                return HttpResponse("Success")
            except:
                return HttpResponse("Failed")
    return HttpResponse("Failed")

@login_required
def glucose_update_result(request):
    if request.method == 'POST':
        with transaction.atomic():
            try:
                glucose_result = get_object_or_404(BloodGlucoseModel, user=request.user, id=request.POST['id'])
                glucose_result.glucose = request.POST['glucose']
                glucose_result.insulin_dosage = request.POST['insulin_dosage']
                glucose_result.date_time = request.POST['date_time']
                glucose_result.save()
                return HttpResponse("Success")
            except:
                return HttpResponse("Failed")
    return HttpResponse("Failed")

@login_required
def glucose_remove_result(request):
    if request.method == 'POST':
        with transaction.atomic():
            try:
                glucose_result = get_object_or_404(BloodGlucoseModel, user=request.user, id=request.POST['id'])
                glucose_result.delete()
                return HttpResponse("Success")
            except:
                return HttpResponse("Failed")
    return HttpResponse("Failed")

@login_required
def glucose_update_goals(request):
    if request.method == 'POST':
        with transaction.atomic():
            try:
                glucose_boundary = __get_glucose_boundary_or_create_initial(request)
                glucose_boundary.upper_bound = request.POST['upper_bound']
                glucose_boundary.lower_bound = request.POST['lower_bound']
                glucose_boundary.glucose_goal = request.POST['glucose_goal']
                glucose_boundary.save()
                return HttpResponse("Success")
            except:
                return HttpResponse("Failed")
    return HttpResponse("Failed")

def __get_glucose_boundary_or_create_initial(request):
    glucose_boundary = BloodGlucoseBoundModel.objects.filter(user=request.user)
    if glucose_boundary:
        glucose_boundary = glucose_boundary[0]
    else:
        glucose_boundary = BloodGlucoseBoundModel(user=request.user, upper_bound=200,
                                                lower_bound=50, glucose_goal=100)
        glucose_boundary.save()
    return glucose_boundary

def __get_glucose_points(request):
    glucose_list =BloodGlucoseModel.objects.filter(user=request.user)
    glucose_list = glucose_list.order_by('date_time')
    glucose_points = []
    for sugar in glucose_list:
        date_time = datetime(sugar.date_time.year, sugar.date_time.month, sugar.date_time.day,sugar.date_time.hour,sugar.date_time.minute, sugar.date_time.second)

        glucose_points.append({'glucose': sugar.glucose, 'date_time': date_time})

    return glucose_points

def __get_datetime(request, field_name):
    # Look here for datetime string format http://www.tutorialspoint.com/python/time_strptime.htm
    return datetime.strptime(request.POST[field_name], '%m/%d/%Y %I:%M %p')