19
$\begingroup$

I have the following data

data = {{7.5, 12.45, 12.45, 12.75, 12.75, 12.25, 12.25, 12.53, 12.53},
{8.5, 12.22, 12.22, 12.23, 12.23, 13, 13, 12.54, 12.54}, 
{9.5, 11.58, 11.53, 12.75, 13.48, 12.39, 12.52, 12.17, 13.56}, 
{10.5, 11.76, 11.82, 12.97, 13.55, 12.15, 11.88, 13.07, 12.79}, 
{11.5, 11.18, 11.85, 13.27, 13.02, 12.32, 13, 12.72, 12.63}, 
{12.5, 11.04, 11.61, 13.70, 14.17, 12.77, 12.79, 12.13, 11.78}, 
{13.5, 11.64, 10.68, 13.52, 14.03, 13.14, 13.21, 11.64, 12.13}, 
{14.5, 12.04, 12.12, 13.23, 13.67, 12.58, 13.02, 11.26, 12.05}, 
{15.5, 14.10, 14, 11.65, 11.68, 12.17, 12.36, 12.19, 11.85}, 
{16.5, 14.85, 14.54, 10.94, 11.62, 12.17, 11.72, 11.84, 12.31}, 
{17.5, 15.78, 15.78, 10.62, 10.62, 11.72, 11.72, 11.88, 11.88}, 
{18.5, 17.18, 17.18, 9.53, 9.53, 11.66, 11.66, 11.63, 11.63}};

but I can't find a way to visualize them. Let me explain the structure of the data and also what I want to plot. data contains 12 sub-lists and each one contains 9 elements. The first element, let's say, is the x-coordinate and all the other eight represent percentages. I would like to plot these percentages with vertical lines (something like a histogram). So, at the axis there should be 7.5, 8.5, 9.5, ... , 18.5 and above of every number eight vertical lines (with different colors and indicators 1, 2, 3, ..., 8 if possible) of the corresponding percentages. Any ideas how to implement this?

EDIT

Following @Pinguin Dirk 's method I added some style options using

B0 = BarChart[Rest /@ data, Frame -> True, 
FrameTicks -> {{True, False}, {False, False}}, 
FrameLabel -> {"h", "Percentage %"}, 
FrameStyle -> Directive[FontSize -> 18, FontFamily -> "Helvetica"], 
ChartLabels -> {data[[All, 1]], None}, BarSpacing -> {1, 3}, 
ChartLegends -> Range[8], PlotRange -> {-1, 18}, ImageSize -> 550]

This is the output

enter image description here

Some minor issues:

(a). How can we manipulate the size/fonts of the numbers at the horizontal axis (7.5, 8.5, etc)?

(b). How can we manipulate the size/fonts of the chart's legends? Is there a way to increase the size of the squares or change the used colors?

$\endgroup$
3
  • $\begingroup$ you want something like that: BarChart[Rest /@ data, ChartLabels -> {data[[All, 1]], None}]? $\endgroup$ Oct 4, 2013 at 7:09
  • $\begingroup$ @PinguinDirk Something like that but with a little white space between every eight bars. Anyway, post an answer if you like so to accept it. $\endgroup$
    – Vaggelis_Z
    Oct 4, 2013 at 7:45
  • 1
    $\begingroup$ Glad you like it! Posted - don't accept just yet, other users might have better ideas! Give them some time $\endgroup$ Oct 4, 2013 at 7:49

9 Answers 9

14
$\begingroup$

As discussed in the comment, it seems you want:

BarChart[Rest /@ data, ChartLabels -> {data[[All, 1]], None}, 
   BarSpacing -> {0, 2}]

