15  Ranking

Bar charts and their variants – comparing quantities across categories.

(ns plotje-book.ranking
  (:require
   ;; Kindly -- notebook rendering protocol
   [scicloj.kindly.v4.kind :as kind]
   ;; Tablecloth -- dataset manipulation
   [tablecloth.api :as tc]
   ;; Rdatasets -- standard datasets
   [scicloj.metamorph.ml.rdatasets :as rdatasets]
   ;; Plotje -- composable plotting
   [scicloj.plotje.api :as pj]))
(def sales {:product [:widget :gadget :gizmo :doohickey]
            :revenue [120 340 210 95]})

Count bars

pj/lay-bar with only a category column counts the rows in each category – the bar height is the number of occurrences.

Plain

Count occurrences of a categorical column.

(-> (rdatasets/datasets-iris)
    (pj/lay-bar :species))
speciessetosaversicolorvirginica05101520253035404550

Colored (dodged)

Grouped (dodged) bars – count by day, colored by smoking status.

(-> (rdatasets/reshape2-tips)
    (pj/lay-bar :day {:color :smoker}))
daysmokerNoYesSunSatThurFri01020304050

Stacked

Same data, stacked instead of dodged.

(-> (rdatasets/reshape2-tips)
    (pj/lay-bar :day {:position :stack :color :smoker}))
daysmokerNoYesSunSatThurFri0102030405060708090

Proportions (100% stacked)

100% stacked bars – shows proportions instead of counts.

(-> (rdatasets/palmerpenguins-penguins)
    (pj/lay-bar :island {:position :fill :color :species}))
islandspeciesAdelieGentooChinstrapTorgersenBiscoeDream0.00.10.20.30.40.50.60.70.80.91.0

Horizontal

Counting bars have no native horizontal form (the category would need to be counted onto the y-axis), so flip the chart instead.

(-> (rdatasets/datasets-iris)
    (pj/lay-bar :species)
    (pj/coord :flip))
species05101520253035404550setosaversicolorvirginica

(pj/coord :flip) draws categories bottom-to-top in data order, matching ggplot2’s coord_flip(). For a ranking chart where the biggest value should appear at the top, sort the data ascending before plotting, e.g. (tc/order-by data [:value] [:asc]).

Horizontal, colored

Colored bars, flipped.

(-> (rdatasets/reshape2-tips)
    (pj/lay-bar :day {:color :time})
    (pj/coord :flip))
daytimeDinnerLunch0102030405060708090SunSatThurFri

Value bars

Give pj/lay-bar a value column too and it uses those numbers directly as the bar heights – no counting.

Vertical

One bar per product; the bar height is the revenue.

(-> sales
    (pj/lay-bar :product :revenue))
revenueproductwidgetgadgetgizmodoohickey050100150200250300350

Horizontal

Put the category on y – no coord flip needed (unlike count bars).

(-> sales
    (pj/lay-bar :revenue :product))
productrevenue050100150200250300350widgetgadgetgizmodoohickey

Ranked

A ranking chart is read down from the biggest, and the bars above are in whatever order the data happened to hold. Plotje draws the bands of a categorical y axis in data order, running bottom to top, so sorting the rows ascending by the value puts the biggest bar at the top. The same sort does the same thing under (pj/coord :flip), which is how the count-bar form gets there.

(def sales-ranked
  (-> sales
      tc/dataset
      (tc/order-by :revenue :asc)))
(-> sales-ranked
    (pj/lay-bar :revenue :product))
productrevenue050100150200250300350doohickeywidgetgizmogadget

Rotated labels

Horizontal bars are one way to fit long category names. To keep the bars vertical instead, rotate the x-tick labels with :x-tick-angle (see Customization for details, including :x-tick-label-pad):

(-> {:department ["Office Supplies" "Electronics" "Home Goods"
                  "Sporting Gear" "Garden Tools" "Toys"]
     :revenue [120 340 210 95 160 80]}
    (pj/lay-bar :department :revenue)
    (pj/options {:x-tick-angle -45}))
revenuedepartmentOffice SuppliesElectronicsHome GoodsSporting GearGarden ToolsToys050100150200250300350

Lollipop

A stem and a dot in place of a bar – a lollipop chart draws the same comparison with less ink.

Vertical

(-> sales
    (pj/lay-lollipop :product :revenue))
revenueproductwidgetgadgetgizmodoohickey050100150200250300350

Horizontal

Flipped for horizontal orientation.

(-> sales
    (pj/lay-lollipop :product :revenue)
    (pj/coord :flip))
productrevenue050100150200250300350widgetgadgetgizmodoohickey

With a color column

Map a categorical column to :color to distinguish groups visually – here, products grouped by region.

(-> {:product ["A" "B" "C" "D" "E" "F"]
     :revenue [120 95 150 80 200 110]
     :region  ["North" "South" "North" "South" "North" "South"]}
    (pj/lay-lollipop :product :revenue {:color :region}))
revenueproductregionNorthSouthABCDEF020406080100120140160180200

See Also

  • Core Concepts – mappings and aesthetic vocabulary
  • Distributions – when comparing categories also means comparing their distributions

What’s Next

source: notebooks/plotje_book/ranking.clj