5
$\begingroup$

I've been using a DateList plot to visualise property information but I don't think it's the best way display my data. My data is formatted as {time (hours), property} where property is an integer between 1 and 20

data = {{0, 0}, {0.2187, 3}, {0.25, 1}, {0.3715, 15}, {0.868, 
1}, {1.261, 15}, {1.4595, 1}, {1.583, 15}, {2.088, 1}, {2.35, 
0}, {2.57, 1}, {3., 0}, {4., 1}, {5.226, 0}, {8.537, 1}, {10, 
0}, {11.1359, 1}, {13, 0}, {14, 1}, {14.11, 16}}

DateListPlot[data]

I would like to use something like an ArrayPlot but instead of having constant width the width of the bars would be dependent on the time in my data. The colour of the bar would be dependent on the property value. Similar to this plot but instead of having % it would have date;

enter image description here

My data is generally thousands of rows. I use manipulate to present a subset (window) of a couple of months of data which I can move through. I bring this up because any solution will have to be able to handle larger data sets than I have supplied in this question.

$\endgroup$
  • $\begingroup$ ArrayPlot[] doesn't have "bars" ... Could you draw a picture showing what you want? $\endgroup$ – Dr. belisarius Oct 28 '14 at 1:38
  • $\begingroup$ is this Q/A relevant/useful? $\endgroup$ – kglr Oct 28 '14 at 1:59
  • $\begingroup$ I've added a picture. It's more like a stacked bar chart on its side with the colour being defined by the property value. $\endgroup$ – Cam Oct 28 '14 at 2:06
  • $\begingroup$ @kguler - nice. I may be able to modify that one to get what I want. $\endgroup$ – Cam Oct 28 '14 at 2:08
5
$\begingroup$

The terse Graphics primitives approach:

Graphics[{
  EdgeForm[{Black, Thick}],
  {ColorData[39][#2], Rectangle[{0, 0}, {#, 1}]} & @@@ Reverse[data]
  },
 Axes -> {True, False}
]

enter image description here

You can add whatever Ticks specification or function you wish to label the data line appropriately.

$\endgroup$
  • 2
    $\begingroup$ I sat there for 15 seconds wondering why on Earth you reversed the data :) $\endgroup$ – Dr. belisarius Oct 28 '14 at 12:18
  • $\begingroup$ 0.05 seconds for my 3,311 row datatset. Using the graphics primitives makes a huge speed difference, even if they don't have all the bells a whistles. I'll give this one the answer because I did bring up performance in my original question. $\endgroup$ – Cam Oct 28 '14 at 23:20
  • $\begingroup$ @Cam Thanks for the Accept. Graphics is my preferred method for custom plotting, e.g.: (1780), (5192), (11533), (21129), (21134), (22953). The performance is usually better and behavior rarely changes, unlike various plotting functions. $\endgroup$ – Mr.Wizard Oct 28 '14 at 23:42
  • $\begingroup$ @Cam (continued from above) It is quite annoying to get a plot just right, then have its appearance change when Mathematica is updated. By the way, if you have any trouble adding a legend to this let me know. $\endgroup$ – Mr.Wizard Oct 28 '14 at 23:44
  • $\begingroup$ Thanks for your help and I'll let you know if I have trouble figuring out the legend. $\endgroup$ – Cam Oct 29 '14 at 1:54
3
$\begingroup$
Row[{Column[{
  Plot[Interpolation[data, InterpolationOrder -> 0][x], {x, 0, Max[data[[All, 1]]]}, 
       PlotRange -> All, AspectRatio -> 1/4, ImageSize -> 600, AxesOrigin -> {0, -1}, 
       ColorFunction -> "Rainbow", PlotStyle -> Thick], 
  BarChart[Thread[Differences@data[[All, 1]] -> data[[2 ;;, 2]]], ImageSize -> 600, 
     ChartLayout -> "Stacked", BarOrigin -> Left, AspectRatio -> 1/10,
     ChartElementFunction -> Function[{region, values, metadata}, 
                                      {ColorData[{"Rainbow", {0, 16}}][metadata[[1]]], 
                                      EdgeForm[Thick], Rectangle @@ (Transpose@region)}]]}], 
  BarLegend[{"Rainbow", {0, 16}}]}]

Mathematica graphics

$\endgroup$
  • $\begingroup$ Very nice. ChartElementFunction seems to be the bit I was missing. The performance I get on my machine is 31 seconds for a dataset with 3,311 elements which is probably acceptable. Is it worth looking into using graphics primitives like Rectangle if I want faster speeds? $\endgroup$ – Cam Oct 28 '14 at 2:52
  • $\begingroup$ @Cam Yes, that will be much faster $\endgroup$ – Dr. belisarius Oct 28 '14 at 2:55
  • $\begingroup$ I was planning on adding a legend but the colours would need to be discrete because the property value is an integer. $\endgroup$ – Cam Oct 28 '14 at 3:24
2
$\begingroup$

Completely rewritten following the clarification. If those are timestamps, then the height of the bars should be the Differences of the first column. Then style these heights according to the value of the second element of the pair, like this.

transformeddata = 
 With[{max = Max[data[[All, 2]]]}, 
  MapThread[
   Style[#1, Blend[{Red, Blue}, N@#2]] &, {Join[{1}, 
     Differences[data[[All, 1]]]], data[[All, 2]]/max}] ]

