13

In the course of exploring @kglr's answer to Edmund's question gain some insight into how I might answer my own question here, I came across the undocumented System`ChartElementData function, which evidently allows you to map the strings passed as options to ChartElementFunction to the actual functions which draw the elements. Thus, using the calling convention described for BoxChart in the docs for ChartElementFunction, you can do the following:

In[1]:= cfd = ChartElementData["Rectangle"]
Out[1]= ChartElementDataFunction["Rectangle"]

In[2]:= cfd[{{0, 1}, {0, 1}}, 1, "foo"]
Out[2]= Rectangle[{0, 0}, {1, 1}, "RoundingRadius" -> 0]

That's pretty neat. However, you can also find out that there are many applicable, named, ChartElementDataFunctions for any given chart type:

In[3]:= ChartElementData["BarChart"]
Out[3]= {"ArrowRectangle", "EdgeFadingRectangle", "FadingRectangle", 
         "GlassRectangle", "GradientRectangle", "GradientScaleRectangle", 
         "ObliqueRectangle", "Rectangle", "SegmentScaleRectangle"}

Looking at some output, I'm pretty sure that "Rectangle" is the default for BarChart, but I'm not 100% certain, and it would be nice to avoid having to do trial and error for every bar type should I wish to discover the default. Is there a way to find, programmatically, what ChartElementDataFunction is used by any given chart type when it's passed ChartElementFunction -> Automatic?

J. M.'s missing motivation
  • 124,525
  • 11
  • 401
  • 574
Pillsy
  • 18,498
  • 2
  • 46
  • 92
  • 4
    TracePrint[(* charting function *), ChartElementDataFunction[_], TraceInternal -> True] quickly reveals not a few secrets. – J. M.'s missing motivation Nov 12 '15 at 05:16
  • 1
    @J.M., if you don't write that up as an answer, how am I supposed to give you your bounty? :) – Pillsy Nov 12 '15 at 05:20
  • It doesn't always work, you see: TracePrint[PieChart3D[{1, 2, 3, 4}, PlotTheme -> "Marketing"], ChartElementDataFunction[_], TraceInternal -> True] so I left it as a comment. – J. M.'s missing motivation Nov 12 '15 at 05:23
  • @J.M. Got it. Still a good start, though. – Pillsy Nov 12 '15 at 05:24
  • 1
    For "Marketing", this works: ChartElementFunction /. Charting`ResolvePlotTheme["Marketing", BarChart3D]. For some of the other plot themes this doesn't work, but the previously presented approach works. I don't know if there's a situation where neither will work, but this at least reveals some inconsistency in internal handling. – J. M.'s missing motivation Nov 12 '15 at 05:36

2 Answers2

4

Some ChartElementDataFunctions have options and some plot themes (namely, "Business", "Marketing" and "Monochrome") use these options. So, the pattern we need to use in the second argument of Trace is ChartElementDataFunction[__]. With this small change we can use J.M.'s suggested approach to discover the default ChartElementFunction for every pairing of charting functions and plot themes.

ClearAll[traceCEF]
traceCEF[th_] := Last[Flatten @
  Trace[#[If[# === PairedBarChart, ## & @@ #2, #2], PlotTheme -> th], 
        ChartElementDataFunction[__], TraceInternal -> True]] /. 
     HoldPattern[ChartElementDataFunction[b__][__] | 
        ChartElementDataFunction[b__]] :> Column[{b}] &;

themes = {Automatic, "Business", "Marketing", "Monochrome"};

charts = {BarChart, BarChart3D, BoxWhiskerChart, BubbleChart, 
   BubbleChart3D, DistributionChart, GeoBubbleChart, PairedBarChart, 
   PieChart, PieChart3D, RectangleChart, RectangleChart3D, 
   SectorChart, SectorChart3D};

simpleinput = {{1, 2, 3}, {1, 2, 3}, {1, 2, 3}, 
   Partition[Range@6, 3], Partition[Range@8, 4], {1, 2, 3}, 
   {GeoPosition[{1, 1}] -> 1, GeoPosition[{2, 2}] -> 2}, 
   Partition[Range@6, 3], {1, 2, 3}, {1, 2, 3}, Partition[Range@6, 2],
   Partition[Range@6, 3], Partition[Range@6, 2], Partition[Range@6, 3]};

grid = Join[{Join[Item[Style[#, 14], Background -> LightBlue] & /@ {"function", 
       "PlotTheme"}, {SpanFromLeft, SpanFromLeft, SpanFromLeft}]}, 
    {Prepend[Item[Style[#, 14], Background -> LightBlue] & /@ themes, SpanFromAbove]}, 
   MapThread[Prepend[Table[traceCEF[t][##], {t, themes}], 
      Item[Style[#, 14], Background -> LightBlue]] &, 
     {charts, simpleinput}]];

Grid[grid, Dividers -> {{True, True, {False}, True}, All}, 
 Alignment -> {Left, Center, {{1, 2} -> Center}}]

enter image description here

The other themes

themes = Prepend[Complement["Base" /. Charting`$PlotThemes, 
   {"Business", "Marketing",  "Monochrome"}], Automatic]
 {Automatic, "Classic", "Detailed", "Minimal", "Scientific", "Web"}

use the same ChartElementFunction for each charting function:

enter image description here

kglr
  • 394,356
  • 18
  • 477
  • 896
0

This is what AbsoluteOptions is for, but it actually doesn't work for me (v11.2), even though the doc states:

gives the absolute settings of options specified in an expression such as a graphics object.

Your question should be answered by:

AbsoluteOptions[
    BarChart[...],
    ChartElementFunction
 ]
Anti Earth
  • 1,211
  • 6
  • 13