DateHistogram FrameLabel overlaps FrameTicks

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


How about

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

as a simple work-around? Produces

histogram


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