9
$\begingroup$

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

$\endgroup$
1
  • $\begingroup$ 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? $\endgroup$ Jan 28, 2012 at 14:42

3 Answers 3

7
$\begingroup$

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

$\endgroup$
3
  • $\begingroup$ This looks nice except that there will always be margins equal to 1 at the first and last point. $\endgroup$
    – faleichik
    Jan 28, 2012 at 17:18
  • 1
    $\begingroup$ @faleichik I did that intentionally ({Min@# - 1, Max@# + 1}) -- what behavior would you prefer? $\endgroup$
    – Mr.Wizard
    Jan 28, 2012 at 17:30
  • $\begingroup$ 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. $\endgroup$
    – faleichik
    Jan 28, 2012 at 17:51
4
$\begingroup$

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.

$\endgroup$
4
$\begingroup$

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]]]}];
$\endgroup$
4
  • 2
    $\begingroup$ 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 :) $\endgroup$ Jan 28, 2012 at 14:45
  • $\begingroup$ These are two answers (incorrect and correct) plus nice comment from the deleted answer. $\endgroup$
    – faleichik
    Jan 28, 2012 at 16:24
  • 2
    $\begingroup$ @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). $\endgroup$
    – Szabolcs
    Jan 28, 2012 at 20:28
  • $\begingroup$ Thank you for clarification! I've removed the incorrect one. $\endgroup$
    – faleichik
    Jan 29, 2012 at 9:03

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.