Using numpy and matplotlib, I'm trying to plot a polyfitted set of data points:
x = [0, 5, 10, 15, 20]
y = [0, 0.07, 0.14, 0.2, 0.27]
Using this code:
import numpy as np
import matplotlib.pyplot as plt
x = [0, 5, 10, 15, 20]
y = [0, 0.07, 0.14, 0.2, 0.27]
poly = np.polyfit(x, y, 1)
f = np.poly1d(poly)
plt.plot(f)
plt.show()
The variable f in the above code is 0.0134 x + 0.002. This polynomial, when plotted, is supposed to be leaning to the right. But when I plot it, it shows this:
What could be wrong with the code?
What you see is the plot of coefficients of linear function f, but not its values. This is the same as plotting two points:
plt.plot([0.0134, 0.002])
This happens because f is converted to list inside plt.plot:
print(list(f))
[0.0134, 0.002]
The points are displayed with coordinates (0, 0.0134) and (1, 0.002), because 0 and 1 are default x-values in plt.plot.
What you want is to to evaluate f at points x and plot its values:
plt.plot(x, [f(xi) for xi in x])
[f(xi) for xi in x] can be shortened just as f(x), because f can take list arguments, so that the code becomes:
plt.plot(x, f(x))
as already mentioned in other answers.
Because f is a linear function, just 2 points will be enough. x[0] is the first point and x[-1] is the last:
plt.plot([x[0], x[-1]], [f(x[0]), f(x[-1])])
You need to pass x values into the polynomial to get the corresponding y values:
plt.plot(x, f(x)) # this should solve your issue
If you print out f, that returns poly1d([0.0134, 0.002 ]). So if you try to plot that, it will draw a line between 0.0134 and 0.002 on the [0, 1] interval.
What you really want to do is evaluate f at x:
plt.plot(x, f(x))
Related
I want to code a program to generate an array with coordinates to follow for drawing a shape like the white here, given are the blue points. Does anyone know how to do something like that or at least can give me a tip?
You could use e.g. InterpolatedUnivariateSpline to interpolate the points. As these spline functions are usually 1D, you could calculate x and y positions separately, depending on a new variable t going from 0 to 1.
import matplotlib.pyplot as plt
import numpy as np
from scipy import interpolate
# positions of the given points
px = [1, 4, 3, 2, 5]
py = [1, 3, 4, 3, 1]
# 5 t-values, at t=0 in point 1, at t=1 reaching point 5
pt = np.linspace(0, 1, len(px))
# sx and sy are functions that interpolate the points at the given t-values
sx = interpolate.InterpolatedUnivariateSpline(pt, px)
sy = interpolate.InterpolatedUnivariateSpline(pt, py)
# calculate many intermediate values
t = np.linspace(0, 1, 500)
x = sx(t)
y = sy(t)
# show the original points together with the spline
fig, ax = plt.subplots(facecolor='black')
ax.axis('off')
plt.scatter(px, py, s=80, color='skyblue')
plt.plot(x, y, color='white')
for i, (xi, yi) in enumerate(zip(px, py), start=1):
ax.text(xi, yi, f'\n {i}', ha='left', va='center', size=30, color='yellow')
plt.show()
I wanted to generate a 2-dimensional sample dataset. I copied the code stated in this link and doubled it to generate vectors X,Y to scatter them as 2-dimensional dataset as the following. But the result was not favourable. In fact I wanted something like the picture below.
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
mu = [1,4]
sigma = [2, 1]
p_i = [0.3, 0.7]
n = 1000
x = []
y=[]
for i in range(n):
z_i = np.argmax(np.random.multinomial(1, p_i)) #np.random.multinomial(1,[0.3,0.5,0.2]) returns the result of an experiment
#of rolling a dice. the result is as this: [1,0,0]. this means that the side one occurs in the experiment and the others
#not. the goal is choosing mu[i] in a random way
x_i = np.random.normal(mu[z_i], sigma[z_i])
x.append(x_i)
mu = [3,6]
sigma = [1, 2]
p_i = [0.6, 0.4]
for i in range(n):
z_i = np.argmax(np.random.multinomial(1, p_i)) #np.random.multinomial(1,[0.3,0.5,0.2]) returns the result of an experiment
#of rolling a dice. the result is as this: [1,0,0]. this means that the side one occurs in the experiment and the others
#not. the goal is choosing mu[i] in a random way
y_i = np.random.normal(mu[z_i], sigma[z_i])
y.append(y_i)
plt.scatter(x, y)
plt.show()
`
Can any one help me?
It looks like what you're trying to plot is data sampled from 2 distinct 2D gaussians. Here is code that can plot mock data that looks like this. Feel free to adjust the mean and covariance matrix to suit your needs.
from numpy.random import multivariate_normal
# First 2D gaussian:
mu = [1, 3]
cov = [[0.07, 0],[0, 1.8]]
x, y = np.random.multivariate_normal(mu, cov, 200).T
plt.figure(figsize=(10,6))
plt.scatter(x, y, s=5, color='blue')
ax = plt.gca()
# Second 2D gaussian:
mu = [2, 1]
cov = [[0.8, -0.4],[-0.4, 0.5]]
x, y = np.random.multivariate_normal(mu, cov, 200).T
plt.scatter(x, y, s=5, color='red')
plt.xlim([-2, 8])
plt.ylim([-6, 10]);
This produces something like the plot below (different colors so you can see the pattern):
I'm trying to wrap my head around the quiver function to plot vector fields. Here's a test case:
import numpy as np
import matplotlib.pyplot as plt
X, Y = np.mgrid[1:1.5:0.5, 1:1.5:0.5]
print(X)
print(Y)
u = np.ones_like(X)
v = np.zeros_like(Y)
plt.quiver(X,Y, u, v)
plt.axis([0, 3, 0, 3], units='xy', scale=1.)
plt.show()
I am trying to get a vector of length 1, point from (1,0) to (2,0), but here is what I get:
I have tried adding the scale='xy' option, but the behaviour doesn't change. So how does this work?
First funny mistake is that you put the quiver arguments to the axis call. ;-)
Next, looking at the documentation, it says
If scale_units is ‘x’ then the vector will be 0.5 x-axis units. To plot vectors in the x-y plane, with u and v having the same units as x and y, use angles='xy', scale_units='xy', scale=1.
So let's do as the documentation tells us,
import numpy as np
import matplotlib.pyplot as plt
X, Y = np.mgrid[1:1.5:0.5, 1:1.5:0.5]
u = np.ones_like(X)
v = np.zeros_like(Y)
plt.quiver(X,Y, u, v, units='xy', angles='xy', scale_units='xy', scale=1.)
plt.axis([0, 3, 0, 3])
plt.show()
and indeed we get a one unit long arrow:
My data is the following:
x = [3,4,5,6,7,8,9,9]
y = [6,5,4,3,2,1,1,2]
And I can obtain the following two graphs.
and
However, what I want is this (an average of all the points along the way):
Is it possible in matplotlib? Or do I have to change the list manually and somehow create:
x = [3,4,5,6,7,8,9]
y = [6,5,4,3,2,1,1.5]
RELEVANT CODE
ax.plot(x, y, 'o-', label='curPerform')
x1,x2,y1,y2 = ax.axis()
x1 = min(x) - 1
x2 = max(x) + 1
ax.axis((x1,x2,(y1-1),(y2+1)))
This can done by generating a new y_mean from your data, then plotting this on the same plot axis using an additional call to ax.plot(), where:
x is the same x used in your scatter plot
y is an iterable with "mean" value you calculate repeated so that its length is equal to x, i.e. y_mean = [np.mean(y) for i in x].
Example:
import matplotlib.pyplot as plt
import random
import numpy as np
# Create some random data
x = np.arange(0,10,1)
y = np.zeros_like(x)
y = [random.random()*5 for i in x]
# Calculate the simple average of the data
y_mean = [np.mean(y)]*len(x)
fig,ax = plt.subplots()
# Plot the data
data_line = ax.plot(x,y, label='Data', marker='o')
# Plot the average line
mean_line = ax.plot(x,y_mean, label='Mean', linestyle='--')
# Make a legend
legend = ax.legend(loc='upper right')
plt.show()
Resulting figure:
Yes, you must do the calculation yourself. plot plots the data you give it. If you want to plot some other data, you need to calculate that data yourself and then plot that instead.
Edit: A quick way to do the calculation:
>>> x, y = zip(*sorted((xVal, np.mean([yVal for a, yVal in zip(x, y) if xVal==a])) for xVal in set(x)))
>>> x
(3, 4, 5, 6, 7, 8, 9)
>>> y
(6.0, 5.0, 4.0, 3.0, 2.0, 1.0, 1.5)
I'm trying to start 2D contour plot for a flow net and I'm having trouble getting the initial grid to show up properly.
Given the number of columns and the number of rows, how can I write a function that will plot a grid so that all points in the given range appear?
I tried plotting for 4 columns and 3 rows of points by doing this:
r = 3
c = 4
x = [i for i in range(c)]
y = [i for i in range(r)]
plot(x,y,'ro')
grid()
show()
and get this error:
'ValueError: x and y must have same first dimension'
So I tried testing it on a 4x4 grid and got this and I get close to what I want, however it only plots points (0,0), (1,1), (2,2), and (3,3)
However, I also want the points (0,0), (1,0), (2,0), (3,0), (1,0), (1,1)...(3,2), (3,3) to appear, as I will later need to plot vectors from this point indicating the direction of flow for my flow net.
Sorry, I know my terminology isn't that great. Does anyone know how to do this and how to make it work for grids that aren't square?
You could use itertools.product to generate the desired points.
Use plt.scatter to plot the points
Use plt.quiver to plot the vector field. (Relevant code taken from these SO answers)
import numpy as np
import matplotlib.pyplot as plt
import itertools
r = 3
c = 4
x = np.linspace(0, c, c+1)
y = np.linspace(0, r, r+1)
pts = itertools.product(x, y)
plt.scatter(*zip(*pts), marker='o', s=30, color='red')
X, Y = np.meshgrid(x, y)
deg = np.arctan(Y**3 - 3*Y-X)
QP = plt.quiver(X, Y, np.cos(deg), np.sin(deg))
plt.grid()
plt.show()
r = 3
c = 4
x = [i % c for i in range(r*c)]
y = [i / c for i in range(r*c)]
print x
print y
Gives:
[0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3]
[0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2]
When used to draw graph as you did it produces desired result.
The first two arguments specify your x and y components. So the number of points must match. I think what you want is something like:
from itertools import product
import matplotlib.pyplot as plt
points = np.array(list(product(range(3),range(4))))
plt.plot(points[:,0],points[:,1],'ro')
plt.show()