How to make a graph with x and y of different length - python

I'm trying to make a Python app that shows a graph after the input of the data by the user, but the problem is that the y_array and the x_array do not have the same dimensions. When I run the program, this error is raised:
ValueError: x and y must have same first dimension, but have shapes () and ()
How can I draw a graph with the X and Y axis of different length?
Here is a minimal example code that will lead to the same error I got
:
import matplotlib.pyplot as plt
y = [0, 8, 9, 3, 0]
x = [1, 2, 3, 4, 5, 6, 7]
plt.plot(x, y)
plt.show()

This is virtually a copy/paste of the answer found here, but I'll show what I did to get these to match.
First, we need to decide which array to use- the x_array of length 7, or the y_array of length 5. I'll show both, starting with the former. Note that I am using numpy arrays, not lists.
Let's load the modules
import numpy as np
import matplotlib.pyplot as plt
import scipy.interpolate as interp
and the arrays
y = np.array([0, 8, 9, 3, 0])
x = np.array([1, 2, 3, 4, 5, 6, 7])
In both cases, we use interp.interp1d which is described in detail in the documentation.
For the x_array to be reduced to the length of the y_array:
x_inter = interp.interp1d(np.arange(x.size), x)
x_ = x_inter(np.linspace(0,x.size-1,y.size))
print(len(x_), len(y))
# Prints 5,5
plt.plot(x_,y)
plt.show()
Which gives
and for the y_array to be increased to the length of the x_array:
y_inter = interp.interp1d(np.arange(y.size), y)
y_ = y_inter(np.linspace(0,y.size-1,x.size))
print(len(x), len(y_))
# Prints 7,7
plt.plot(x,y_)
plt.show()
Which gives

Related

Creating a contour plot from three data columns

I have two columns of input data, that I want as my x and y axis, and a third column of results data relating to the inputs. I have 36 combinations of inputs and then 36 results
I want to achieve something like this plot
I have tried using a cmap but get told the z data is in 1D and needs to be 2D and don't understand how I get get around this issue
Also attached another method below
data = excel[['test','A_h','f_h','fore C_T','hind C_T','fore eff','hind eff','hind C_T ratio','hind eff ratio']]
x = data['A_h']
y = data['f_h']
z = data['hind C_T ratio']
X,Y = np.meshgrid(x,y)
Z = z
plt.pcolor(x,y,z)
If you have arrays [1, 2, 3] and [4, 5, 6] then meshgrid will will give you two arrays of 3x3 each: [[1, 1, 1], [2, 2, 2], [3, 3, 3]] and [[4, 5, 6], [4, 5, 6], [4, 5, 6]]. In your case, you seem to have this already taken care of, since you have 36 each of x, y, z, values. So meshgrid won't be necessary.
If your arrays are well defined (already in the 11122233 and 456456456 format above), then you can just reshape them:
x = np.reshape(data['A_h'], (6,6))
y = np.reshape(data['f_h'], (6,6))
z = np.reshape(data['hind C_T ratio'], (6,6))
plt.contourf(x, y, z)
You can see more help about contourf for details.
On the other hand, if your data are irregular (the 36 points do not form a grid), then you will have to use griddata as #obchardon suggested above.

What's meaning of plt.plot(x[0:-1],y/y[0])?

I am plotting an exponential distribution using the information provided by the tutor.
plt.plot(x[:-1],y/y[0])
plt.plot(tvals,pvals)
plt.show()
But, I do not know what's meaning of x[:-1] and y/y[0]?
x[:-1] means all the elements except the last one
y/y[0] is simply dividing the array y by the first value i.e y[0] of the array.
Code Example
import numpy as np
import matplotlib.pyplot as plt
x = np.array([1, 3, 5, 7])
y = np.array([2, 4, 6])
a = x[:-1] # [1, 3, 5]
b = y/y[0] # [1, 2, 3]
plt.plot(a, b)
Output

Sum of n elements of a list with for-in loop

I am trying to create a graph with the number of days as the x axis and the total hours as the y axis, but I don't know how to create the y axis. The code is:
hours_per_day = [1, 4, 3, 2, 3, 1]
days = [x for x in range(len(hours_per_day))]
def total_hours():
y = 0
for x in hours_per_day:
y = x + y
return y
plt.plot(days, total_hours, label="Total Hours")
And the error:
ValueError: x and y must have same first dimension, but have shapes (6,) and (1,)
I might not grasp correctly what you're trying to achieve, but just reading the sentence "create a graph with the number of days as the x axis and the total hours as the y axis" this would simply be
import numpy as np
import matplotlib.pyplot as plt
hours_per_day = [1, 4, 3, 2, 3, 1]
plt.plot(np.cumsum(hours_per_day))
plt.show()

Piecewise Fit not working - large dataset

