13
$\begingroup$

I am trying to visually compare multiple functions that depend on a single argument running from $0$ to $1$. They describe a radial property and so I thought it would be nice to use a kind of PieChart plot where the function values are used as a color function to fill the pie. The best I could come up with is the following:

 SectorPlot[func_List, label_List, colorrange_: {0, 66.7}, 
  opts : OptionsPattern[]] /; Length[func] == Length[label] := 
 Module[{div, len, sectors, size, wedge, colorbar},
 len = Length[func];
 sectors = makesectors[len];
 size = 300;
 colorbar[colorFunction_: Automatic, range_: colorrange, divs_: 25] :=
 DensityPlot[y, {x, 0, .1}, {y, First@range, Last@range},
 (* Remove possible PlotRange specification from the options, 
 which would mess up the bar*)
 Evaluate[
 FilterRules[{opts}, 
  Cases[Options[DensityPlot], Except[PlotRange -> _]]]],
 AspectRatio -> 10,
 PlotRangePadding -> 0,
 PlotPoints -> {2, divs},
 MaxRecursion -> 0,
 FrameTicks -> {None, Automatic, None, None},
 ColorFunctionScaling -> False,
 ColorFunction -> colorFunction];
 (* now the pie function*)
 wedge[fun_, {minangle_, maxangle_}, lab_] := Show[{
 ParametricPlot[{v Cos[u], v Sin[u]}, {u, minangle, maxangle}, {v,
    0, 1},
  Evaluate[FilterRules[{opts}, Options[ParametricPlot]]], 
  ColorFunction -> (ColorData[{"Rainbow", colorrange}][fun[#4]] &),
  ColorFunctionScaling -> False,
  Mesh -> False,
  ImagePadding -> All,
  BoundaryStyle -> Directive[Thick, Black],
  Frame -> False,
  Axes -> False,
  PlotRange -> {-1.2, 1.2},
  Background -> Transparent],
  Graphics@Text[
   Style[lab, Bold, FontFamily -> "Times"], {
    1.1 Cos[Mean[{minangle, maxangle}]],
    1.1 Sin[Mean[{minangle, maxangle}]]},
   {
    -Cos[Mean[{minangle, maxangle}]],
    -Sin[Mean[{minangle, maxangle}]]}
   ]}];
 Row[{
 Show[Table[
  wedge[func[[i]], sectors[[i]], label[[i]]], {i, 1, len}],
 ImageSize -> {Automatic, size}, 
 ImagePadding -> 20], 
 Show[colorbar[ColorData[{"Rainbow", colorrange}], colorrange], 
 ImageSize -> {Automatic, size}, 
 ImagePadding -> 20]}]]

I used the answers to this post to set up the colorbar in a Row.

Here is an example.

SectorPlot[{
  (60 Sin[4.3 # + 0.3]) &,
  (50 Sin[12 # + 0.1]) &,
  (66 Cos[7.3 # + 0.3]) &,
  (60 Tan[1.2 #]) &,
  (60 Cos[23.5 # - 0.1]) &},
  {"1", "2", "3", "4", "5"}, {0, 70},
  BoundaryStyle -> Directive[Thick, Darker@Gray], 
  PlotRange -> {-1.2, 1.2}]

output

Everything looks OK, but it looks like a lot of effort given the fact that we have very powerful PieChart functionalities. Imagine I have to provide longer labels:

 SectorPlot[{
  (60 Sin[4.3 # + 0.3]) &,
  (50 Sin[12 # + 0.1]) &,
  (66 Cos[7.3 # + 0.3]) &,
  (60 Tan[1.2 #]) &,
  (60 Cos[23.5 # - 0.1]) &},
 {"12345678901234567890", "12345678901234567890", 
  "12345678901234567890", "12345678901234567890", 
  "12345678901234567890"}, {0, 70},
 BoundaryStyle -> Directive[Thick, Darker@Gray], PlotRange -> {-2, 2}]

output

Note the rescaled pie chart. I am sure I could pimp my function a lot more to handle this automatically, all suggestions are welcome. But my main question would be: Is there an easier way that uses the built-in SectorChart, PieChart, etc. commands together with a radial color function? (of course I still need the colorbar.)

$\endgroup$

2 Answers 2

11
$\begingroup$

Your wedge function is a good starting point, and with a few small modifications can be used as a custom ChartElementFunction for PieChart.

wedge[fun_, {minangle_, maxangle_}, colorrange_, divs_: 25] := 
   First[ParametricPlot[
      {v Cos[u], v Sin[u]}, {u, minangle, maxangle}, {v, 0, 1}, 
      ColorFunction -> (ColorData[{"Rainbow", colorrange}][fun[#4]] &), 
      ColorFunctionScaling -> False, Mesh -> False, ImagePadding -> All, 
      BoundaryStyle -> Directive[Thick, Black], Frame -> False, 
      Axes -> False, PlotPoints -> divs, PlotRange -> {-1.2, 1.2}, 
      Background -> Transparent]]

The main differences are that

  • we're using First to extract the main primitives and directives from the plot
  • we've added a divs parameter to allow us to get better resolution of the colors
  • we've removed the text, since we're going to do that differently

(With this approach several of the options (Frame, Axes, etc...) become irrelevant, but I haven't removed them.)

I then split out the colorbar function, mainly to improve the readability of the code. I didn't pass the options through, so it probably lost a small amount of control.

colorbar[colorFunction_, range_, divs_: 25] := 
   DensityPlot[
      y, {x, 0, .1}, {y, First@range, Last@range}, 
      AspectRatio -> 10, PlotRangePadding -> 0, PlotPoints -> {2, divs}, 
      MaxRecursion -> 0, FrameTicks -> {None, Automatic, None, None}, 
      ColorFunctionScaling -> False, ColorFunction -> colorFunction]

Now we come to the main SectorPlot.

SectorPlot[func_List, label_List, colorrange_: {0, 66.7}, 
   opts:OptionsPattern[]] /; Length[func] == Length[label] := 
   Module[{div, size},
      size = 300;
      Row[{
         PieChart[Table[1 -> f, {f, func}], 
            ChartLabels -> Placed[label, "RadialCallout", 
               Style[#, Bold, FontFamily -> "Times"] &], 
            ChartElementFunction -> (wedge[First[#3], First[#1], colorrange, 50] &), 
            ImageSize -> {Automatic, size}, ImagePadding -> 20], 
         Show[colorbar[ColorData[{"Rainbow", colorrange}], colorrange], 
            ImageSize -> {Automatic, size}, ImagePadding -> 20]
          }]
       ]

The main things to note here:

  • we use -> to assign the functions as metadata for the (constant-size) sectors
  • we use ChartLabels and Placed for the sector labels, which provides easy access to several built-in label locations
  • when we call wedge as a ChartElementFunction
    • First[#1] is the angle range for the sector
    • #3 contains a list of all metadata for a sector, we extract the function with First

Here's the final result:

SectorPlot[
   {(60 Sin[4.3 # + 0.3]) &, 
    (50 Sin[12 # + 0.1]) &, 
    (66 Cos[7.3 # + 0.3]) &, 
    (60 Tan[1.2 #]) &, 
    (60 Cos[23.5 # - 0.1]) &}, 
   {"1", "2", "3", "4", "5"}, 
   {0, 70}]

enter image description here

(As a note, really big labels are generally problematic, especially inside Graphics which have a constrained size.)

$\endgroup$
1
  • 1
    $\begingroup$ Cool! Exactly what I was looking for! How would I have to modify the wedge function if I want to allow for unequal radii, like in SectorChart? $\endgroup$ Apr 12, 2012 at 8:15
2
$\begingroup$

An alternative is to use the built-in ChartElementFunction "GradientSector" with appropriate setting for the option "ColorScheme".

The function ceF below uses the arguments (colorrange, gradient, direction) and the associated function (passed as metadata) to produce the value for the option "ColorScheme".

ClearAll[ceF, sectorPlot]
ceF[colorrange_: {0, 70}, gradient_: "Rainbow", direction_: "Radial"] := 
 Module[{colors = Table[ColorData[{gradient, colorrange}]@First[#3][i], {i, 0, 1, 1/20}]},
   ChartElementDataFunction["GradientSector", "ColorScheme" -> colors, 
      "GradientDirection" -> direction][##]] &;

sectorPlot[funcs_, labels_, colorrange_: {0, 70}, gradient_: "Rainbow", 
  direction_: "Radial", o : OptionsPattern[]] :=
 PieChart[Thread[1 -> funcs], 
  ChartLabels -> Placed[labels, "RadialCallout", Style[#, 18, "Panel"] &], 
  ChartElementFunction -> ceF[colorrange, gradient, direction], o, 
  ImageSize -> 500, ChartLegends -> BarLegend[{grad, colorrange}]]

Example:

funcs = {(60 Sin[4.3 # + 0.3]) &, (50 Sin[12 # + 0.1]) &, (66 Cos[
       7.3 # + 0.3]) &, (60 Tan[1.2 #]) &, (60 Cos[23.5 # - 0.1]) &};
sectorPlot[funcs, {"1", "2", "3", "4", "5"}]

enter image description here

sectorPlot[funcs, {"1", "2", "3", "4", "5"}, {0, 70}, "TemperatureMap", "DescendingRadial",
 SectorOrigin -> {Automatic, 1}]

enter image description here

$\endgroup$

Your Answer

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

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