2

I want to order the stack elements (group-by-k) while keeping order in the global bars (col-k).

The $order function doesn't allow ordering multiple columns at once. So the function twice, though, the last sort will not preserve the previous sort. So I can either have the global bars sorted, or the stacked elements of a bar, but not both!

How can I achieve this? I suspect we would need a sorted-map working inside a $fn but not sure how to implement this...

Here the function I've written to attempt multiple ordering.

(require
   (incanter '[core :as core]
             '[charts :as charts])

(defn sorted-barchart [data col-k & {:keys [group-by-k 
                                            order-k 
                                            order-sign 
                                            order-group-k 
                                            order-group-sign 
                                            title 
                                            x-label 
                                            y-label 
                                            legend]}]
  (core/with-data
    (let [d (core/to-dataset data)
          d1 (core/$where {group-by-k {:$fn #(not (empty? %))}} d)
          d2 (core/$where {col-k {:$fn #(not (empty? %))}} d1)
          d3 (core/$rollup :count :counts (if group-by-k [col-k group-by-k] [col-k]) d2)
          d4 (core/$order (or order-k col-k) (or order-sign nil) d3)
          d5 (core/$order (or order-group-k group-by-k)
                          (or order-group-sign nil) d4)]
      d5) 
    (let [chart (charts/stacked-bar-chart col-k :counts
                                           :group-by group-by-k 
                                           :vertical false
                                           :x-label (or x-label " ")
                                           :y-label (or y-label " ")
                                           :title (or title " ")
                                           :legend (or legend true)
                                           :series-label "Total")]
      chart)))

EDIT: this actually works when sorting by col-k and group-by-k. But when you want to first sort by counts it gets trickier to preserve col-k order when sort by count when you also want to get the stack elements sorted.

leontalbot
  • 2,513
  • 1
  • 23
  • 32

1 Answers1

1

We can index the counts on main key only (col-k), then sort by index and stacked key (group-by-k).

So, in the sorted-barchart function, we can replace d4 and d5 by the following:

(if
  (and group-by-k order-k (not= order-k col-k))
  (let [d-count (core/$ col-k 
                        (core/$order :c 
                                     :desc 
                                     (core/$rollup :count :c [col-k] d2)))
        d-index (core/dataset [:index col-k] 
                              (map-indexed vector d-count))
        d-join (core/$join [col-k col-k] d-index d3)]
    (->> d-join
         (core/$order (or order-group-k group-by-k)
                      (or order-group-sign :asc))
         (core/$order :index :asc)))
  (let [d-new (if group-by-k 
                (core/$order (or order-group-k group-by-k)
                             (or order-group-sign :asc) d3)
                d3)]
    (core/$order (or order-k col-k) (or order-sign :desc) d-new)))
leontalbot
  • 2,513
  • 1
  • 23
  • 32