17
$\begingroup$

I'm trying to create a chart usually called "Helio chart". It's a chart type very suited for canonical correlation analysis involving several dependent and independent variables.

However, it is a little bit difficult to find good examples of for this chart on the web and the best example I have can be found on the 6th page of this paper on the NASA website:

http://ti.arc.nasa.gov/m/profile/adegani/Canonical%20Correlation.pdf

It is possible to create such a chart in Mathematica?

enter image description here

$\endgroup$
2
  • $\begingroup$ Starting from what input? $\endgroup$ Mar 7, 2013 at 17:04
  • 2
    $\begingroup$ Here's a start for implementing this from scratch, using graphics primitives: Manipulate[ Graphics[{Rotate[ Translate[ Scale[Rectangle[{-1, 0}, {1, 2}], .1 {1, l}, {0, 0}], {0, t}], r, {0, 0}], {Red, PointSize[Large], Point[{0, 0}]}}, Frame -> True, AspectRatio -> Automatic, PlotRange -> 3 {{-1, 1}, {-1, 1}}], {r, 0, 2 \[Pi]}, {{l, 1}, -5, 5}, {{t, 1}, 0.2, 2}] $\endgroup$
    – Szabolcs
    Mar 7, 2013 at 17:13

2 Answers 2

24
$\begingroup$

Here's some code that could help you to start:

sample data:

data = RandomReal[{-1, 1}, 30];

plot:

angleBar[max_, length_: .1][{{t0_, t1_}, {r0_, r1_}}, v_, meta_] :=
    Block[{angle, coords, x, y},
        angle = t0 + (t1 - t0)/2;
        coords = {Cos[angle], Sin[angle]};
        x = r0 coords;
        y = r1 coords;
        {{Gray, Dashed, Line[{x, y}]}, 
        {Black, If[meta[[1]] > 0, EdgeForm[],FaceForm[White]], 
          Translate[
            Rotate[Scale[
              Rectangle[{0, -.5}, {1, .5}], { meta[[1]]/max, length}, {0, 
          0}], angle, {0, 0}], x]} }
];

newdata = 1 -> # & /@ data;
max = Max[Abs[data]];
PieChart[newdata, ChartElementFunction -> angleBar[1.3 max, .1], 
   SectorOrigin -> {Automatic, 1.5}, 
   PolarGridLines -> {None, {0, 1.5}}, PerformanceGoal -> "Speed"]

enter image description here

I added names and grouping.

angleBarName[max_, length_: .1][{{t0_, t1_}, {r0_, r1_}}, v_, meta_] :=
     Block[{angle, coords, x, y, tangle, offset},
         angle = t0 + (t1 - t0)/2;
         coords = {Cos[angle], Sin[angle]};
         x = r0 coords;
         y = r1 coords;
         If[Pi/2 <= Mod[angle, 2 Pi] <= 3/2 Pi, tangle = angle + Pi; 
            offset = {1, 0}, tangle = angle; offset = {-1, 0}];
         {{Gray, Dashed, Line[{x, 1.2 y}]}, {Black, 
          If[meta[[1, 1]] > 0, EdgeForm[], FaceForm[White]], 
          Translate[
            Rotate[Scale[
               Rectangle[{0, -.5}, {1, .5}], {meta[[1, 1]]/max, length}, {0, 
               0}], angle, {0, 0}], x]},
               Translate[
               Rotate[Text[Style[meta[[1, 2]], "Title", 10, Black], {0, 0}, 
               offset], tangle, {0, 0}], 2.1 x]}];

angleBarName[max_, length_: .1][{{t0_, t1_}, {r0_, r1_}},v_, {{"Group", msize_}}] :=
       Block[{angle, end, start, offset},
          If[v == msize, {},
           offset = (t1 - t0)/(v/msize *2);
           start = {Cos[t0 + offset], Sin[t0 + offset]};
           end = {Cos[t1 - offset], Sin[t1 - offset]};
           {Black, Thick, Line[{2.7 start, 3 start}], 
           Line[{2.7 end, 3 end}], 
           Circle[{0, 0}, 2.7, {t0 + offset, t1 - offset}]}]];

angleBarName[max_, length_: .1][{{t0_, t1_}, {r0_, r1_}}, v_, {"LineBreaker"}]:= {}

Sample data with names and grouping:

