0

I have written a code for SPC and I am attempting to highlight certain out of control runs. So I was wondering if there was a way to pull out n(in my case 7) amount of increasing elements in an array so I can index with with the color red when I go to plot them. This is what I attempted but I obviously get an indexing error.

import  numpy as np
import matplotlib.pyplot as plt

y = np.linspace(0,10,15) 
x = np.array([1,2,3,4,5,6,7,8,9,1,4,6,4,6,8])
col =[]
  
for i in range(len(x)):
    if x[i]<x[i+1] and x[i+1]<x[i+2] and x[i+2]<x[i+3] and x[i+3]<x[i+4] and x[i+4]<x[i+5] and x[i+5]<x[i+6] and x[i+6]<x[i+7]:
        col.append('red')  
    elif x[i]>x[i+1] and x[i+1]>x[i+2] and x[i+2]>x[i+3] and x[i+3]>x[i+4] and x[i+4]>x[i+5] and x[i+5]>x[i+6] and x[i+6]>x[i+7]:
        col.append('red')  
    else:
        col.append('blue') 
  
for i in range(len(x)):
      
    # plotting the corresponding x with y 
    # and respective color
    plt.scatter(y[i], x[i], c = col[i], s = 10,
                linewidth = 0)

Any help would be greatly appreciated!

  • The array x has 15 elements. In your first for loop, i will reach 8 at which point i+1 will be 15 which too large - hence the index error –  Aug 05 '21 at 19:46
  • "This is what I attempted but I obviously get an indexing error." If it's "obvious", then presumably you understand what is happening. Can you think of a mathematical rule that tells you the greatest value of `i` that will still avoid the indexing error? What happened when you tried using that rule to fix the `for` loop? – Karl Knechtel Aug 07 '21 at 07:27
  • Please also see https://stackoverflow.com/questions/6822725/rolling-or-sliding-window-iterator ; if I understand correctly what you want to you, you may find it helps you write a more elegant solution. (Hint: if you wanted to check if *an entire list* were in ascending order, could you do that? Without knowing how many elements there are? You don't actually need to do any element-wise comparison yourself for that, actually. Hint 2: if the elements are in ascending order, you could say that they are `sorted`, right? So...) – Karl Knechtel Aug 07 '21 at 07:28
  • @KarlKnechtel I ended up using a different solution to the two posted even though both were fantastic. My collaborators preferred the use of data frames which allowed for more possible solutions. I ended up creating a parallel data frame to store when the index is out of order. Thank you for your comments – Keaton B Aug 18 '21 at 17:05

2 Answers2

0

To determine if all integer elements of a list are ascending, you could do this:-

def ascending(arr):
    _rv = True
    for i in range(len(arr) - 1):
        if arr[i + 1] <= arr[i]:
            _rv = False
            break
    return _rv


a1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 10, 11, 12, 13, 14, 16]
a2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16]

print(ascending(a1))
print(ascending(a2))

If you want to limit the sequence of ascending values then you could just use nested loops. It may look inelegant but it's surprisingly efficient and much simpler than bringing dataframes into the mix:-

def ascending(arr, seq):
    for i in range(len(arr) - seq + 1):
        state = True
        for j in range(i, i + seq - 1):
            if arr[j] >= arr[j + 1]:
                state = False
                break
        if state:
            return True
    return False


a1 = [100, 99, 98, 6, 7, 8, 10, 11, 12, 13, 14, 13]
a2 = [9, 8, 7, 6, 5, 4, 3, 2, 1]

print(ascending(a1, 7))
print(ascending(a2, 7))
  • Hello, Thank you for your response. I'm uninterested in seeing if the entire list is increasing just if there is a run of 7 consecutive elements are increasing. I've found some code that uses dataframes to accomplish this, but I don't quite understand it. I will post once I get some clarity. Thank you so much again! – Keaton B Aug 06 '21 at 20:05
  • that is absolutely fabulous! – Keaton B Aug 07 '21 at 16:09
0

As Andy said in his comment you get the index error because at i=8 you get to 15 which is the length of x.

Either you only loop over len(x)-7 and just repeat the last entry in col 7 times or you could do something like this:

import  numpy as np
import matplotlib.pyplot as plt

y = np.linspace(0,10,20)
x = np.array([1,2,3,4,5,6,1,2,3,1,0,-1,-2,-3,-4,-5,-6,4,5])
col =[]

diff = np.diff(x) # get diff to see if x inc + or dec - // len(x)-1
diff_sign = np.diff(np.sign(diff)) # get difference of the signs to get either 1 (true) or 0 (false) // len(x)-2
zero_crossings = np.where(diff_sign)[0] + 2 # get indices (-2 from len(x)-2) where a zero crossing occures
diff_zero_crossings = np.diff(np.concatenate([[0],zero_crossings,[len(x)]])) # get how long the periods are till next zero crossing

for i in diff_zero_crossings:
    if i >= 6:
        for _ in range(i):
            col.append("r")
    else:
        for _ in range(i):
            col.append("b")

for i in range(len(x)):

    # plotting the corresponding x with y
    # and respective color
    plt.scatter(y[i], x[i], c = col[i], s = 10,
            linewidth = 0)

plt.show()
Yoxcu
  • 91
  • 5
  • Thank you so much! This is a very nice solution to the problem! I found a different solution involving data frames. I will also post this solution once I personally understand it better! – Keaton B Aug 06 '21 at 20:08