# Replace sublist entries after the first match (and retain plot-ability)

I think I have a subtle problem. I have nested lists. The first level can be considered as a time series. The lowest level list is a pair of numbers.
These number s can all be thought of as random. Each number in the pair represents a variable. I am only interested in adjusting the second number/variable in the pair.

Example: Two variables, three time series, four observed pairs in each series:

lst={
{{100., 20.}, {99.7401, 19.7457},{99.7401, 19.7457},{99.7401, -19.7457}},
{{102., 22.}, {98.7401, -39.7457},{98.7401, 39.7457},{98.7401, 39.7457}},
{{103., 21.}, {97.7401, 49.7457},{97.7401, -49.7457},{97.7401, -49.7457}},
}


Objective: I would like to be able to plot each variable as a line plot. I would like to prevent any observation of the second variable from plotting after it takes a negative value (I don't want to just hide that region of the plot).

That is I would like to keep these NULL or empty list entries so that in other parts of the work flow I can calculate the number of observations removed, the value prior to the removed observation, etc. etc. This suggests replacing the data rather than delete the data. The result, I think I need is, the three time series returned as:

res={
{{100., 20.}, {99.7401, 19.7457},{-99.7401, 19.7457},{99.7401, NULL}},
{{102., 22.}, {98.7401, NULL},{98.7401, NULL},{98.7401, NULL}},
{{103., 21.}, {-97.7401, 49.7457},{-97.7401, NULL},{97.7401, NULL}},
}


I've tried several things. One approach seemed to be find the position of the negatives and then do something with those index values. I can get Position to return the full position, I'm at a loss about the best way to do next step, replace all entries after the first negative.

Position[lst, _?(# < 0 &)]
{{1, 4, 2}, {2, 2, 2}, {3, 3, 2}, {3, 4, 2}}


Appreciate any assistance.

• Instead of setting to Null, just keep taking points as long as the $y$-coordinate is positive: TakeWhile[#, Positive @* Last] & /@ lst. Nov 8 '17 at 7:16
• Thanks, I did go through the tutorials on list manipulation and none mentioned this function... Ideally I'd like to only process these lists once, hence the desire to insert Null or some place holder. It sounds like that just won't fit naturally in this use case. correct? Nov 8 '17 at 7:55
• You probably could if you really wanted to (I just didn't try to think of how to do so), but if it's only for plotting purposes, my proposal should be adequate. Also, the canonical way to denote entries to be omitted for plotting would be to use Missing[], instead of your NULL. Nov 8 '17 at 8:12

If the appropriate input is

lst = {
{{100., 20.}, {99.7401, 19.7457}, {-99.7401, 19.7457}, {99.7401, -19.7457}},
{{102., 22.}, {98.7401, -39.7457}, {98.7401, 39.7457}, {98.7401, 39.7457}},
{{103., 21.}, {-97.7401, 49.7457}, {-97.7401, -49.7457}, {97.7401, -49.7457}}
}


and the requested output is

res = {
{{100., 20.}, {99.7401, 19.7457}, {-99.7401, 19.7457}, {99.7401,NULL}},
{{102., 22.}, {98.7401, NULL}, {98.7401, NULL}, {98.7401, NULL}},
{{103., 21.}, {-97.7401, 49.7457}, {-97.7401, NULL}, {97.7401, NULL}}
}


then

Map[FoldList[f, adjust[#]] &, lst] === res/.NULL->Null


returns True,

where

adjust = MapAt[
If[Last[#] < 0, {First[#], Null}, #] &, #, 1] &


is used to modify the first entry for every line in the input (make the second entry Null if it is negative). This function is needed because the proposed solution manipulates every input line one pair at a time (see below).

Function f is used in FoldList to perform the change of the y coordinate as described in the question. Namely, it receives two points as input and returns the later, appropriately modified.

f = Which[
MatchQ[#1, {_, _?(Or[SameQ[#, Null], Negative[#]] &)}], {First[#2], Null},
MatchQ[#2, {_, _?(Negative[#] &)}], {First[#2], Null},
True, #2
] &