enter image description here

You can then use a normal bar chart:

BarChart[transformeddata, ChartLayout -> "Stacked", BarOrigin -> Left]

enter image description here

$\endgroup$
  • $\begingroup$ I've updated by question to provide more clarity. Basically the property (1->20) would be better represented as a colour instead of the height of the bar. $\endgroup$ – Cam Oct 28 '14 at 2:01
1
$\begingroup$

In addition to the methods suggested in previosly posted answers and in this related Q/A, there is also ...

Graphics with thick Lines (instead of Rectangles):

colorRules = Thread[# -> Charting`CommonDump`brightrogerStyles[Length@#]] &@
                   DeleteDuplicates[data[[All, 2]]];
colors = labels /. colorRules;
ldata = Partition[Thread[{dates, 1}], 2, 1];
Graphics[{Thickness[.1], CapForm[None], Transpose[{colors, Line /@ ldata}]}]

enter image description here

colorRules = Thread[# -> ColorData[5, "ColorList"][[;; Length@#]]] &@
               DeleteDuplicates[data[[All, 2]]];
colors = data[[All,2]] /. colorRules;
Graphics[{Thickness[.1], CapForm["Butt"], Transpose[{colors, Line /@ ldata}]}]

enter image description here

MatrixPlot

max = Max[data[[All, 1]]];
mindif = Min[Differences[dates]];
widths = Round[Differences[dates]/mindif];
labels = data[[All, 2]];
mpdata = {Flatten@(ConstantArray[#2, {#}] & @@@ Transpose[{widths, labels}])};
options = {Frame -> False, AspectRatio -> 1/15, PlotRangePadding -> 0, ImagePadding -> 0};
MatrixPlot[mpdata, options, ColorFunction -> Hue]

enter image description here

Column[Labeled[MatrixPlot[mpdata, options, ColorFunction -> #], 
    Style[#, "Panel", 16], Right] & /@ {"Rainbow", "TemperatureMap", 
   "SolarColors", "DeepSeaColors", "BlueGreenYellow"}, Spacings -> 1]

enter image description here

$\endgroup$
  • $\begingroup$ There's a bit of an issue with this approach for large datasets. My 3,311 row dataset fails due to lack of memory. $\endgroup$ – Cam Oct 28 '14 at 23:16
  • $\begingroup$ @Cam, actually it is a big issue. I made some changes to make the size of the transformed data somewhat smaller... but I wouldn't use it for large data sets. $\endgroup$ – kglr Oct 28 '14 at 23:53

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.