Project

General

Profile

0001-statistics-improve-label-sorting-on-group-by-71656.patch

Valentin Deniaud, 08 December 2022 05:29 PM

Download (7.31 KB)

View differences:

Subject: [PATCH] statistics: improve label sorting on group by (#71656)

 tests/api/test_statistics.py | 31 ++++++++++++++++++++++---------
 wcs/statistics/views.py      | 29 +++++++++++++++++++++++------
 2 files changed, 45 insertions(+), 15 deletions(-)
tests/api/test_statistics.py
674 674
    resp = get_app(pub).get(sign_uri(url + '&group-by=test-item'))
675 675
    assert resp.json['data']['x_labels'] == ['2021-01', '2021-02', '2021-03']
676 676
    assert resp.json['data']['series'] == [
677
        {'data': [3, None, None], 'label': 'baz'},
678 677
        {'data': [13, None, None], 'label': 'Foo'},
678
        {'data': [3, None, None], 'label': 'baz'},
679 679
        {'data': [None, None, 4], 'label': 'None'},
680 680
    ]
681 681

  
682 682
    resp = get_app(pub).get(sign_uri(url + '&group-by=test-item&time_interval=year'))
683 683
    assert resp.json['data']['x_labels'] == ['2021']
684 684
    assert resp.json['data']['series'] == [
685
        {'label': 'baz', 'data': [3]},
686 685
        {'label': 'Foo', 'data': [13]},
686
        {'label': 'baz', 'data': [3]},
687 687
        {'label': 'None', 'data': [4]},
688 688
    ]
689 689

  
690 690
    resp = get_app(pub).get(sign_uri(url + '&group-by=test-item&time_interval=hour'))
691 691
    assert resp.json['data']['x_labels'] == list(range(24))
692
    assert resp.json['data']['series'][0]['data'][0] == 3
693
    assert resp.json['data']['series'][1]['data'][0] == 13
692
    assert resp.json['data']['series'][0]['data'][0] == 13
693
    assert resp.json['data']['series'][1]['data'][0] == 3
694 694
    assert resp.json['data']['series'][2]['data'][2] == 4
695 695

  
696 696
    resp = get_app(pub).get(sign_uri(url + '&group-by=test-item&time_interval=weekday'))
697 697
    assert len(resp.json['data']['x_labels']) == 7
698 698
    assert resp.json['data']['series'] == [
699
        {'label': 'baz', 'data': [None, None, None, None, 3, None, None]},
700 699
        {'label': 'Foo', 'data': [None, None, None, None, 13, None, None]},
700
        {'label': 'baz', 'data': [None, None, None, None, 3, None, None]},
701 701
        {'label': 'None', 'data': [4, None, None, None, None, None, None]},
702 702
    ]
703 703

  
......
715 715
    resp = get_app(pub).get(sign_uri(url + '&group-by=checkbox'))
716 716
    assert resp.json['data']['x_labels'] == ['2021-01', '2021-02', '2021-03']
717 717
    assert resp.json['data']['series'] == [
718
        {'data': [13, None, None], 'label': 'Yes'},
718 719
        {'data': [3, None, None], 'label': 'No'},
719 720
        {'data': [None, None, 4], 'label': 'None'},
720
        {'data': [13, None, None], 'label': 'Yes'},
721 721
    ]
722 722

  
723 723
    # group by status
724 724
    resp = get_app(pub).get(sign_uri(url + '&group-by=status'))
725 725
    assert resp.json['data']['x_labels'] == ['2021-01', '2021-02', '2021-03']
726 726
    assert resp.json['data']['series'] == [
727
        {'data': [3, None, None], 'label': 'End status'},
728 727
        {'data': [13, None, 4], 'label': 'New status'},
728
        {'data': [3, None, None], 'label': 'End status'},
729 729
    ]
730 730

  
731 731
    # group by channel
......
738 738

  
739 739
    # group by item field without time interval
740 740
    resp = get_app(pub).get(sign_uri(url + '&group-by=test-item&time_interval=none'))
741
    assert resp.json['data']['x_labels'] == ['baz', 'Foo', 'None']
742
    assert resp.json['data']['series'] == [{'data': [3, 13, 4], 'label': 'Forms Count'}]
741
    # Foo is first because it has a display value, baz is second because it has not, None is always last
742
    assert resp.json['data']['x_labels'] == ['Foo', 'baz', 'None']
743
    assert resp.json['data']['series'] == [{'data': [13, 3, 4], 'label': 'Forms Count'}]
743 744

  
744 745
    # group by items field without time interval
745 746
    resp = get_app(pub).get(sign_uri(url + '&group-by=test-items&time_interval=none'))
......
751 752
    assert resp.json['data']['x_labels'] == ['Mail', 'Web']
752 753
    assert resp.json['data']['series'] == [{'data': [3, 17], 'label': 'Forms Count'}]
753 754

  
755
    # group by status without time interval
756
    resp = get_app(pub).get(sign_uri(url + '&group-by=status&time_interval=none'))
757
    assert resp.json['data']['x_labels'] == ['New status', 'End status']
758
    assert resp.json['data']['series'] == [{'data': [17, 3], 'label': 'Forms Count'}]
759

  
760
    # check statuses order
761
    formdef.workflow.possible_status = list(reversed(formdef.workflow.possible_status))
762
    formdef.workflow.store()
763
    resp = get_app(pub).get(sign_uri(url + '&group-by=status&time_interval=none'))
764
    assert resp.json['data']['x_labels'] == ['End status', 'New status']
765
    assert resp.json['data']['series'] == [{'data': [3, 17], 'label': 'Forms Count'}]
766

  
754 767
    # group by on block field is not supported
755 768
    resp = get_app(pub).get(sign_uri(url + '&group-by=blockdata_bool'))
756 769
    assert resp.json['data']['series'] == [{'data': [16, 0, 4], 'label': 'Forms Count'}]
wcs/statistics/views.py
457 457
        for group in seen_group_values:
458 458
            totals_by_group[group] = [totals.get(group) for totals in totals_by_time.values()]
459 459

  
460
        totals_by_label = self.get_totals_by_label(totals_by_group, group_labels)
461

  
460 462
        x_labels = list(totals_by_time)
461
        series = [
462
            {'label': group_labels.get(group, group), 'data': data} for group, data in totals_by_group.items()
463
        ]
464
        series.sort(key=lambda x: x['label'].lower())
463
        series = [{'label': label, 'data': data} for label, data in totals_by_label.items()]
465 464
        return x_labels, series
466 465

  
467 466
    def get_grouped_data(self, totals, group_labels):
......
472 471
            for group in groups:
473 472
                totals_by_group[group] += total
474 473

  
475
        x_labels = [group_labels.get(group, group) for group in totals_by_group]
476
        series = [{'label': self.label, 'data': [total for total in totals_by_group.values()]}]
474
        totals_by_label = self.get_totals_by_label(totals_by_group, group_labels)
475

  
476
        x_labels = list(totals_by_label)
477
        series = [{'label': self.label, 'data': [total for total in totals_by_label.values()]}]
477 478
        return x_labels, series
478 479

  
480
    def get_totals_by_label(self, totals_by_group, group_labels):
481
        groups = list(totals_by_group)
482
        group_label_indexes = {group: i for i, group in enumerate(group_labels)}
483

  
484
        def get_group_order(group):
485
            if group is None:
486
                # None choice should always be last
487
                return len(group_label_indexes) + 1
488
            if group not in group_label_indexes:
489
                # unknown group should be last but before none
490
                return len(group_label_indexes)
491
            return group_label_indexes[group]
492

  
493
        groups.sort(key=get_group_order)
494
        return {group_labels.get(group, group): totals_by_group[group] for group in groups}
495

  
479 496

  
480 497
class CardsCountView(FormsCountView):
481 498
    formdef_class = CardDef
482
-