9

it is possible to get a histogram style in ListPlot using InterpolationOrder->0

testdata = {{1, 3}, {3, 4}, {4, 3}, {5, 8}, {7, 6}, {9, 4}};
ListPlot[testdata, Joined -> True, InterpolationOrder -> 0, 
Epilog -> {PointSize[Large], Point[testdata]}]

enter image description here

Note that the data points are sitting at the corner of the histograms at the left end of the horizontal lines. My question is:

How could I plot the same data set with the data points being centered on the horizontal line segments? For equidistant data points this is of course a simple shift. But how to do this for irregularly gridded data?

Edit 1:

To clarify: Of course this is possibly not very meaningfull in irregularly spaced cases, and centered is the wrong term, however, in the example case the data point connection I was looking for could look like the following:

enter image description here

Szabolcs
  • 234,956
  • 30
  • 623
  • 1,263
Markus Roellig
  • 7,703
  • 2
  • 29
  • 53
  • I'm not quite sure what "centered" would look like if the abscissas are irregularly spaced. Having said that, would the results of Plot[Evaluate[Last[First[testdata]] + Differences[Last /@ testdata].UnitStep[x - ListConvolve[{1, 1}/2, First /@ testdata]]], {x, 0, 10}, Axes -> None, Epilog -> {AbsolutePointSize[5], Point /@ testdata}, Frame -> True] suit your needs? – J. M.'s missing motivation Jan 28 '12 at 14:42

3 Answers3

7

This uses Nearest to build a NearestFunction (nf) for your testdata. This is like InterpolationOrder -> 0 except that it is centered because it does as the name implies: gives the nearest value.

testdata = {{1, 3}, {3, 4}, {4, 3}, {5, 8}, {7, 6}, {9, 4}};

nf = Nearest[Rule @@@ testdata];

{min, max} = {Min@# - 1, Max@# + 1} &@testdata[[All, 1]];

Plot[ nf[x], {x, min, max},
  AxesOrigin -> {0, 0},
  Epilog -> {PointSize[Large], Point[testdata]}
]

Mathematica graphics

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
  • This looks nice except that there will always be margins equal to 1 at the first and last point. – faleichik Jan 28 '12 at 17:18
  • 1
    @faleichik I did that intentionally ({Min@# - 1, Max@# + 1}) -- what behavior would you prefer? – Mr.Wizard Jan 28 '12 at 17:30
  • I've slightly changed the data and uploaded a picture to my answer. I think this is what expected. Of course, your variand can be corrected too. BTW I was surprised how fast NearestFunction is evaluated in your example. – faleichik Jan 28 '12 at 17:51
4

This is the right variant now.

data = {{-3, 3}, {3, 4}, {4, 3}, {5, 8}, {7, 6}, {9, 4}, {23, 0}};
mid = {(#[[1, 1]] + #[[2, 1]])/2, #[[2, 2]]} & /@ (Partition[data, 2, 
     1]);
lpdata = Join[
   {{2 data[[1, 1]] - mid[[1, 1]], data[[1, 2]]}},
   mid,
   {{2 data[[-1, 1]] - mid[[-1, 1]], data[[-1, 2]]}}
   ];
ListPlot[lpdata, Joined -> True, InterpolationOrder -> 0, 
 PlotStyle -> Thickness[Large], 
 Epilog -> {PointSize[Large], Point[data]}, PlotRange -> All]

enter image description here

This is a modification which J. M. suggested:

mid = Transpose[{ListConvolve[{1, 1}/2, data[[All, 1]]], Rest[data[[All, 2]]]}];
faleichik
  • 12,651
  • 8
  • 43
  • 62
  • 2
    Hi, thank you for the answer. That is not quite what I was looking for. I would prefer if the data remains intact and the line plotting is altered. Data is holy :) – Markus Roellig Jan 28 '12 at 14:45
  • These are two answers (incorrect and correct) plus nice comment from the deleted answer. – faleichik Jan 28 '12 at 16:24
  • 2
    @faleichik Thank you for merging your answers. Don't worry about older, incorrect versions: all older versions of your post are kept and accessible here on StackExchange (just click the "edited x hours ago" link). You can safely remove the incorrect version. The idea behind StackExchange is that these questions and answers should eventually become a repository of knowledge useful for everyone (not only the original question asker). Thus ideally the post will eventually get cleaned up so that a new visitors can also follow them easily (without needing the context of the original conversation). – Szabolcs Jan 28 '12 at 20:28
  • Thank you for clarification! I've removed the incorrect one. – faleichik Jan 29 '12 at 09:03
4

I find this behaviour inconsistent with the one implemented for 2D functions (ListDensityPlot, ListPlot3D, etc.). I am sure someone will respond with a proper from the grounds up implementation of zeroth order interpolation, but here's a lazy hack based on ListPlot3D:

Graphics[
 {Blue,
  Line[
   Union /@ Cases[
      Normal@
       ListPlot3D[ArrayPad[testdata, {{0, 0}, {1, 0}}], 
        InterpolationOrder -> 0, Mesh -> All],
      Polygon[p_, ___] :> p,
      Infinity
      ][[All, All, {2, 3}]]
   ]
  }, Frame -> True, PlotRange -> {0, 10}, 
 Epilog -> {PointSize[Large], Point[testdata]}
]

Mathematica graphics

Like with ListPlot3D, the regions are centred on the points (except for the endpoints).


EDIT Another possibility is

centres = Join[
  testdata[[1, {1}]],
  Mean /@ Partition[testdata[[All, 1]], 2, 1],
  testdata[[-1, {1}]]
  ]

regions = 
 ArrayFlatten[{{Partition[centres, 2, 1], testdata[[All, {2}]]}}]

Plot[
 Total[#3 (UnitStep[x - #1] - UnitStep[x - #2]) & @@@ regions] // 
  Evaluate,
 {x, testdata[[1, 1]], testdata[[-1, 1]]}, ExclusionsStyle -> Dashed, 
 PlotRange -> {0, 10}, Epilog -> {PointSize[Large], Point[testdata]}
]

Mathematica graphics

I am building a function from UnitSteps, which makes it easy to style exclusions appropriately. The // Evaluate part is essential for Mathematica to be able to autodetect exclusions.

Szabolcs
  • 234,956
  • 30
  • 623
  • 1,263