Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to draw line inside a scatter plot

I can't believe that this is so complicated but I tried and googled for a while now.

I just want to analyse my scatter plot with a few graphical features. For starters, I want to add simply a line.

So, I have a few (4) points and I want to add a line to it, like in this plot (source: http://en.wikipedia.org/wiki/File:ROC_space-2.png)

enter image description here

Now, this won't work. And frankly, the documentation-examples-gallery combo and content of matplotlib is a bad source for information.

My code is based upon a simple scatter plot from the gallery:

# definitions for the axes
left, width = 0.1, 0.85 #0.65
bottom, height = 0.1, 0.85 #0.65
bottom_h = left_h = left+width+0.02

rect_scatter = [left, bottom, width, height]

# start with a rectangular Figure
fig = plt.figure(1, figsize=(8,8))
axScatter = plt.axes(rect_scatter)

# the scatter plot:
p1 = axScatter.scatter(x[0], y[0], c='blue', s = 70)
p2 = axScatter.scatter(x[1], y[1], c='green', s = 70)
p3 = axScatter.scatter(x[2], y[2], c='red', s = 70)
p4 = axScatter.scatter(x[3], y[3], c='yellow', s = 70)
p5 = axScatter.plot([1,2,3], "r--")

plt.legend([p1, p2, p3, p4, p5], [names[0], names[1], names[2], names[3], "Random guess"], loc = 2)

# now determine nice limits by hand:
binwidth = 0.25
xymax = np.max( [np.max(np.fabs(x)), np.max(np.fabs(y))] )
lim = ( int(xymax/binwidth) + 1) * binwidth

axScatter.set_xlim( (-lim, lim) )
axScatter.set_ylim( (-lim, lim) )

xText = axScatter.set_xlabel('FPR / Specificity')
yText = axScatter.set_ylabel('TPR / Sensitivity')

bins = np.arange(-lim, lim + binwidth, binwidth)
plt.show()

Everything works, except the p5 which is a line.

Now how is this supposed to work? What's good practice here?

like image 263
ruffy Avatar asked Oct 19 '12 20:10

ruffy


People also ask

How do I add a line to a scatter?

Select the data that you want to plot in the line chart. Click the Insert tab, and then click Insert Line or Area Chart. Click Line with Markers.

How do you add a horizontal line to a scatter plot?

Right click on one of the orange dots and click Format Data Series… In the window that appears on the right side of the screen, click Solid Line: What is this? Feel free to modify the color, thickness, and style of the line to make it more aesthetically pleasing.


2 Answers

plottakes either y values and uses x as index array 0..N-1 or x and y values as described in the documentation. So you could use

p5 = axScatter.plot((0, 1), "r--")

in your code to plot the line.

However, you are asking for "good practice". The following code (hopefully) shows some "good practise" and some of the capabilities of matplotlib to create the plot you mention in your question.

import numpy as np
import matplotlib.pyplot as plt 

# create some data
xy = np.random.rand(4, 2)
xy_line = (0, 1)

# set up figure and ax
fig, ax = plt.subplots(figsize=(8,8))

# create the scatter plots
ax.scatter(xy[:, 0], xy[:, 1], c='blue')
for point, name in zip(xy, 'ABCD'):
    ax.annotate(name, xy=point, xytext=(0, -10), textcoords='offset points',
                color='blue', ha='center', va='center')
ax.scatter([0], [1], c='black', s=60)
ax.annotate('Perfect Classification', xy=(0, 1), xytext=(0.1, 0.9),
            arrowprops=dict(arrowstyle='->'))

# create the line
ax.plot(xy_line, 'r--', label='Random guess')
ax.annotate('Better', xy=(0.3, 0.3), xytext=(0.2, 0.4),
            arrowprops=dict(arrowstyle='<-'), ha='center', va='center')
ax.annotate('Worse', xy=(0.3, 0.3), xytext=(0.4, 0.2),
            arrowprops=dict(arrowstyle='<-'), ha='center', va='center')
# add labels, legend and make it nicer
ax.set_xlabel('FPR or (1 - specificity)')
ax.set_ylabel('TPR or sensitivity')
ax.set_title('ROC Space')
ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
ax.legend()
plt.tight_layout()
plt.savefig('scatter_line.png', dpi=80)

scatter_with_line.png

By the way: I think that matplotlibs documentation is quite useful nowadays.

like image 167
bmu Avatar answered Sep 29 '22 23:09

bmu


the p5 line should be:

p5 = axScatter.plot([1,2,3],[1,2,3], "r--")

argument 1 is a list of the x values, and argument 2 is a list of y values

If you just want a straight line, you only need to provide values for the extremities of the line.

like image 44
Anake Avatar answered Sep 29 '22 22:09

Anake