11

Let's say I have two samples:

data1 = RandomChoice[DateRange[{2010, 1, 1}, {2010, 4, 31}, "Day"], 100];
data2 = RandomChoice[DateRange[{2010, 5, 1}, {2010, 8, 31}, "Day"], 100];

I want to plot a histogram with both of them, and I want data2's bars to have Dotted or Dashed EdgeForm depending of a value of some variable, let's say t.

Problems with available styling options:

  • Dynamic @ DateHistogram[...], recreating it will be too slow for bigger samples.

  • ChartStyle can't be Dynamic or contain it in a list. It can have Directives but they can't contain Dynamic either so it won't work as a wrapper.

  • ChartElementFunction does not allow to distinguish data samples.

  • Histogram* allows certain wrappers for data, e.g. Style: Style[data2, Orange] but it won't allow Dynamic inside

The only way I was able to use is a hairy postprocessing:

t = True; Checkbox @ Dynamic @ t

DateHistogram[
    {data1, data2}, ChartStyle -> {Green, Red} 
] /. d_Directive :> Which[
   MemberQ[d, Red, ∞], 
   Dynamic[
     Directive[##, EdgeForm[If[TrueQ[t], Dashed, Dotted]]]
   ] & @@ d
   ,
   True, 
   d
]

enter image description here

Is there a more stable/generic way to achieve this?

Kuba
  • 136,707
  • 13
  • 279
  • 740

4 Answers4

3

A better post-processing approach

You can use Annotation (or Hyperlink or Button) as a wrapper for the data with a tag as the second argument for simplification of the post-processing:

DateHistogram[{data1, Annotation[data2, myTag]}] /. 
 Annotation[d_, myTag] :> Sequence[Dynamic[EdgeForm[If[TrueQ[t], Dashed, Dotted]]], d]

This is much simpler and more stable/generic than the method shown in the question, but it still depends on the specifics of the current implementation of DateHistogram.


A hackish solution

Another way is to fool the internal check for validness of style directives by wrapping the tag with Glow (other possibilities: Specularity, RGBColor, Opacity, GrayLevel; checked with Mathematica 11.0.0):

DateHistogram[{data1, data2}, ChartStyle -> {Green, Glow[myTag]}] /. 
 d_Directive /; MemberQ[d, Glow[myTag], ∞] :> 
  Sequence[d /. Glow[myTag] :> {}, Dynamic[EdgeForm[If[TrueQ[t], Dashed, Dotted]]]]

Shorter version:

DateHistogram[{data1, Style[data2, Glow[myTag]]}] /. 
 Directive[Glow[myTag]] :> Dynamic[EdgeForm[If[TrueQ[t], Dashed, Dotted]]]

Of course this method potentially can be broken in future if there will be introduced a check for validness of arguments of Glow etc. Hence the method shown in the previous section is preferable.

Alexey Popkov
  • 61,809
  • 7
  • 149
  • 368
2

A worse post-processing approach

I messed around with this for a while and this is the best I could do.

data = RandomVariate[NormalDistribution[#, 3], 100] & /@ {-1, 5};

t = True; Checkbox@Dynamic@t

MapAt[
  # /. _FEPrivate`If :> EdgeForm[If[t, Dashed, Dotted]] &,
  Histogram[data, ChartStyle -> {Green, Red}],
  {1, 1, 2, 2}
]

The second 2 in {1, 1, 2, 2} may be changed to target the styling. Hey, I said it was worse. :^)

YAPPM

(Yet another post-processing method.) The same thing you did but less focused.

Histogram[data, ChartStyle -> {Green, Red}] /.
  x_Directive :> Dynamic[x] /. 
    x : Red :> {x, EdgeForm[If[t, Dashed, Dotted]]}
Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
  • Look out for PerformanceGoal -> "Speed" too. – Kuba Aug 18 '16 at 13:26
  • @Kuba Yes, I'm sure this is quite fragile. :-( – Mr.Wizard Aug 18 '16 at 13:26
  • 1
    @Mr.Wizard Thank you for posting this answer! I won't upvote it but I express thanks because I was much wondered whether there is a straightforward way to solve this problem. Now I'm sure there is no way and the reason is clear: Directive doesn't accept Dynamic style directives. But WHY? I don't see any reason for this! – Alexey Popkov Aug 18 '16 at 13:48
  • 1
    @Alexey I don't know; it doesn't seem to be easy to get an answer to questions like that. I am glad you found something in this answer useful; I regularly find your answers quite enlightening. – Mr.Wizard Aug 18 '16 at 13:57
2

You could specify the low-level parameter of the Dashing:

t = Small;
Checkbox[Dynamic[t], {Small, 0}]
DateHistogram[{data1, 
  Style[data2, EdgeForm[Dashing[{Dynamic@t, Small}]]]}]
Basheer Algohi
  • 19,917
  • 1
  • 31
  • 78
1

You may apply Dynamic to the entire DateHistogram.

Checkbox[Dynamic@t, {Dashed, Dotted}]

Then

Dynamic@DateHistogram[{data1, data2}, 
  ChartStyle -> {Green, Directive@{Red, EdgeForm[t]}}]

Hope this helps.

Edmund
  • 42,267
  • 3
  • 51
  • 143
  • 1
    +1 For simple cases it is a good solution I forgot to mention but I came here because it was not enough for large datasets. Recalculating whole plot takes to much time then. – Kuba Aug 19 '16 at 05:26