Django + Bootstrap - [echart] Advanced use of statistical charts - statistics of user daily activity increase, monthly activity increase and other data (2)

I. Introduction

Bootstrapis a popular front-end framework, and ECharts is a popular visualization library.
BootstrapIt can be used to design user interfaces for websites and applications, while ECharts can be used to create interactive and visual charts.
chart.jsChinese documentation: http://www.bootcss.com/p/chart.js/docs/

2. Advanced use

The basic usage has been introduced in the previous article, link: https://blog.csdn.net/qq_43030934/article/details/131540606

This article is based on an advanced use of the Django+bootstrap+echart plug-in. The basic usage will not be introduced too much.

2. Rendering

1. Daily activity statistics

Insert image description here

2. Year and month data statistics

Insert image description here

3. Sample code

No more nonsense, let’s go straight to the code

1. Front end

The code is written based on related projects. You can refer to it based on your own projects.

{% extends "base.html" %} {% load static %}

{% block main %}
    {#    <script src="../../../../static/js/echarts-v5.1.2.min.js"></script>#}

    {% if 'is_superuser' in permissions.keys %}
        <!-- daily active users statistics start -->
        <section class="section" style="padding: 100px 0 30px 0">
            <div class="container">
                <div class="row justify-content-center">
                    <div class="col-12 text-center">
                        <div class="section-title mb-2">
                            <h4 class="title mb-4">用户数据统计</h4>
                        </div>
                    </div><!--end col-->
                </div><!--end row-->
                <div class="row mt-4 pt-2 position-relative" id="userDailyData" style="z-index: 1;">
                    <div class="col-lg-7 col-6 mt-4 pt-2">
                        <div class="counter-box text-center">
                            <div id="userDailyIncrease" style="width:auto;height:400px;"></div>
                        </div><!--end counter box-->
                    </div>

                    <div class="col-lg-5 col-6 mt-4 pt-2">
                        <div class="counter-box text-center">
                            <div id="userBaseData" style="width:auto;height:400px;"></div>
                        </div><!--end counter box-->
                    </div>
                </div><!--end row-->
                <div class="feature-posts-placeholder"></div>
            </div><!--end container-->
        </section><!--end section-->
        <!-- daily active users statistics End -->

        <!-- monthly/year increase users statistics start -->
        <section class="section" style="padding: 30px 0 100px 0">
            <div class="container">
                <div class="row mt-4 pt-2 position-relative" style="z-index: 1;">
                    <div class="col-lg-6 col-6 mt-4 pt-2">
                        <div class="counter-box text-center">
                            <div id="userMonthlyIncrease" style="width:auto;height:400px;"></div>
                        </div><!--end counter box-->
                    </div>

                    <div class="col-lg-6 col-6 mt-4 pt-2">
                        <div class="counter-box text-center">
                            <div id="userYearIncrease" style="width:auto;height:400px;"></div>
                        </div><!--end counter box-->
                    </div>
                </div><!--end row-->
                <div class="feature-posts-placeholder"></div>
            </div><!--end container-->
        </section><!--end section-->
        <!-- monthly/year increase users statistics  End -->
    {% endif %}

    <!-- Document change achievement Start -->
    <section class="section  bg-light">
        <div class="container">
            <div class="row mt-4 pt-2 position-relative" id="counter" style="z-index: 1;">
                <div class="col-md col-6 mt-4 pt-2">
                    <div class="counter-box text-center">
                        <img src="{% static 'images/homepage/Asset260.svg' %}" class="avatar avatar-small" alt="">
                        <h2 class="mb-0 mt-4"><span class="counter-value"
                                                    data-count="97">{
   
   { quarterData.requestTotal }}</span></h2>
                        <h6 class="counter-head text-muted">{
   
   { quarterData.currentQuarter }} Change requests</h6>
                    </div><!--end counter box-->
                </div>

                <div class="col-md col-6 mt-4 pt-2">
                    <div class="counter-box text-center">
                        <img src="{% static 'images/homepage/Asset189.svg' %}" class="avatar avatar-small" alt="">
                        <h2 class="mb-0 mt-4"><span class="counter-value"
                                                    data-count="15">{
   
   { quarterData.completed }}</span></h2>
                        <h6 class="counter-head text-muted">Completed</h6>
                    </div><!--end counter box-->
                </div>

                <div class="col-md col-6 mt-4 pt-2">
                    <div class="counter-box text-center">
                        <img src="{% static 'images/homepage/Asset192.svg' %}" class="avatar avatar-small" alt="">
                        <h2 class="mb-0 mt-4"><span class="counter-value"
                                                    data-count="98">{
   
   { quarterData.percentageComplete }}</span>%</h2>
                        <h6 class="counter-head text-muted">Request Complete</h6>
                    </div><!--end counter box-->
                </div>
            </div><!--end row-->
            <div class="feature-posts-placeholder"></div>
        </div><!--end container-->
    </section><!--end section-->
    <!-- Document change achievement End -->
{% endblock %}

{% block script %}
    <script>
        var MyViewVar = {
      
      
            userCurActiveData: {
      
      {
      
       userCurActiveData|safe }},
            usersDataByDaily: {
      
      {
      
       usersDataByDaily|safe }},
            usersDataByMonthly: {
      
      {
      
       usersDataByMonthly|safe }},
            usersDataByYears: {
      
      {
      
       usersDataByYears|safe }},
        }
        console.log(MyViewVar)
        var userDailyIncreaseChart = echarts.init(document.getElementById('userDailyIncrease'));
        userDailyIncreaseChart.setOption({
      
      
            title: {
      
      
                text: '日增日活',
                x: 'center'
            },
            // 图表图例
            legend: {
      
      
                orient: 'vertical',
                data: ['日活用户', '日增用户',],
                left: 'right',
            },
            xAxis: {
      
      
                name: '日',
                type: 'category',
                data: MyViewVar.usersDataByDaily.date_list,
                boundaryGap: false,
                axisLabel: {
      
      
                    inside: false, //刻度标签是否朝内,false朝外
                    interval: 1, // 设置标签全部显示
                    rotate: 30, // 设置标签旋转角度
                    maxInterval: 1000, // 设置刻度间隔
                },
                axisLine: {
      
      
                    lineStyle: {
      
      
                        color: '#333',
                        type: 'solid',
                    },
                }
            },
            yAxis: {
      
      
                name: '数量',
                type: 'value',
                axisLine: {
      
      
                    show: true,    // 是否显示坐标轴轴线
                    lineStyle: {
      
      
                        color: '#333',    // 坐标轴线线的颜色
                        type: 'solid',    // 坐标轴线线的类型(solid实线类型;dashed虚线类型;dotted点状类型)
                    },
                },
            },
            tooltip: {
      
      
                trigger: 'axis',
                axisPointer: {
      
      
                    type: 'cross'
                }
            },
            series: [
                {
      
      
                    name: '日增用户',
                    data: MyViewVar.usersDataByDaily.user_increase_count_list,
                    type: 'line',
                    itemStyle: {
      
      
                        color: '#91CC75',
                    },
                    markPoint: {
      
      
                        data: [
                            {
      
      type: 'max', name: '最大值'},
                            {
      
      type: 'min', name: '最小值'}
                        ]
                    },
                    lineStyle: {
      
      
                        color: '#91CC75', //线颜色
                        type: 'solid', //线的类型
                        opacity: 0.8, //线透明度
                        shadowBlur: 5, //阴影模糊度
                        shadowColor: '#999', //阴影颜色
                        shadowOffsetX: 2, //阴影X轴偏移量
                        shadowOffsetY: 2, //阴影Y轴偏移量
                        radius: 100 //曲线圆角半径
                    },
                },
                {
      
      
                    name: '日活用户',
                    type: 'line',
                    data: MyViewVar.usersDataByDaily.user_active_count_list,
                    itemStyle: {
      
      
                        color: '#FFC858',
                    },
                    markPoint: {
      
      
                        data: [
                            {
      
      type: 'max', name: '最大值'},
                            {
      
      type: 'min', name: '最小值'}
                        ]
                    },
                    lineStyle: {
      
      
                        color: '#FFC858', //线颜色
                    },
                },
            ]
        });

        var userBaseDataChart = echarts.init(document.getElementById('userBaseData'));
        //定义饼图数据
        var data = [
            {
      
      value: MyViewVar.userCurActiveData.dailyActiveCount, name: '日活用户'},
            {
      
      value: MyViewVar.userCurActiveData.monthlyActiveCount, name: '月活用户'},
        ];
        //定义饼图配置项
        var option = {
      
      
            title: {
      
      
                text: '用户当日及当月活跃人数\n' + '用户总人数:' + MyViewVar.userCurActiveData.totalCount,
                x: 'center'
            },
            tooltip: {
      
      
                trigger: 'item',
                formatter: "{a} <br/>{b} : {c}<br/>" + "用户总人数:" + MyViewVar.userCurActiveData.totalCount
            },
            legend: {
      
      
                orient: 'vertical',
                left: 'right',
                data: ['日活用户', '月活用户']
            },
            series: [
                {
      
      
                    name: '用户基础数据统计',
                    type: 'pie',
                    radius: ['40%', '60%'],
                    center: ['50%', '60%'],
                    data: data,
                    label: {
      
      
                        show: true,
                        formatter: function (params) {
      
      
                            // 计算总数
                            var total = MyViewVar.userCurActiveData.totalCount;
                            // 显示数据项名称和百分比
                            return params.name + '\n' + params.value + '人' + '\n' + (params.value / total * 100).toFixed(2) + '%';
                        }
                    },
                    itemStyle: {
      
      
                        emphasis: {
      
      
                            shadowBlur: 10,
                            shadowOffsetX: 0,
                            shadowColor: 'rgba(0, 0, 0, 0.5)'
                        }
                    },
                    color: ['#FF8D5D', '#FFC858']
                }
            ]
        };
        //渲染饼图
        userBaseDataChart.setOption(option);

        var userMonthlyIncreaseChart = echarts.init(document.getElementById('userMonthlyIncrease'));
        userMonthlyIncreaseChart.setOption({
      
      
            title: {
      
      
                text: '月增月活',
                x: 'center'
            },
            // 图表图例
            legend: {
      
      
                data: ['月活用户', '月增用户'],
                left: 'right',
            },
            xAxis: {
      
      
                name: '月',
                type: 'category',
                data: MyViewVar.usersDataByMonthly.month_list,
                boundaryGap: false,
                axisLabel: {
      
      
                    inside: false, //刻度标签是否朝内,false朝外
                    interval: 0, // 设置标签全部显示
                    rotate: 30, // 设置标签旋转角度
                    maxInterval: 1000, // 设置刻度间隔
                },
                axisLine: {
      
      
                    lineStyle: {
      
      
                        color: '#333',
                        type: 'solid',
                    },
                },
            },
            yAxis: {
      
      
                name: '数量',
                type: 'value',
                axisLine: {
      
      
                    show: true,    // 是否显示坐标轴轴线
                    lineStyle: {
      
      
                        color: '#333',    // 坐标轴线线的颜色
                        type: 'solid',    // 坐标轴线线的类型(solid实线类型;dashed虚线类型;dotted点状类型)
                    },
                },
            },
            tooltip: {
      
      
                trigger: 'axis',
            },
            series: [
                {
      
      
                    name: '月活用户',
                    type: 'line',
                    data: MyViewVar.usersDataByMonthly.user_active_count_list,
                    itemStyle: {
      
      
                        color: '#FFC858',
                    },
                    markPoint: {
      
      
                        data: [
                            {
      
      type: 'max', name: '最大值'},
                            {
      
      type: 'min', name: '最小值'}
                        ]
                    },
                    lineStyle: {
      
      
                        color: '#FFC858', //线颜色
                    },
                },
                {
      
      
                    name: '月增用户',
                    data: MyViewVar.usersDataByMonthly.user_increase_count_list,
                    type: 'line',
                    itemStyle: {
      
      
                        color: '#91CC75',
                    },
                    label: {
      
      
                        show: true,
                        formatter: function (params) {
      
      
                            return params.value;
                        }
                    },
                    markPoint: {
      
      
                        data: [
                            {
      
      type: 'max', name: '最大值'},
                            {
      
      type: 'min', name: '最小值'}
                        ]
                    },
                    lineStyle: {
      
      
                        color: '#91CC75', //线颜色
                    },
                },
            ]
        });

        var userYearIncreaseChart = echarts.init(document.getElementById('userYearIncrease'));
        userYearIncreaseChart.setOption({
      
      
            title: {
      
      
                text: '用户年增长及跃人数\n' + '用户总人数:' + MyViewVar.userCurActiveData.totalCount,
                x: 'center'
            },
            tooltip: {
      
      },
            legend: {
      
      
                orient: 'vertical',
                data: ['年活跃用户', '年增长用户'],
                left: 'right',
            },
            xAxis: {
      
      
                axisLine: {
      
      
                    show: true,    // 是否显示坐标轴轴线
                    lineStyle: {
      
      
                        color: '#333',    // 坐标轴线线的颜色
                        type: 'solid',    // 坐标轴线线的类型(solid实线类型;dashed虚线类型;dotted点状类型)
                    },
                },
                data: MyViewVar.usersDataByYears.year_list,
            },
            yAxis: {
      
      
                name: '数量',
                type: 'value',
                axisLine: {
      
      
                    show: true,    // 是否显示坐标轴轴线
                    lineStyle: {
      
      
                        color: '#333',    // 坐标轴线线的颜色
                        type: 'solid',    // 坐标轴线线的类型(solid实线类型;dashed虚线类型;dotted点状类型)
                    },
                },
            },
            series: [
                {
      
      
                    name: '年活跃用户',
                    type: 'bar',
                    data: MyViewVar.usersDataByYears.user_active_count_list,
                    itemStyle: {
      
      
                        color: '#FFC858',
                    },
                },
                {
      
      
                    name: '年增长用户',
                    type: 'bar',
                    data: MyViewVar.usersDataByYears.user_increase_count_list,
                },

            ],
            label: {
      
      
                show: true,
                position: 'top',  // 在柱形顶部显示标签
                formatter: '{c}',  // 数值显示格式
                color: '#000',  // 标签颜色
                fontSize: 14,  // 标签字体大小
            },
        })
    </script>
{% endblock %}

2. Backend code

The technology stack used by the back-end code interface is. Django+ORM
The code is for reference only. You can use it as a reference according to the business of your own project.

class DataStatisticsView(LoginRequiredJSONMixin, APIView):

    def get(self, request):
        permissions = get_user_permissions(request.user.id)

        quarterData = get_quarter_data_statistics(CP_Register)

        # 获取当前日期
        now_date = datetime.date.today()
        userCurActiveData = self.get_cur_user_active_data(now_date)
        usersDataByDaily = self.get_increase_and_active_users_by_daily(now_date)
        usersDataByMonthly = self.get_increase_and_active_users_by_monthly(now_date)
        usersDataByYears = self.get_increase_and_active_users_by_years(now_date)

        context = {
    
    
            'permissions': permissions,
            'quarterData': quarterData,
            'userCurActiveData': userCurActiveData,
            'usersDataByDaily': usersDataByDaily,
            'usersDataByMonthly': usersDataByMonthly,
            'usersDataByYears': usersDataByYears,
        }
        return render(request, 'teams/my_dashboard/statistics/data_statistics.html', context)

    def get_increase_and_active_users_by_years(self, now_date):
        """数据库中按年增长及年活跃人数"""
        # 按年增长统计用户
        users_per_year = User.objects.annotate(year=ExtractYear('date_joined')).values('year').annotate(
            total=Count('id'))
        user_increase_count_list = []
        year_list = []
        for user in users_per_year:
            user_increase_count_list.append(user['total'])
            year_list.append(user['year'])

        # 按年统计活跃人数
        users_per_year = User.objects.annotate(year=ExtractYear('last_login')).values('year').annotate(
            total=Count('id'))
        user_active_count_list = []
        for user in users_per_year:
            user_active_count_list.append(int(user['total']) * ActiveCoefficient.year_active)

        usersDataByYears = {
    
    
            'user_increase_count_list': user_increase_count_list,
            'user_active_count_list': user_active_count_list,
            'year_list': year_list,
        }

        return usersDataByYears

    def get_increase_and_active_users_by_monthly(self, now_date):
        """
        近一年用户月增及月活跃数据
        sqlite按当月统计一年用户的数量sql:SELECT DATE('now', 'start of month') AS end_date,
                                    DATE('now', '-12 months', 'start of month') AS start_date;
                                    SELECT strftime('%Y-%m', date_joined) AS month,
                                           COUNT(id) AS count
                                    FROM auth_user
                                    WHERE date_joined >= DATE('now', '-12 months', 'start of month')
                                    GROUP BY month
                                    ORDER BY month;
        """
        user_increase_count_list = []
        user_active_count_list = []
        month_list = []

        # FIXME--bug:某月用户数量为0时无数据
        """
        end_date = now_date.replace(day=30)
        start_date = (end_date - datetime.timedelta(days=365)).replace(day=1)

        {'user_count_list': [33, 37, 30, 35, 25, 22, 11, 35, 4, 6, 1, 7], 
         'month_list': ['22-07', '22-08', '22-09', '22-10', '22-11', '22-12', '23-01', '23-02', '23-03', '23-04', '23-05', '23-07']
         }
        users_last_year = User.objects.filter(date_joined__range=(start_date, end_date)).annotate(
            month=TruncMonth('date_joined')).values('month').annotate(count=Count('id'))
        for user in users_last_year:
            user_count_list.append(user['count'])
            month_list.append(user['month'].strftime('%y-%m'))
        """

        # 计算往前12个月的日期时间,计算月增月活数据
        for i in range(12):
            # 当月起始时间和月末时间
            month_first_day = (now_date - datetime.timedelta(days=365 * i / 12)).replace(day=1)
            month_last_day = (month_first_day + datetime.timedelta(days=32)).replace(day=1) - datetime.timedelta(days=1)
            month_increase_count = User.objects.filter(date_joined__range=(month_first_day, month_last_day)).count()
            month_list.append(month_first_day.strftime('%y-%m'))
            user_increase_count_list.append(month_increase_count)
            moth_active_count = int(User.objects.filter(
                last_login__range=(month_first_day, month_last_day)).count() * ActiveCoefficient.monthly_active)
            user_active_count_list.append(moth_active_count)

        usersDataByMonthly = {
    
    
            'user_increase_count_list': user_increase_count_list[::-1],
            'user_active_count_list': user_active_count_list[::-1],
            'month_list': month_list[::-1],
        }

        return usersDataByMonthly

    def get_increase_and_active_users_by_daily(self, now_date):
        """近一月用户日增日活数据"""
        # 获取一个月前日期
        start_date = now_date - datetime.timedelta(days=30)
        date_list = []
        user_increase_count_list = []
        user_active_count_list = []
        for i in range(1, 31):
            # 循环遍历获取当天日期
            cur_date = start_date + datetime.timedelta(days=i)
            next_date = start_date + datetime.timedelta(days=i + 1)
            day_increase_count = User.objects.filter(last_login__range=(cur_date, next_date)).count()
            date_list.append(cur_date.strftime('%y-%m-%d'))
            user_increase_count_list.append(day_increase_count)
            day_active_count = int(
                User.objects.filter(last_login__range=(cur_date, next_date)).count() * ActiveCoefficient.daily_active)
            user_active_count_list.append(day_active_count)

        dailyIncreaseUsers = {
    
    
            'date_list': date_list,
            'user_increase_count_list': user_increase_count_list,
            'user_active_count_list': user_active_count_list,
        }

        return dailyIncreaseUsers

    def get_cur_user_active_data(self, now_date):
        """当日及当月活跃数据"""
        # 日活用户
        dailyActiveCount = User.objects.filter(last_login__gte=now_date).count()
        # 月活用户
        first_day_of_month = datetime.date(now_date.year, now_date.month, 1)
        last_day_of_month = datetime.date(now_date.year, now_date.month + 1, 1) - datetime.timedelta(days=1)
        monthlyActiveCount = User.objects.filter(last_login__range=(first_day_of_month, last_day_of_month)).count()
        # 用户总数
        totalCount = User.objects.all().count()

        userCurActiveData = {
    
    
            'dailyActiveCount': int(dailyActiveCount * ActiveCoefficient.daily_active),
            'monthlyActiveCount': int(monthlyActiveCount * ActiveCoefficient.monthly_active),
            'totalCount': totalCount,
            'date': now_date.strftime('%Y-%m-%d'),
        }
        return userCurActiveData

utils.py

class ActiveCoefficient:
    daily_active = 1.5
    monthly_active = 1.5
    year_active = 3

def get_user_permissions(user_id):
    from registration.models import UserProfile

    u_pro = UserProfile.objects.filter(user_id=user_id).first()
    permissions = OrderedDict()
    if u_pro.is_superuser:
        permissions['is_superuser'] = '超级管理员'
    if u_pro.is_team_leader:
        permissions['is_team_leader'] = '团队负责人'
    if u_pro.is_ele_feature_extension_admin:
        permissions['ele_feature_extension_admin'] = '普通管理员'
    if u_pro.is_es_feature_extension_admin:
        permissions['es_feature_extension_admin'] = '普通管理员'

    if u_pro.role:
        permissions = get_role_permission(u_pro.role.id, permissions)
    return permissions

def get_quarter_data_statistics(obj):
    """季度发布数据统计"""

    today = datetime.date.today()
    current_quarter = (today.month - 1) // 3 + 1
    # 当前年份季度
    current_year_quarter = str(today.year) + 'Q{}'.format(str(current_quarter))
    total = obj.objects.filter(schedule__startswith=current_year_quarter).count()
    completed_cnt = obj.objects.filter(schedule__startswith=current_year_quarter).filter(
        Q(decision__in=['', 'Released']) | Q(decision__isnull=True)).count()
    try:
        percentageComplete = int(completed_cnt / total * 100)
    except Exception as e:
        percentageComplete = 0
        logger.info('homePage error :{}'.format(e))
    QuarterData = {
    
    
        'requestTotal': total,
        'percentageComplete': percentageComplete,
        'completed': completed_cnt,
        'currentQuarter': 'Q{}'.format(current_quarter),
    }
    return QuarterData

The above is Django + Bootstrap - [echart] advanced use of statistical charts - the basic use of statistical data such as daily user activity and monthly activity increase, etc., I hope it will be helpful to you!

Guess you like

Origin blog.csdn.net/qq_43030934/article/details/131769391