I have been using a solution found in several places on stack overflow for fitting a piecewise function:
from scipy import optimize
import matplotlib.pyplot as plt
import numpy as np
x = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ,11, 12, 13, 14, 15], dtype=float)
y = np.array([5, 7, 9, 11, 13, 15, 28.92, 42.81, 56.7, 70.59, 84.47, 98.36, 112.25, 126.14, 140.03])
def piecewise_linear(x, x0, y0, k1, k2):
return np.piecewise(x, [x < x0], [lambda x:k1*x + y0-k1*x0, lambda x:k2*x + y0-k2*x0])
p, e = optimize.curve_fit(piecewise_linear, x, y)
xd = np.linspace(-5, 30, 100)
plt.plot(x, y, ".")
plt.plot(xd, piecewise_linear(xd, *p))
plt.show()
(for example, here: How to apply piecewise linear fit in Python?)
The first time I try it in the console I get an OptimizeWarning.
OptimizeWarning: Covariance of the parameters could not be estimated
category=OptimizeWarning)
After that I just get a straight line for my fit. It seems as though there is clearly a bend in the data that the fit isn't following, although I cannot figure out why.
For the dataset I am using there are about 3200 points in each x and y, is this part of the problem?
Here are some fake data that kind of simulate mine (same problem occurs where fit is not piecewise):
x = np.append(np.random.uniform(low=10.0, high=40.2, size=(1500,)), np.random.uniform(low=-10.0, high=20.2, size=(1500,)))
y = np.append(np.random.uniform(low=-3000, high=0, size=(1500,)), np.random.uniform(low=-2000, high=1000, size=(1500,)))
Just to complete the question with the answer provided in the comment above:
The issue was not due to the large number of points, but the fact that I had such large values on my y axis. Since the default initial values are 1, my values of around 1000 were too large. To fix that an initial guess for the line fit was used for parameter p0. From the docs for scipy.optimize.curve_fit it looks like:
p0 : None, scalar, or N-length sequence, optional
Initial guess for the parameters. If None, then the initial values will all be 1 (if the number of parameters for the function can be determined using introspection, otherwise a ValueError is raised).
So my final code ended up looking like this:
from scipy import optimize
import matplotlib.pyplot as plt
import numpy as np
x = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ,11, 12, 13, 14, 15], dtype=float)
y = np.array([500, 700, 900, 1100, 1300, 1500, 2892, 4281, 5670, 7059, 8447, 9836, 11225, 12614, 14003])
def piecewise_linear(x, x0, y0, k1, k2):
return np.piecewise(x, [x < x0], [lambda x:k1*x + y0-k1*x0, lambda x:k2*x + y0-k2*x0])
p, e = optimize.curve_fit(piecewise_linear, x, y, p0=(10, -2500, 0, -500))
xd = np.linspace(-5, 30, 100)
plt.plot(x, y, ".")
plt.plot(xd, piecewise_linear(xd, *p))
plt.show()
Just for fun (very scattered case) :
Since the original data was not available, the coordinates of the points are obtained from the figure published in the Rachel W's question, thanks to a graphical scan and the record of the blue pixels. They are some artefact due to the straight line and the grid which, after scanning, appear in white.
The result of a piecewise regression (two segments) is drawn in red on the above figure.
The equation of the fitted function is :
The regression method used is not iterative and don't require initial guess. The code is very simple : pp.12-13 in this paper https://fr.scribd.com/document/380941024/Regression-par-morceaux-Piecewise-Regression-pdf

Interpolate Table from txt

I'm fairly new to python programming and I'm trying to write a program that plots a graph from a txt file and interpolate the data later.
To get the data, I know that I can use:
precos = np.genfromtxt('Precos.txt', delimiter=',')
or
precos = sp.loadtxt("Precos.txt", delimiter=",")
And the data is something simple like:
1, 69.00
2, 69.00
3, 69.00
4, 69.00
5, 69.00
6, 69.00
7, 69.00
8, 79.00
9, 56.51
10, 56.51
I also know that I can use
plt.plot(precos)
To plot the graph but I don't how to interporlate. I saw that sp.interpolate.interp1d can help, but I am still unable to get my head around it.
----EDIT----
Ok, I tried a new approach, and now my code is almost done, but I still getting one error.
import scipy as sp
import numpy as np
import matplotlib.pyplot as plt
## Importando os dados numa matriz Nx2
M = sp.loadtxt('Precos.txt', delimiter=',')
## Construindo os vetores X e Y
x=np.zeros(len(M))
y=np.zeros(len(M))
for i in range(len(M)):
x[i] = M[i][0]
y[i] = M[i][1]
##Grahp Plot
plt.plot(x,y)
plt.title("Fone de Ouvido JBL com Microfone T100A - Fevereiro 2017")
plt.xlabel("Dia")
plt.ylabel("Preco em R$")
##Interpolation
F = sp.interpolate.interp1d(x,y)
xn = sp.arange(0,9,0.1)
yn = F(xn)
plt.plot(x, y, 'o', xn, yn, '-')
plt.show()
But now I getting: ValueError: A value in x_new is below the interpolation range.
Any ideas?
sp.interpolate.interp1d generates a function that you can reuse to interpolate the original data at intermediate points. Here's some specific code to breathe some life into it:
import numpy as np
from scipy import interpolate
data = np.array([[1, 69.00],
[2, 69.00],
[3, 69.00],
[4, 69.00],
[5, 69.00],
[6, 69.00],
[7, 69.00],
[8, 79.00],
[9, 56.51],
[10, 56.51]])
x = data[:,0]
y = data[:,1]
# Define an interpolation function
interpolation_function = interpolate.interp1d(x,y,kind='linear')
# Define intermediate points to interpolate at, and print the result
xi = [1, 1.5, 2.5, 9.5]
print(interpolation_function(xi))
gives the result:
[ 69. 69. 69. 56.51]

Categories