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$
4
  • $\begingroup$ ArrayPlot[] doesn't have "bars" ... Could you draw a picture showing what you want? $\endgroup$ Oct 28, 2014 at 1:38
  • $\begingroup$ is this Q/A relevant/useful? $\endgroup$
    – kglr
    Oct 28, 2014 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, 2014 at 2:06
  • $\begingroup$ @kguler - nice. I may be able to modify that one to get what I want. $\endgroup$
    – Cam
    Oct 28, 2014 at 2:08

4 Answers 4

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$
6
  • 2
    $\begingroup$ I sat there for 15 seconds wondering why on Earth you reversed the data :) $\endgroup$ Oct 28, 2014 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, 2014 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, 2014 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, 2014 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, 2014 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$
3
  • $\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, 2014 at 2:52
  • $\begingroup$ @Cam Yes, that will be much faster $\endgroup$ Oct 28, 2014 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, 2014 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$
1
  • $\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, 2014 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$
2
  • $\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, 2014 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, 2014 at 23:53

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.