10
$\begingroup$

I'd like to control more aspects of a DateListPlot, for example: shading for weekend days, and/or indicators for daytime/nighttime areas.

By way of illustration, here's a simple example of a set of time data points (recent questions on mathematica.stackexchange):

questions = 
  First[Rest[
    Import["http://api.stackexchange.com/2.0/questions?page=1&\
pagesize=100&order=desc&sort=creation&site=mathematica", "JSON"]]];

questionTimes = 
  Cases[questions, HoldPattern["creation_date" -> value_] :>  value, 
   Infinity];

hours = (Mod[#, 86400] /86400) 24  & /@ questionTimes ;

DateListPlot[Transpose[{questionTimes, hours}], Filling -> Bottom, 
 GridLines -> False, Frame -> {True, True, False, False}]

and the plot is like this:

stack exchange

I can't see how to show the necessary information along the x-axis, nor how to shade different areas of the graph to show day/night.

Edit: I now realise that the date/times returned by the SE API are in Unix Epoch (1970), and I hadn't noticed because I wasn't able to see the day numbers or years on my first attempt at a plot...

$\endgroup$

2 Answers 2

8
$\begingroup$

Somehow DateListPlot is resistant to many styling options. Without fiddling with the internals, here is a starting point.

WeekendQ[date_] := 
 With[{d = DateString[date, "DayName"]}, 
  MatchQ[d, "Saturday" | "Sunday"]]
weekStyle = {Blue};
weekendStyle = {PointSize -> .015, Directive[Red]};
styleList = 
  Map[If[WeekendQ[#], weekendStyle, weekStyle] &, questionTimes];
DateListPlot[Partition[Transpose[{questionTimes, hours}], 1],
 PlotStyle -> styleList, Filling -> Bottom, GridLines -> False,
 FillingStyle -> ColorData[1][1],
 Frame -> {True, True, False, False},
 PlotRange -> {0, 24}, 
 Prolog -> {LightGray, Rectangle[Scaled[{0, 0}], Scaled[{1, 6/24}]], 
  Rectangle[Scaled[{0, 20/24}], Scaled[{1, 1}]]}]

Looks like:

enter image description here

$\endgroup$
1
  • $\begingroup$ Thanks, this is great! I hadn't made the connection with PlotStyle (still getting used to the wily ways of the Mathematica help) ... Just wondering whether your "May 02" entries are due to the use of Unix Epoch timestamps or different time zones... I'm trying to add "+ AbsoluteTime["January 1, 1970"]" to fix. :) $\endgroup$
    – cormullion
    May 1, 2012 at 16:06
6
$\begingroup$

Here is an alternative approach which uses colour coding of date labels to indicate Weekday/Weekend ( Green/Red ) and colour shade to indicate daytime/nightime ( Lighter/Darker ).

I've dropped some of the points and applied a minimum separation to help make the plot more legible in the limited display space here.

Functions

(* Check for the type of day of the week *)
WeekdayQ[dateString_String] := With[{weekend = {"Sat", "Sun"}}, 
  And @@ (StringFreeQ[dateString, #] & /@ weekend)]

(* Check for time of day, adjust for time of year and location *)
DaytimeQ[dateString_String] := With[{daylight = Range[8, 18]}, 
  MemberQ[daylight, (DateList@dateString)[[4]]]]

(* Apply colour adjustments to date strings to reflect weekday/time *)
ColorizeDate[dateString_String] := Style[dateString, 
  If[DaytimeQ@dateString, Lighter, Darker]@
   If[WeekdayQ@dateString, Darker@Green, Red]]

(* Ease points apart enough to make the text legible  *)
Options[Relax]={MinSeperation->0.03};
Relax[data_,OptionsPattern[]]:=With[{sep=OptionValue@MinSeperation(Max@data-Min@data)},
Flatten[{First@data,First@data +Accumulate[If[#<sep, sep,#]&@Differences@data]}]]

Prep data for plotting

(* points thinned to allow plot to be readable within the online space constraints *)
questionTimes = 
  Reverse@Cases[questions, 
     HoldPattern["creation_date" -> value_] :> value, 
     Infinity][[Select[Range@Length@questions[[2]], OddQ]]];

shift = DateDifference[{1900, 1, 1}, {1970, 1, 1}]*24*60*60;

hours = (Mod[#, 86400]/86400) 24 & /@ questionTimes;

questionData = {ToDate /@ (questionTimes+shift), hours}\[Transpose];

Plot the data

With[{labels = 
   Rotate[ColorizeDate@DateString@#, (3 \[Pi])/2] & /@ questionData[[All, 1]], 
  softCoords = Relax[AbsoluteTime /@ questionData[[All, 1]], MinSeperation -> 0.01]}, 
 ListPlot[{softCoords, questionData[[All, 2]]}\[Transpose], 
  Ticks -> {{softCoords, labels}\[Transpose], Automatic}, 
  Filling -> Axis, AxesOrigin -> {First@softCoords, 0}]]

Mathematica graphics

$\endgroup$
4
  • $\begingroup$ If anyone can work out how to easily extend the colouring to the points and fill lines, I think that would make a nice option. $\endgroup$ May 1, 2012 at 14:04
  • $\begingroup$ coloring the points can be done with PlotStyle. I didn't manage to specify separate filling styles though. $\endgroup$ May 1, 2012 at 14:10
  • $\begingroup$ @image_doctor Thanks, nice solution. I'm currently working out how to make it show today's date... :) $\endgroup$
    – cormullion
    May 1, 2012 at 16:07
  • $\begingroup$ @cormullion How about this: shift = DateDifference[{1900, 1, 1}, {1970, 1, 1}]*24*60*60; Then add that to your time value. $\endgroup$ May 1, 2012 at 16:30

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.