7
$\begingroup$

Bug introduced in 11.3 or earlier and persisting through 12.0.0


d1 = {DateObject[{2010, 10, 4}], DateObject[{2019, 2, 25}]};

d2 = {DateObject[{2000, 1, 1}], DateObject[{2018, 9, 4}]};

DateHistogram[d1, "Year", FrameLabel -> {"Year"}, PlotLabel -> "M", Frame -> True]

The FrameLabel "Year" overlaps the FrameTicks values

enter image description here

Happens when the date format of the ticks is YYYY. If the range of years is expanded, the format is MM/DD/YY and there is no overlap.

DateHistogram[d2, "Year", FrameLabel -> {"Year"}, PlotLabel -> "M", Frame -> True]

enter image description here

This looks like a bug in both 11.3 and 12.0. I have reported it to WRI. Will update when I hear back.

Any suggestions for workarounds, apart from using Labeled rather than FrameLabel and PlotLabel?

Update 2019-04-22

WRI has confirmed that this is a bug. CASE:4248494

They suggested this workaround that uses PlotRangePadding. Apart from the poor aesthetics, it will also require the padding to be adjusted unless the same date format is used for both cases.

DateHistogram[d1, "Year", 
 DateTicksFormat -> {"MonthNameShort", " ", "YearShort"}, 
 FrameLabel -> {"Year"}, Frame -> True, 
 PlotRangePadding -> {Automatic, Scaled[0.15]}]

enter image description here

$\endgroup$
4
$\begingroup$

DateHistogram has two kinds of frame ticks: ordinary ticks and categorical ticks. Ordinary ticks are those that are created by the FrameTicks option, while categorical ticks are actually included as graphics primitives. This is why the categorical ticks have a clashing frame label. Let's use TracePrint to see the internal call to Histogram:

TracePrint[
    DateHistogram[d1,"Year",FrameLabel->{"Year"},PlotLabel->"M",Frame->True],
    _Histogram
];

Histogram[System`TimeVisualizationsDump`modelData\$2871[WrappedValues],System`TimeVisualizationsDump`timebinning\$2871,Automatic,System`TimeVisualizationsDump`opts\$2871]

Histogram[{3495139200,3760041600},{{3471292800,3502828800,3534364800,3565987200,3597523200,3629059200,3660595200,3692217600,3723753600,3755289600,3786825600}},Automatic,{Axes->{False,True},ChartLabels->{None,None},Frame->True,FrameLabel->{Year},FrameTicks->{{Automatic,Automatic},{None,Automatic}},GridLines->{None,None},PlotLabel->M,PlotRange->{{Automatic,Automatic},{Automatic,Automatic}}}]

Notice that the FrameTicks option is:

FrameTicks -> {{Automatic, Automatic}, {None, Automatic}}

The option suppresses any frame ticks on the bottom frame so that the categorical "ticks", which are actually graphics primitives can be shown.

So, what can be done to fix this? One possibility is to have DateHistogram use FrameTicks of the form:

FrameTicks -> {
    {Automatic, Automatic},
    {{{Median[AbsoluteTime /@ d1], Style["1", FontOpacity->0]}}, Automatic}
}

when calling Histogram, so that an invisible tick is placed in the middle of the bottom frame, causing the frame label to be lowered to accommodate it. I will do this by adding some conditioned downvalues to DateHistogram and Histogram.

To do this it will be convenient to use my Initial function (which I reproduce below) to insert these new DownValues at the beginning:

Initial /: Verbatim[TagSetDelayed][Initial[sym_], lhs_, rhs_] := With[
    {
    new=Block[{sym},
        TagSetDelayed[sym,lhs,rhs];
        First @ Language`ExtendedDefinition[sym]
    ],
    protect=Unprotect[sym]
    },

    sym;
    Quiet@MakeBoxes[sym[],TraditionalForm];

    Unprotect[sym];
    Replace[
        new,
        Rule[values_,n:Except[{}]] :> (
            values[sym] = DeleteDuplicates @ Join[n, values[sym]]
        ),
        {2}
    ];
    Protect@protect;
]

The new DownValues:

Initial[Histogram] /: Histogram[v_, b_, h_, o:OptionsPattern[]] /; TrueQ @ $FixH := 
Block[{$FixH = False},
    If[MatchQ[OptionValue[FrameTicks], {{Automatic,Automatic},{None, Automatic}}],
        Histogram[
            v, b, h,
            FrameTicks -> {
                {Automatic, Automatic},
                {{{Median[v], Style["1", FontOpacity->0]}}, Automatic}
            },
            o
        ],
        Histogram[v, b, h, o]
    ]
]

Initial[DateHistogram] /: DateHistogram[a__] /; !TrueQ @ $FixDH := Block[
    {$FixH = True, $FixDH = True},

    DateHistogram[a]
]

Test:

DateHistogram[d1, "Year", FrameLabel->{"Year"}, PlotLabel->"M", Frame->True]

enter image description here

DateHistogram[d2, "Year", FrameLabel->{"Year"}, PlotLabel->"M", Frame->True]

enter image description here

$\endgroup$
  • $\begingroup$ This answer has the same issue as the answer from @m_goldberg. I experimented with various options and positions for Pane, but was unable to get the distance between the axis and the label to match in both cases using identical options and positions. Seems like there is no way to position relative to the baseline of the tick values. $\endgroup$ – Rohit Namjoshi Apr 18 at 0:04
  • $\begingroup$ Nice. Should this be something that is done automatically by Mma? $\endgroup$ – Mike Honeychurch Apr 18 at 23:18
  • $\begingroup$ Perfect. Thanks Carl. It is going to take me a while to understand how this works. $\endgroup$ – Rohit Namjoshi Apr 22 at 23:58
2
$\begingroup$

How about

DateHistogram[d1, "Year",
 FrameLabel -> {"\nYear"},
 PlotLabel -> "M",
 Frame -> True]

as a simple work-around? Produces

histogram

$\endgroup$
  • $\begingroup$ I have several DateHistogram's with varying date ranges that I am displaying in a grid. Apologies for not mentioning that in my question. This answer works well for the case when there is overlap, when there is not, the label is too far from the axis and that is very obvious in the grid. I suppose I could conditionally add the newline based on the number of bins. $\endgroup$ – Rohit Namjoshi Apr 17 at 23:49
2
$\begingroup$

If the other two answers are not satisfactory maybe try using adjustment boxes, but that might lead to the same issue. I suspect you might need to make your final code conditional to meet your requirements

DateHistogram[d1, "Year", 
 FrameLabel -> {DisplayForm@
    AdjustmentBox["Year", BoxBaselineShift -> 0, 
     BoxMargins -> {{0, 0}, {0, 1.5}}]}, PlotLabel -> "M", 
 Frame -> True]

enter image description here

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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