2D Orthogonal projection of vector onto line with numpy yields wrong result
<p>I have 350 document scores that, when I plot them, have this shape:</p>

<pre><code>docScores = [(0, 68.62998962), (1, 60.21374512), (2, 54.72480392), 
             (3, 50.71389389), (4, 49.39723969), ...,  
             (345, 28.3756237), (346, 28.37126923), 
             (347, 28.36397934), (348, 28.35762787), (349, 28.34219933)]
</code></pre>

<p>I posted the complete array <a href="http://pastebin.com/JeW3kJf4" rel="nofollow">here</a> on <code>pastebin</code> (it corresponds to the <code>dataPoints</code> list on the code below).</p>

<p><a href="http://i.stack.imgur.com/BAeDE.png" rel="nofollow"><img src="http://i.stack.imgur.com/BAeDE.png" alt="Score distribution"></a></p>

<p>Now, I originally needed to find the <code>elbow point</code> of this <code>L-shape</code> curve, which I found thanks to <a href="http://stackoverflow.com/questions/2018178/finding-the-best-trade-off-point-on-a-curve">this post</a>.</p>

<p>Now, on the following plot, the red vector <code>p</code> represents the elbow point. I would like to find the point <code>x=(?,?)</code> (the yellow star) on the vector <code>b</code> which corresponds to the orthogonal projection of <code>p</code> onto <code>b</code>. </p>

<p><a href="http://i.stack.imgur.com/f1Kju.png" rel="nofollow"><img src="http://i.stack.imgur.com/f1Kju.png" alt="enter image description here"></a></p>

<p>The red point on the plot is the one I obtain (which is obviously wrong).  I obtain it doing the following:</p>

<pre><code>b_hat = b / np.linalg.norm(b)    #unit vector of b
proj_p_onto_b = p.dot(b_hat)*b_hat
red_point = proj_p_onto_b + s
</code></pre>

<p>Now, if the projection of <code>p</code> onto <code>b</code> is defined by the its starting and ending point, namely <code>s</code> and <code>x</code> (the yellow star), it follows that <code>proj_p_onto_b = x - s</code>, therefore <code>x = proj_p_onto_b + s</code> ?</p>

<p>Did I make a mistake here ?</p>

<p><strong>EDIT :</strong> In answer to @cxw, here is the code for computing the elbow point :</p>

<pre><code>def findElbowPoint(self, rawDocScores):
    dataPoints = zip(range(0, len(rawDocScores)), rawDocScores)
    s = np.array(dataPoints[0])
    l = np.array(dataPoints[len(dataPoints)-1])
    b_vect = l-s
    b_hat = b_vect/np.linalg.norm(b_vect)
    distances = []
    for scoreVec in dataPoints[1:]:
        p = np.array(scoreVec) - s
        proj = p.dot(b_hat)*b_hat
        d = abs(np.linalg.norm(p - proj)) # orthgonal distance between b and the L-curve
        distances.append((scoreVec[0], scoreVec[1], proj, d))

    elbow_x = max(distances, key=itemgetter(3))[0]
    elbow_y = max(distances, key=itemgetter(3))[1]
    proj = max(distances, key=itemgetter(3))[2]
    max_distance = max(distances, key=itemgetter(3))[3]

    red_point = proj + s
</code></pre>

<p><strong>EDIT</strong> : Here is the code for the plot :</p>

<pre><code>&gt;&gt;&gt; l_curve_x_values = [x[0] for x in docScores]
&gt;&gt;&gt; l_curve_y_values = [x[1] for x in docScores]
&gt;&gt;&gt; b_line_x_values = [x[0] for x in docScores]
&gt;&gt;&gt; b_line_y_values = np.linspace(s[1], l[1], len(docScores))
&gt;&gt;&gt; p_line_x_values = l_curve_x_values[:elbow_x]
&gt;&gt;&gt; p_line_y_values = np.linspace(s[1], elbow_y, elbow_x)
&gt;&gt;&gt; plt.plot(l_curve_x_values, l_curve_y_values, b_line_x_values, b_line_y_values, p_line_x_values, p_line_y_values)
&gt;&gt;&gt; red_point = proj + s
&gt;&gt;&gt; plt.plot(red_point[0], red_point[1], 'ro')
&gt;&gt;&gt; plt.show()
</code></pre>

<p>If you are using the plot to visually determine if the solution looks correct, you must plot the data using the same scale on each axis, i.e. use <code>plt.axis('equal')</code>. If the axes do not have equal scales, the angles between lines are distorted in the plot.</p>

python numpy plot linear-algebra orthogonal