Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

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

share|improve this question
    
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. Jan 28 '12 at 14:42
add comment

3 Answers

up vote 6 down vote accepted

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

share|improve this answer
    
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
add comment

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.

share|improve this answer
add comment

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]]]}];
share|improve this answer
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 9:03
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.