# Using ListPlot and lists of Associations

I have a list of associations :

testdata = {<|"label" -> "v1", "value1" -> -2, "value2" -> 6|>,
<|"label" -> "v2", "value1" -> 4, "value2" -> -4|>,
<|"label" -> "v3", "value1" -> 6, "value2" -> -5|>};


The first element of each association is the X axis label, each following key indicates the set of data it belongs to.

Using Vitali's answer here I have managed to get ListPlot to use each first element as X axis labels, but the code isn't the cleanest due to repeated usage of "testdata"

ListPlot[{testdata[[All, 2]], testdata[[All, 3]]}, Joined -> True,
Ticks -> {Transpose[{Range@Length@testdata[[All, 1]],
testdata[[All, 1]]}], Automatic},
PlotLegends -> DeleteDuplicates@Keys@testdata[[All, 2 ;; 3]]]


Using key names is a tiny bit clearer at the expense of verbosity:

ListPlot[{testdata[[All, "value1"]], testdata[[All, "value2"]]},
Joined -> True,
Ticks -> {Transpose[{Range@Length@testdata[[All, "label"]],
testdata[[All, "label"]]}], Automatic},
PlotLegends -> DeleteDuplicates@Keys@testdata[[All, 2 ;; 3]]]


I believe there must be a way to substitute in a pure function for this usage but am struggling to find it - any ideas?

Note that Im trying to avoid explicit use of Dataset due to its somewhat quirky behaviour in 10.0.x

BTW

Named keys in associations doesn't seem to support the ;; span specification syntax of Part - is this a bug?

testdata[[All,2;;3]] (* works *)
testdata[[All,"value1";;"value2"]] (* doesnt work *)

• You mean something like ListPlot[testdata[[All,#]]&/@{ "value1","value2"}, Joined -> True, Ticks -> {Transpose[{Range@Length@#, #}]&@testdata[[All, "label"]], Automatic}, PlotLegends -> DeleteDuplicates @Keys @ testdata[[All, 2 ;; 3]]]? – kglr Jan 2 '15 at 19:37
• @kguler Fairly close to what I was thinking, but was wondering if you can take the testdata completely outside of the main ListPlot expression completely, but somehow retain separate parts inside? Im probably trying to push things too far :) – Gordon Coale Jan 2 '15 at 21:18
• maybe ListPlot[{#["value1"]&/@#,#["value2"]&/@#}, Joined -> True, Ticks -> {Transpose[{Range@Length@#, #}]&[#["label"]&/@#], Automatic}, PlotLegends -> DeleteDuplicates @Keys[#][[All,2;;]]]&@testdata? – kglr Jan 2 '15 at 21:39

We can separate the data element selection from the ListPlot generation as follows:

testdata[[All, {"label", "value1", "value2"}]] //
ListPlot[
Transpose @ Values @ #[[All, 2;;]]
, Joined -> True
, Ticks -> {MapIndexed[{#2[[1]], #}&, #[[All, 1]]], Automatic}
, PlotLegends -> DeleteDuplicates @ Keys @ #[[All, 2;;]]
]&


Note the use of a list of keys in testdata[[All, {"label", "value1", "value2"}]]. It is not legal to use key names in spans since, in general, keys are not guaranteed to be in the same order within a list of associations.

The pure function is set up to assume that the first data element is the label and that the remaining data elements are to be plotted. This allows us to use the expression for other association lists where the keys are different, and appear in jumbled order:

testdata2 =
{ <|"x1" -> -10, "x2" -> 30, "title" -> "v1"|>
, <|"x1" -> 20, "title" -> "v2", "x2" -> 22|>
, <|"x2" -> 20, "x1" -> 30, "title" -> "v3"|>
};

testdata2[[All, {"title", "x1", "x2"}]] //
ListPlot[
Transpose @ Values @ #[[All, 2;;]]
, Joined -> True
, Ticks -> {MapIndexed[{#2[[1]], #}&, #[[All, 1]]], Automatic}
, PlotLegends -> DeleteDuplicates @ Keys @ #[[All, 2;;]]
]&


It is inconvenient to copy-and-paste that long pure function expression each time, so we might consider packaging it up for reuse:

myListPlot[data_] :=
ListPlot[
Transpose @ Values @ data[[All, 2;;]]
, Joined -> True
, Ticks -> {MapIndexed[{#2[[1]], #}&, data[[All, 1]]], Automatic}
, PlotLegends -> DeleteDuplicates @ Keys @ data[[All, 2;;]]
]

testdata[[All, {"label", "value1", "value2"}]] // myListPlot


testdata2[[All, {"title", "x1", "x2"}]] // myListPlot


Alternatively, we could have the caller explicitly specify the label and data key names:

myListPlot2[data_, labelKey_, {dataKeys__}] :=
data[[All, {labelKey, dataKeys}]] // myListPlot

myListPlot2[testdata2, "title", {"x1", "x2"}]


• Lovely - exactly what I had in mind. Still digesting kgulers answer below before marking as answered. – Gordon Coale Jan 3 '15 at 12:39
• Lovely answer: addresses all my issues (including the span question) and also contains a logical extrapolation of where I wanted to go. – Gordon Coale Jan 5 '15 at 14:57

You can also do:

ClearAll[listplotF];
listplotF[opts_:{Joined->True}]:= Module[{t, d = Join @@ Through @
{Composition[Transpose, Values], Composition[DeleteDuplicates, Rest/@#&, Keys]}@#},

listplotF[{Joined->True,PlotTheme->"Marketing"}]@testdata