data = Transpose[{RandomReal[{-2, 2}, 30], ChemicalData[][[;; 30]]}];
max = Max[Abs[data[[All, 1]]]];
getherdata = GatherBy[data, StringTake[#[[2]], 1] &];
gdata = Length[#] -> {"Group",1} & /@ getherdata;
newdata = 1 -> # & /@ Flatten[getherdata, 1];

Chart:

PieChart[{newdata, gdata}, 
  ChartElementFunction -> angleBarName[1.1 max, .1], 
  SectorOrigin -> {{Pi/2, "Clockwise"}, 1.5}, 
  PolarGridLines -> {None, {1.5}}, PerformanceGoal -> "Speed", 
  PlotRange -> All]

enter image description here

I edited code to give space in the middle. To do that, I assumed the given data already separated into two part.

filterData[data_] :=
  Block[{fdata, size},
    fdata = Flatten[data, 1];
    size = 1/Length[fdata];
    {Join[{.005 -> "LineBreaker"}, 
           size -> # & /@ fdata, {.005 -> "LineBreaker"}], 
     Join[{.005 -> 
         "LineBreaker"}, (size Length[#]) -> {"Group", size} & /@ 
     data, {.005 -> "LineBreaker"}]}
]

sample data:

data = Transpose[{RandomReal[{-2, 2}, 22], ChemicalData[][[;; 22]]}];
ldata = GatherBy[data[[;; 7]], StringTake[#[[2]], 1] &];
rdata = GatherBy[data[[8 ;;]], StringTake[#[[2]], 1] &];

draw chart:

max = Max[Abs[ldata[[All, 1, 1]]], Abs[rdata[[All, 1, 1]]]];
newdata = MapThread[Join, {filterData[rdata], filterData[ldata]}];
PieChart[newdata, ChartElementFunction -> angleBarName[1.2 max, .1], 
   SectorOrigin -> {{Pi/2, "Clockwise"}, 1.5}, 
   PolarGridLines -> {None, {1.5}}, PerformanceGoal -> "Speed", 
   PlotRange -> All, 
   Epilog -> {Orange, Thick, Line[{{0, -4.5}, {0, 4.5}}]}]

enter image description here

$\endgroup$
6
  • 2
    $\begingroup$ +1, for convincing PieChart to do the work for you. $\endgroup$
    – rcollyer
    Mar 7, 2013 at 18:42
  • $\begingroup$ Well, this option is more similiar to the original Helio chart... however, it would be interesting to have the names plotted in the chart as well. It would be much more interesting to "divide" the names into categories, just like the original chart... $\endgroup$
    – Rod
    Mar 7, 2013 at 18:47
  • $\begingroup$ Another useful comment: there shouldn't be bars in the middle of the circle, because both circle parts should be splitted in the middle by a vertical thin line... $\endgroup$
    – Rod
    Mar 7, 2013 at 18:52
  • $\begingroup$ One more thing would be interesting to add: sometimes we have different numbers of dependent and independent variables... how could I change the chart to have, like, 7 variables on the left side and 15 variables on the right side? $\endgroup$
    – Rod
    Mar 7, 2013 at 23:08
  • 1
    $\begingroup$ Simply fantastic!!! Great job! $\endgroup$
    – Rod
    Mar 8, 2013 at 0:16
4
$\begingroup$

Here is a start:

out = Table[{i, RandomReal[{-1, 1}]}, {i, 0, 2 Pi - 2 Pi/20, 2 Pi/20}];
Graphics[{White, EdgeForm[Directive[Black]], Disk[],
  {If[#[[2]] > 0, White, Black], 
     GeometricTransformation[ Rectangle[{0, 0}, {#[[2]] .5, .1}], 
                         {RotationMatrix[#[[1]]], {Cos[#[[1]]], Sin[#][[1]]}}]} & /@ out}]

Mathematica graphics

$\endgroup$
3
  • $\begingroup$ Nice.. I have made some tests with SectorChart, but it does not accept negative second arguments. +1 $\endgroup$
    – Murta
    Mar 7, 2013 at 17:45
  • 1
    $\begingroup$ Didn't you make a prototype of a similar complicated radial chart on SO? $\endgroup$
    – rm -rf
    Mar 7, 2013 at 17:52
  • 1
    $\begingroup$ @rm-rf My programming abilities are as bad as my memory $\endgroup$ Mar 7, 2013 at 17:52

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.