I want to make a plot , where the data is structured like so

{ {"l1", "l2"}, n1, n2, n3} }

The values in the inner sub list are labels which are associated with each data point.

Each distinct "l2" should be on the 'x' axis (like a histogram bin). Therefore I want to plot ("l2", n1) and ("l2", n2). The point generated by using ("l2", n1) should be labeled with "l1", and the point generated with ("l2", n2) should be labeled with "l2"

any repeated values are ignored.

exampleData = {
  {{"A", "B"}, -1, -2, 0.5},
  {{"C", "B"}, -3, -2, 0.6},
  {{"D", "A"}, -5, -6, 0.7}

For example from the above data we would plot

  • (B, -1) label A

  • (B, -2) label B

  • (B, -3) label C

  • (B, -2) label B (* ignore this one since we plotted the same point *)

  • (A, -5) label D

  • (A, -6) label A

The xAxis Position can be obtained by using a replacement list like so:

rules = {"A" -> 1, "B" -> 2}

The plot should have 3 points above B and two points above A and each point should be labelled.

  • 2
    $\begingroup$ Please, show what you've tried, otherwise it just appears to be a "here's the problem, now do it for me...". Hard to learn by others doing... $\endgroup$ – ciao Apr 30 '14 at 0:07
  • $\begingroup$ You might be able to extract the pieces of the original list with Cases and Conditional, simply putting them in the correct places, perhaps with Table if you've many parts. $\endgroup$ – Ghersic Apr 30 '14 at 0:10

You've been on this site a while so I share rasher's reservation about "doing the work" for you, but I'll give the benefit of the doubt because a problem like this can be difficult to approach in a clean way.

Unlike rasher I shall choose a more literal pattern-based approach as I think it is easier to follow. Be aware that it is unlikely to be as fast, especially if working with large numeric data, but if that is the case I'd suggest a different data format to begin with.

Also, Labeled doesn't work in ListPlot in version 7 so I'll use Tooltip instead.

exampleData /.
  {{l1_, l2_}, x1_, x2_, _} :>
    Thread @ Tooltip[Thread @ {l2 /. rules, {x1, x2}}, {l1, l2}]

ListPlot[Union @@ %,
 PlotStyle -> PointSize[Large],
 PlotRangePadding -> 2

enter image description here

If the use of Thread is hard to follow the first line can also be written:

exampleData /.
  {{l1_, l2_}, x1_, x2_, _} :>
    MapThread[Tooltip[{l2 /. rules, #}, #2] &, {{x1, x2}, {l1, l2}}]
  • $\begingroup$ +1, of course. BTW, been pondering a tutorial series for the MM SE blog - I nominate you, LS, SW, et. al. for a collaboration ;-} $\endgroup$ – ciao Apr 30 '14 at 7:24
  • $\begingroup$ @Mr.Wizard this is exactly the sort of solution which highlights how concisely this can be done. $\endgroup$ – olliepower Apr 30 '14 at 13:40
  • 1
    $\begingroup$ @olliepower Thanks for the Accept. $\endgroup$ – Mr.Wizard Apr 30 '14 at 23:48

I am usually loath to just "do the work", however in this case perhaps the following might spur some learning for you. This can be solved much more compactly, even more so perhaps with a rethinking of your data structures which seem overly convoluted IMO.

I urge you to cut-n-paste the following, observe the outputs of each piece, and study the corresponding documentation of the functions used. Only by doing and understanding can you expect to make real progress toward effective use and mastering of the language.

rules = {"A" -> 1, "B" -> 2}
e1 = exampleData[[All, 1, 2]]
e1 = Riffle[e1, e1]
e2 = exampleData[[All, 1]]
e3 = exampleData[[All, 2 ;; 3]]
tmp = Transpose[{e1, Flatten@e3, Flatten@e2}] // DeleteDuplicates
tmp2 = MapAt[(# /. rules) &, tmp, {All, 1}]
tmp3 = Map[Labeled[#[[;; 2]], #[[3]]] &, tmp2]
ListPlot[tmp3, PlotRange -> {{0, 3}, {0, -7}}]

enter image description here

  • $\begingroup$ As I understood the question, the OP wants the labels as if they were tick labls (Each distinct "l2" should be on the 'x' axis (like a histogram bin)) ... but perhaps I'm wrong ... $\endgroup$ – Dr. belisarius Apr 30 '14 at 0:52
  • $\begingroup$ @belisarius: Beats me, question has ambiguities... $\endgroup$ – ciao Apr 30 '14 at 0:54
  • $\begingroup$ Yep. It's confusing and shows no effort. Recipe for disaster $\endgroup$ – Dr. belisarius Apr 30 '14 at 0:57
  • $\begingroup$ @rasher I didn't include my try because I consisted of some lengthy code involving slicing columns for extracting the data, and reassembling it into a form I could work with. I'm currently trying to get better at effeciently maniuplating and transforming lists mathematica style. (ie by using pure functions and mapping across lists). I come from a procedual style background and still have quite a bit to learn about the functional paradidim. As always, i appreciate everyones help $\endgroup$ – olliepower Apr 30 '14 at 1:02
  Thread[Labeled[(Thread[{#2, {##3}}] /. {"A" -> 1, 
         "B" -> 2}), {#1, #2}]] & @@@ (Flatten /@ (Most /@ 
       exampleData))], AxesOrigin -> {0, 0}]

yields: enter image description here


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.