5
$\begingroup$

I have this data:

data =
  {{{2015, 3, 25}, 130}, {{2015, 3, 26}, 132}, {{2015, 3, 27}, 
    132}, {{2015, 3, 30}, 133}, {{2015, 3, 31}, 132}, {{2015, 4, 1}, 
    131}, {{2015, 4, 2}, 131}, {{2015, 4, 3}, 131}, {{2015, 4, 6}, 
    131}, {{2015, 4, 7}, 131}, {{2015, 4, 8}, 129}, {{2015, 4, 9}, 
    132}, {{2015, 4, 10}, 133}, {{2015, 4, 13}, 132}, {{2015, 4, 14}, 
    131}, {{2015, 4, 15}, 131}, {{2015, 4, 16}, 128}, {{2015, 4, 17}, 
    125}, {{2015, 4, 20}, 127}, {{2015, 4, 21}, 127}};

I want to produce with DateListPlot an image almost like this one:

enter image description here

Almost? If there are more than one maxima or minima only the first point should be plotted.

In reality my data is much longer.

What could an elegant and efficient answer look like?

$\endgroup$
8
$\begingroup$

Perhaps a bit more elegant than Sjoerd's approach:

data = Sort @ data;   (* address Sjoerd's concern *)

pts = {
   data,
   MinimalBy[data, Last, 1],
   MaximalBy[data, Last, 1]
 };

DateListPlot[pts,
  Joined    -> {True, False, False}, 
  PlotStyle -> {Automatic, Red, Green}
]

enter image description here

$\endgroup$
  • $\begingroup$ Certainly a highly fashionable answer :) $\endgroup$ – eldo Apr 22 '15 at 16:21
  • $\begingroup$ Does this guarantee that you always pick the first peak if there are ties and data isn't ordered? $\endgroup$ – Sjoerd C. de Vries Apr 22 '15 at 22:18
  • $\begingroup$ @Sjoerd The data appeared to be ordered. Sort it if it is not. $\endgroup$ – Mr.Wizard Apr 22 '15 at 22:36
  • $\begingroup$ That's what I did already. The data given is just an example. Just wanted to point out that you have an implicit and unwarranted assumption in your approach. $\endgroup$ – Sjoerd C. de Vries Apr 22 '15 at 22:45
  • $\begingroup$ @Sjoerd I added a sort to my code. $\endgroup$ – Mr.Wizard Apr 22 '15 at 23:06
4
$\begingroup$

Haven't aimed for efficiency or elegance but for 'straightforwardness'

data = Sort@data; (* just to make sure the dates are always sorted *)

max = Max@data[[All, 2]];
min = Min@data[[All, 2]];
maxPos = FirstPosition[data[[All, 2]], max] // First;
minPos = FirstPosition[data[[All, 2]], min] // First;

maxPlotPos = MapAt[AbsoluteTime, data[[maxPos]], 1];
minPlotPos = MapAt[AbsoluteTime, data[[minPos]], 1];

DateListPlot[data, 
 Epilog -> {Green, PointSize[.02], Point@maxPlotPos, Red, Point@minPlotPos}]

Mathematica graphics

$\endgroup$
4
$\begingroup$

Lest we forget the old-fashined ways:

extremes=data[[Ordering[# data[[All,2]],1][[1]]&/@{-1,1}]];

DateListPlot[{data,##&@@(List/@extremes)},
 Joined -> {True,False,False}, BaseStyle -> PointSize[Large],
 PlotStyle -> {Gray,Red, Green}, PlotLegends -> {"data", "max","min"}]

enter image description here

Note: If data is not sorted, we need to sort it first (*thanks: @Sjoerd *):

data = data[[Ordering[data]]];
extremes = data[[Ordering[# data[[All, 2]], 1][[1]] & /@ {-1, 1}]];
$\endgroup$
  • $\begingroup$ I have always liked your styles: ##&@@ is extremely nice :) $\endgroup$ – eldo Apr 22 '15 at 19:04
  • 1
    $\begingroup$ Thank you @eldo. I think i learned it from Mr.W. $\endgroup$ – kglr Apr 22 '15 at 20:04
  • $\begingroup$ Does this guarantee that you always pick the first peak if there are ties and data isn't ordered? $\endgroup$ – Sjoerd C. de Vries Apr 22 '15 at 22:17
  • $\begingroup$ Yes, I am fairly sure I am the one who infected you. :o) $\endgroup$ – Mr.Wizard Apr 22 '15 at 22:37
  • $\begingroup$ @SjoerdC.deVries, good point; it doesn't. So, that gives us another chance to use Ordering:) $\endgroup$ – kglr Apr 22 '15 at 22:52
3
$\begingroup$

Do you care about maxima and minima or peaks? If peaks then you could use FindPeaks but this is only available for M10+. Note also that FindPeaks only handles regularly spaced TimeSeries - hence the use of TemporalRegularity:

data = TimeSeries[{{{2015, 3, 25}, 130}, {{2015, 3, 26}, 
 132}, {{2015, 3, 27}, 132}, {{2015, 3, 30}, 133}, {{2015, 3, 31},
  132}, {{2015, 4, 1}, 131}, {{2015, 4, 2}, 131}, {{2015, 4, 3}, 
 131}, {{2015, 4, 6}, 131}, {{2015, 4, 7}, 131}, {{2015, 4, 8}, 
 129}, {{2015, 4, 9}, 132}, {{2015, 4, 10}, 133}, {{2015, 4, 13}, 
 132}, {{2015, 4, 14}, 131}, {{2015, 4, 15}, 131}, {{2015, 4, 16},
  128}, {{2015, 4, 17}, 125}, {{2015, 4, 20}, 
 127}, {{2015, 4, 21}, 127}}, TemporalRegularity -> True];
DateListPlot[{data, FindPeaks[data], 
TimeSeriesMap[#*-1 &, FindPeaks[TimeSeriesMap[#*-1 &, data]]]}, 
Joined -> {True, False, False}]

enter image description here

$\endgroup$
  • $\begingroup$ I think this is expressly not what eldo requested but since you just introduced me to TemporalRegularity here is my +1. $\endgroup$ – Mr.Wizard Apr 22 '15 at 17:00
  • $\begingroup$ Right, I was not looking for peaks.+1 for the reason given by wiz. I will play with TemporalRegularity tomorrow :) $\endgroup$ – eldo Apr 22 '15 at 17:26
  • $\begingroup$ @eldo I did push the Almost? in your question a bit far, but I decided to try and break 1000 before midnight and needed all the awkwardly placed fruit I could find. Strange to see TemporalRegularity is only mentioned three times on MMA.SE, glad to have given you something to play with though. $\endgroup$ – Martin John Hadley Apr 22 '15 at 19:57
  • 1
    $\begingroup$ Well, you hit it !!! $\endgroup$ – eldo Apr 22 '15 at 20:24

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.