see other options in BarChart to format as you desire (as I do not know what it is for, it's hard to suggest other things), bonne chance!

enter image description here

or a version with labels for the bars, placed above the bars (see documentation of BarChart for more information):

BarChart[Rest /@ data, 
   ChartLabels -> {data[[All, 1]], Placed[Range[8], Above]}, 
   BarSpacing -> {0, 2}, ImageSize -> Large]

enter image description here

and here's edit numero 3, ChartLegends:

BarChart[Rest /@ data, ChartLabels -> {data[[All, 1]], None}, 
   BarSpacing -> {0, 2}, ChartLegends -> Range[8]]

enter image description here

and again, it's all there, see: BarChart

Based on your questions, here's the new version:

B0 = BarChart[Rest /@ data, Frame -> True, 
       FrameTicks -> {{True, False}, {False, False}}, 
       FrameLabel -> {"h", "Percentage %"}, 
       FrameStyle -> Directive[FontSize -> 18, FontFamily -> "Helvetica"], 
       ChartLabels -> {Style[#, FontSize -> 14] & /@ data[[All, 1]], None},
       BarSpacing -> {1, 3},
       ChartLegends -> 
            SwatchLegend[(Style[#, FontSize -> 24] & /@ Range[8]), 
               LegendMarkerSize -> Large],
       ChartStyle -> "GrayYellowTones",
       PlotRange -> {-1, 18}, ImageSize -> 550]

Note: the colors of the legend are based on the chart colors, I chose GrayYellowTones. For the font sizes, I just map a Style over the respective labels. Finally, to control the boxes sizes, I use SwatchLegend, see the respective info page for more info.

enter image description here

$\endgroup$
5
  • $\begingroup$ Is there a way to add labels to the bars? At the bottom or at the top of each bar? The labels should be 1, 2, 3 all the way to 8. $\endgroup$
    – Vaggelis_Z
    Oct 4, 2013 at 8:11
  • $\begingroup$ added, I am sure you get the idea (and how to format the output as you desire it to be) - looks a bit crowded now... $\endgroup$ Oct 4, 2013 at 8:17
  • $\begingroup$ Yes, now its too crowded! Perhaps send the all the numbers in a table like PlotLegends? $\endgroup$
    – Vaggelis_Z
    Oct 4, 2013 at 8:24
  • $\begingroup$ See my edit for some minor stylistic issues. $\endgroup$
    – Vaggelis_Z
    Oct 4, 2013 at 9:15
  • $\begingroup$ @Vaggelis_Z, all addressed, see latest edit $\endgroup$ Oct 4, 2013 at 9:34
26
$\begingroup$

None of the solutions so far makes use of the fact that the data are percentages and hence add op to (nearly) 100.

(* Add the rows of the data list *)
Total[Rest /@ data, {2}]
(* out *)
{99.96, 99.98, 99.98, 99.99, 99.99, 99.99, 99.99, 99.97, 100., 99.99,100., 100.}

Borrowing from Pinguin Dirk:

BarChart[Rest /@ data
,ChartLayout -> "Stacked"
,ChartLabels -> {data[[All, 1]], None}
,ImageSize -> Large
]

enter image description here

$\endgroup$
6
  • $\begingroup$ good observation! PieChart[Rest /@ data], hypnotic! $\endgroup$ Oct 4, 2013 at 9:04
  • $\begingroup$ I believe this is spot on. But it will look better if, instead of a sequence of rectangles, each 'colored trend' was represented by a piecewise linear function (basically "connecting the dots"). It amounts to plotting the trends one in top of each other. $\endgroup$
    – Peltio
    Oct 4, 2013 at 14:21
  • $\begingroup$ @Peltio: I guess it is hard to say if it is spot on, given the amount of details provided in the OP, for e.g. in this one here you cannot see temporal evolution of a single process clearly, as e.g. in the second bit of VLC's post (ListLinePlots). And this is not saying that mine's better (I was just trying to emulate what he was asking for directly) :) $\endgroup$ Oct 4, 2013 at 15:34
  • $\begingroup$ IMHO this approach gives a better view of the temporal evolution of single processes. The chosen approach is much harder to decipher. I am not talking here about implementation in mma, just that this sort of data make it difficult to follow single trends. The approach that I suggest with piecewise lines would make it easier to see when a determined process (color) is shrinking or expanding (and all in a single picture. As a matter of fact I've seen it used in many reports and in my humble opinion can be very effective. $\endgroup$
    – Peltio
    Oct 4, 2013 at 17:45
  • $\begingroup$ Just to add, with the 'piecewise linear' approach: parallel lines -> process constant; convergent lines -> process shrinking; divergent lines -> process expanding. (I am probably abusing the term process here, but I believe it's clear what I mean). $\endgroup$
    – Peltio
    Oct 4, 2013 at 17:54
25
$\begingroup$

One More way! The means of each data is the blue dot. bars are color coded according to the standard deviation within each sub list.

ListLinePlot[Mean /@ data, 
 Prolog -> 
  MapThread[{Thickness[.04], ColorData["SandyTerrain"][#3], 
     Line[{{#2, First@#1}, {#2, Last@#1}}], Opacity[0.7], White, 
     Dashed, Thickness[0.003], Arrowheads[0.025], 
     Arrow[{{#2, First@#1}, {#2, Last@#1}}]} &, {{Min@#, Max@#} & /@ 
     data, Range[Length@data], Normalize[StandardDeviation /@ data]}],
  PlotLegends -> 
  Placed[BarLegend[{"SandyTerrain", {Min@#, 
        Max@#} &@(StandardDeviation /@ data)}, 
    StandardDeviation /@ data, LegendMarkerSize -> 310, 
    LegendFunction -> (Framed[#, RoundingRadius -> 3] &), 
    LegendLabel -> Style["Stan. Dev.", Gray, FontSize -> 14]], {After,
     Top}],
 PlotRange -> {{0.5, 1 + Max[Length@data]}, {0.9 Min@data, 
    1.05 Max@data}},
 PlotStyle -> Red,
 MeshStyle -> {{Opacity[.7], Blue, PointSize[0.015]}},
 Frame -> True, Mesh -> All, ImageSize -> 600 , Axes -> None, 
 FrameStyle -> Directive[FontSize -> 14], 
 FrameLabel -> {"i-th data", "min to max arrow"}]

enter image description here

$\endgroup$
2
  • $\begingroup$ Visually I like this better than the crowded barchart! +1 $\endgroup$
    – cormullion
    Oct 4, 2013 at 11:42
  • $\begingroup$ @cormullion Thx! But this thing fails if Length@data is too big. We need to do some other tricks then with Line thickness may be... $\endgroup$ Oct 4, 2013 at 11:47
20
$\begingroup$

Out of curiosity I tried this:

DistributionChart[Rest /@ data,
 ChartLabels -> {data[[All, 1]]},
 ChartElementFunction -> "HistogramDensity",
  ChartStyle -> {LightRed, LightGreen, LightBlue},
 BarOrigin -> Left]

chart

As for 'interpretation', here's my attempt.

This type of chart tries to show the distribution of the values in each 'row'. The height of each box is the number of elements that are considered to be 'grouped'. It might be easier to understand using some of the other options. For example:

DistributionChart[Rest /@ data, ChartLabels -> {data[[All, 1]]}, 
 ChartStyle -> {Directive[
    EdgeForm[None]], {Directive[Darker@Cyan]}}, 
 ChartElementFunction -> 
  ChartElementData["PointDensity", PointSize -> 9], BarOrigin -> Bottom, 
 ImageSize -> 550]

With the "PointDensity" option, you can see that it's trying to show the changing distribution by varying the color intensity of the background, with the data points plotted (very small) in black. Perhaps the effect is too subtle to be generally useful...

a point density

As with most Mathematica functions, there's enough flexibility built-in to allow any amount of specialized graphical treatments:

f[{{xmin_, xmax_}, {ymin_, ymax_}}, metadata___] :=
 { Opacity[1],
  Gray,
  Line[{{(xmin + xmax)/2, ymin}, {(xmin + xmax)/2, ymax}}], 
  Opacity[0.25],
  Darker@Green,
  EdgeForm[],
  Disk[{(xmin + xmax)/2, #}, .15] & /@ metadata
  }
DistributionChart[Rest /@ data,
 ChartLabels -> {data[[All, 1]]},
 ChartElementFunction -> f, 
 BarOrigin -> Bottom,
 ImageSize -> 550]

special chart function

$\endgroup$
4
  • 1
    $\begingroup$ I am sure this is exactly what he had in mind :) +1! $\endgroup$ Oct 4, 2013 at 8:19
  • $\begingroup$ Nice plot but I cannot interpret it! What do we see here?! $\endgroup$
    – Vaggelis_Z
    Oct 4, 2013 at 8:23
  • 1
    $\begingroup$ @PinguinDirk :) One day I will find a use for SectorChart3D ... $\endgroup$
    – cormullion
    Oct 4, 2013 at 8:23
  • $\begingroup$ @cormullion well done job here! I missed this point of view. +1 $\endgroup$ Oct 5, 2013 at 22:13
17
$\begingroup$

Since nobody has used this function yet, I will place it here. Your data seems to be organised almost perfectly for ArrayPlot. First I removed the first column from the rest of the values and added to the axes ticks. The rest is just displayed via ArrayPlot, with a particular color scale.

{xs, values} = {First[#], Transpose@Rest[#]} &@Thread@data;

ArrayPlot[values, Frame -> True, 
FrameTicks -> {{MapIndexed[{Last@#2, #1} &, xs], None}, {Table[i, {i, 1, 8}], None}}, 
ColorFunction -> "Temperature",PlotLegends -> Automatic]

*Edit: added the option PlotLegends which is now available in Mathematica 9

$\endgroup$
2
  • 2
    $\begingroup$ what does this visualization show? how do i read it? $\endgroup$ Oct 4, 2013 at 14:02
  • $\begingroup$ @im so confused you can just use the option "PlotLegends->Automatic" $\endgroup$
    – lalmei
    Oct 5, 2013 at 11:31
9
$\begingroup$

The data in the question presents a good case for visualization with Chernoff faces. For that data, actually, the Chernoff faces work "out of the box" pretty well!

Make faces

Load Chernoff faces plotting package:

Import["https://raw.githubusercontent.com/antononcube/\
MathematicaForPrediction/master/ChernoffFaces.m"]

As it is explained in the question the first element of each row is a coordinate and the rest of the elements are percentages:

Total@*Rest /@ data

(* {99.96, 99.98, 99.98, 99.99, 99.99, 99.99, 99.99, 99.97, 100., 99.99, 100., 100.} *)

Using that data property we apply Chernoff faces in the following way.

  • The Chernoff faces are applied after each non-coordinate column is rescaled into [0,1].

  • The faces are colored according to how close the values of each row of data[[All,2;;-1]] are to the Normal Distribution.

  • The rows with close to normally distributed percentages have faces that are more yellow and more smiling.

Here is a grid of the obtained Chernoff faces :

facesGrid =
 Grid[ArrayReshape[#, {3, 4}, ""], Dividers -> All, 
    Alignment -> {Left, Top}] &@
  MapThread[
   (asc = 
      AssociationThread[
       Take[Keys@ChernoffFace["FacePartsProperties"], 
         Length[#3] + 1] -> Append[#3, #4]];
     Column[{
       Row[{"row:", #1, ", x=", #2}],
       ChernoffFace[
        Join[asc, <|"FaceColor" -> Blend[{White, Lighter[Yellow]}, #4]|>], 
        ImageSize -> 150, AspectRatio -> Automatic]}]) &
   , {Range[Length[data]], First /@ data, 
    Transpose[Rescale /@ Transpose[Rest /@ data]], 
    PearsonChiSquareTest[Standardize[Rest[#]], 
       NormalDistribution[0, 1]] & /@ data}]

enter image description here

Here are all face properties used in the Chernoff faces above:

props = 
 Take[Keys@ChernoffFace["FacePartsProperties"], Length[First@data]]

(* {"FaceLength", "ForheadShape", "EyesVerticalPosition", "EyeSize",\
    "EyeSlant", "LeftEyebrowSlant", "LeftIris", "NoseLength", \
    "MouthSmile"} *)

Discernibility and classification

The main motivation behind the introduction and use of Chernoff faces is that they would provide inherent visual discernibility and classification. With this data that claim is fulfilled.

We can easily see that the face of row 7 is a clear outlier which can be explained by looking at the columns "ForheadShape" and "EyeSlant" of the table of the data:

enter image description here

Also we can easily see from the faces that row 5 has rows 3, 4, 6 as nearest neighbors. This can be demonstrated with the following commands:

nf = Nearest[data[[All, 2 ;; -1]] -> Automatic];
nf[data[[5, 2 ;; -1]], 5]

(*  {5, 4, 3, 6, 1} *)

(Of course other nearest neighbors can be easily found.)

UPDATE with SectorChart

Based on the answer of N.J.Evanns and related comments, here is a grid that combines Chernoff faces and sector charts:

facesGrid =
 Grid[ArrayReshape[#, {3, 4}, ""], Dividers -> All, 
    Alignment -> {Left, Top}] &@
  MapThread[
   (asc = 
      AssociationThread[
       Take[Keys@ChernoffFace["FacePartsProperties"], 
         Length[#3] + 1] -> Append[#3, #4]];
     Grid[{
       {Row[{"row:", #1, ", x=", #2}], SpanFromLeft},
       {ChernoffFace[
         Join[asc, <|
           "FaceColor" -> Blend[{White, Lighter[Yellow]}, #4]|>], 
         ImageSize -> 150, AspectRatio -> Automatic], 
        SectorChart[Transpose@{ConstantArray[1, Length[#3]], #5}]}}]) &
   , {Range[Length[data]], First /@ data, 
    Transpose[Rescale /@ Transpose[Rest /@ data]], 
    PearsonChiSquareTest[Standardize[Rest[#]], 
       NormalDistribution[0, 1]] & /@ data, Rest /@ data}]

enter image description here

$\endgroup$
8
$\begingroup$

A solution for PieChart aficionados:

GraphicsGrid[Partition[
  Table[PieChart[(Rest /@ data)[[i]], 
  ChartLabels -> Placed[Range[8], "RadialOutside"], 
  PlotLabel -> data[[i, 1]]], {i, Length[data[[All, 1]]]}], 4], 
  ImageSize -> 400]

enter image description here

Or, if you are interested in the temporal evolution of each process:

GraphicsGrid[Partition[
  Table[ListLinePlot[
  Transpose[{data[[All, 1]], Transpose[(Rest /@ data)][[i]]}], 
  PlotRange -> {{7, 19}, {0, 20}}, AxesOrigin -> {7, 0}, 
  PlotLabel -> i], {i, Length[(Rest /@ data)[[1]]]}], 4], 
  ImageSize -> 600]

enter image description here

If you want to adjust fonts and their sizes:

GraphicsGrid[Partition[
  Table[PieChart[(Rest /@ data)[[i]], 
  ChartLabels -> 
  Placed[Range[8], "RadialOutside", 
  Style[#, FontFamily -> "Helvetica", 12] &], 
  PlotLabel -> 
  Style[data[[i, 1]], FontFamily -> "Helvetica", 14, Bold]], {i, 
  Length[data[[All, 1]]]}], 4], ImageSize -> 400]

GraphicsGrid[Partition[
  Table[ListLinePlot[
  Transpose[{data[[All, 1]], Transpose[(Rest /@ data)][[i]]}], 
  LabelStyle -> (Directive[FontFamily -> "Helvetica", 12]), 
  PlotRange -> {{7, 19}, {0, 20}}, AxesOrigin -> {7, 0}, 
  PlotLabel -> Style[i, 14, Bold]], {i, 
  Length[(Rest /@ data)[[1]]]}], 4], ImageSize -> 600]
$\endgroup$
2
  • $\begingroup$ Nice approach! Any ideas how to manipulate size/fonts of the Plot and Chart labels? $\endgroup$
    – Vaggelis_Z
    Oct 4, 2013 at 10:07
  • $\begingroup$ @Vaggelis_Z See update. $\endgroup$
    – VLC
    Oct 4, 2013 at 12:18
5
$\begingroup$

Is this helpful?

Grid[Partition[BarChart /@ (Transpose[Thread[{#1, ##2}] & /@ data]), 
  4]]

enter image description here

You could standardize the plot range.

$\endgroup$
4
$\begingroup$

I can't imagine any case where this would be the best option, but no one has mentioned SectorChart yet - where I use equal theta bins, and radius indicates percentage. The only benefit I see is you can compare percentages within a sublist easily.

GraphicsGrid[
 Partition[
  SectorChart[Transpose@{ConstantArray[1, Length@Rest@#], Rest@#}, 
     PlotLabel -> First@#] & /@ data
  , 3
  ]
 ]

enter image description here

$\endgroup$
4
  • $\begingroup$ "I can't imagine any case where this would be the best option [...]" -- It is good (+1). Basically, I would rather use a grid of pie charts than a grid of Chernoff faces. $\endgroup$ Jun 3, 2016 at 17:26
  • 1
    $\begingroup$ It does have the disadvantage of making it very hard to determine how angry your data is though. $\endgroup$
    – N.J.Evans
    Jun 3, 2016 at 17:28
  • $\begingroup$ :) ha-ha -- nice one! $\endgroup$ Jun 3, 2016 at 17:29
  • $\begingroup$ See the update of my answer -- the data can look both angry and sectored. $\endgroup$ Jun 3, 2016 at 18:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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