Related
I am struggling a bit with the pandas transformations needed to make data render in 3D on matplot lib. The data I have is usually in columns of numbers (usually time and some value). So lets create some test data to illustrate.
import pandas as pd
pattern = ("....1...."
"....1...."
"..11111.."
".1133311."
"111393111"
".1133311."
"..11111.."
"....1...."
"....1....")
# create the data and coords
Zdata = list(map(lambda d:0 if d == '.' else int(d), pattern))
Zinverse = list(map(lambda d:1 if d == '.' else -int(d), pattern))
Xdata = [x for y in range(1,10) for x in range(1,10)]
Ydata = [y for y in range(1,10) for x in range(1,10)]
# pivot the data into columns
data = [d for d in zip(Xdata,Ydata,Zdata,Zinverse)]
# create the data frame
df = pd.DataFrame(data, columns=['X','Y','Z',"Zi"], index=zip(Xdata,Ydata))
df.head(5)
Edit: This block of data is demo data that would normally come from a query on a
database that may need more cleaning and transforms before plotting. In this case data is already aligned and there are no problems aside having one more column we don't need (Zi).
So the numbers in pattern are transferred into height data in the Z column of df ('Zi' being the inverse image) and with that as the data frame I've struggled to come up with this pivot method which is 3 separate operations. I wonder if that can be better.
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.cm as cm
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
Xs = df.pivot(index='X', columns='Y', values='X').values
Ys = df.pivot(index='X', columns='Y', values='Y').values
Zs = df.pivot(index='X', columns='Y', values='Z').values
ax.plot_surface(Xs,Ys,Zs, cmap=cm.RdYlGn)
plt.show()
Although I have something working I feel there must be a better way than what I'm doing. On a big data set I would imagine doing 3 pivots is an expensive way to plot something. Is there a more efficient way to transform this data ?
I guess you can avoid some steps during the preparation of the data by not using pandas (but only numpy arrays) and by using some convenience fonctions provided by numpy such as linespace and meshgrid.
I rewrote your code to do so, trying to keep the same logic and the same variable names :
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
pattern = ("....1...."
"....1...."
"..11111.."
".1133311."
"111393111"
".1133311."
"..11111.."
"....1...."
"....1....")
# Extract the value according to your logic
Zdata = list(map(lambda d:0 if d == '.' else int(d), pattern))
# Assuming the pattern is always a square
size = int(len(Zdata) ** 0.5)
# Create a mesh grid for plotting the surface
Xdata = np.linspace(1, size, size)
Ydata = np.linspace(1, size, size)
Xs, Ys = np.meshgrid(Xdata, Ydata)
# Convert the Zdata to a numpy array with the appropriate shape
Zs = np.array(Zdata).reshape((size, size))
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
# Plot the surface
ax.plot_surface(Xs, Ys, Zs, cmap=cm.RdYlGn)
plt.show()
I am trying to plot vehicle position (coordinates - x,y) against time(1s,2s,3s...). I tried with matplotlib but could not succeed. I am new in python. Could anyone help me please.
My code:
import matplotlib.pyplot as plt
import numpy as np
coordinate = [[524.447876,1399.091919], [525.1377563,1399.95105], [525.7932739,1400.767578], [526.4627686,1401.601563],
[527.2360229,1402.564575], [527.8989258,1403.390381], [528.5689697,1404.224854]]
timestamp =[0,0.05,0.1,0.15,0.2,0.25,0.3]
plt.plot(coordinate,timestamp)
Plot comes like: But this is wrong one. I did wrong.
Plot supposed to become, in particular, timestamp (1s) the vehicle position is (x,y). So there should be one line just like vehicle trajectory.
Thanks.
I believe this is the output you're looking for:
import matplotlib.pyplot as plt
import numpy as np
coordinate = [[524.447876,1399.091919],
[525.1377563,1399.95105],
[525.7932739,1400.767578],
[526.4627686,1401.601563],
[527.2360229,1402.564575],
[527.8989258,1403.390381],
[528.5689697,1404.224854]]
v1 = [y[1] for y in coordinate]
v2 = [y[0] for y in coordinate]
x = [0,0.05,0.1,0.15,0.2,0.25,0.3]
plt.plot(x,v1)
plt.plot(x,v2,'--')
plt.ylim(0,1500)
plt.show()
Does something simple like this meet your needs:
import matplotlib.pyplot as plt
coordinates = [
(524.447876,1399.091919),
(525.1377563,1399.95105),
(525.7932739,1400.767578),
(526.4627686,1401.601563),
(527.2360229,1402.564575),
(527.8989258,1403.390381),
(528.5689697,1404.224854),
]
timestamp = [0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3]
x, y = zip(*coordinates)
ax = plt.axes(projection="3d")
ax.plot(x, y, timestamp);
plt.show()
Matplotlib will let you rotate the image with the mouse to view it from various angles.
Hi I think the problem over here is that you are using a two-dimensional list, so matplotlib plots the coordinates and not the timestamp.
Code:
import matplotlib.pyplot as plt
import numpy as np
coordinate = np.array([[524.447876,1399.091919], [525.1377563,1399.95105], [525.7932739,1400.767578], [526.4627686,1401.601563], [527.2360229,1402.564575], [527.8989258,1403.390381], [528.5689697,1404.224854]])
timestamp =np.array([0,0.05,0.1,0.15,0.2,0.25,0.3])
plt.plot(coordinate)
Output:
You have to convert it into a single dimension list like this:
coordinate_new = np.array([524.447876,525.1377563,1399.95105, 525.7932739,1400.767578, 526.4627686,1401.601563])
timestamp =np.array([0,0.05,0.1,0.15,0.2,0.25,0.3])
plt.plot(coordinate_new, timestamp)
Then the output will be:
Hope I could help!!
If you want to plot it in 3-d, here is what you can do:
import matplotlib.pyplot as plt
#importing matplotlib
fig = plt.figure() #adding figure
ax_3d = plt.axes(projection="3d") #addign 3-d axes
coordinate_x = [524.447876, 525.137756, 525.7932739, 526.4627686, 527.2360229, 527.8989258, 528.5689697]
coordinate_y = [1399.091919, 1399.95105,1400.767578,1401.601563,1402.564575,1403.390381,1404.224854]
timestamp =[0,0.05,0.1,0.15,0.2,0.25,0.3]
# defining the variables
ax.plot(coordinate_x, coordinate_y, timestamp)
#plotting them
Output:
All the Best!
I have a set of x,y,z data on an irregular grid. I tried to interpolate the same on a regular grid using griddata. Now, how can i extract the output (X,Y,Z) to a file in Python. Any help is much appreciated.
The code is as shown below
import numpy as np
import matplotlib.pyplot as plt
import numpy.ma as ma
from numpy.random import uniform
import matplotlib.pyplot as plt
from scipy.interpolate import griddata
# Read data from an existing dataframe
x = df['X']
y = df['Y']
z = df['WD']
# define grid.
xi = np.linspace(-4900,6000,100)
yi = np.linspace(-5200,7700,100)
# grid the data.
zi = griddata((x, y), z, (xi[None,:], yi[:,None]), method='cubic')
xn=[]
yn=[]
l=1
for i in range(0, len(xi)):
for j in range(0, len(yi)):
xn[l]=xi[i]
yn[l]=yi[j]
l=l+1
d = np.vstack((xn,yn,zi))
np.savetxt("file.csv", d, delimiter=",", fmt='% 4d')
Apparently this method works tills extracting the zi values using griddata, and not beyond that.
I am trying to extract the xi,yi,zi from the griddata and write this information to a file to be used by another program.
Can anyone advice on how to go about it?
I have a sequence of data files which contain two columns of data (x value, and z value). I want to asign each file with a unique constant y value with a loop and then use x,y,z values to make a contour plot.
import glob
import matplotlib.pyplot as plt
import numpy as np
files=glob.glob('C:\Users\DDT\Desktop\DATA TIANYU\materials\AB2O4\synchronchron\OX1\YbFe1Mn1O4_2cyc_600_meth_ox1-*.xye')
s1=1
for file in files:
t1=s1/3
x,z = np.loadtxt(file,skiprows=3,unpack=True, usecols=[0,1])
def f(x, y):
return x*0 +y*0 +z
l1=np.size(x)
y=np.full(l1, t1,dtype=int)
X,Y=np.meshgrid(x,y)
Z = f(X,Y)
plt.contour(X,Y,Z)
s1=s1+1
continue
plt.show()
There is no error in this code, however what I got is an empty figure with nothing.
What mistake did I make?
It is very hard to guess what you're trying to do. Here is an attempt. It supposes that all x-arrays are equal. And that the y really makes sense (although that is hard if the files are read in an unspecified order). To get a useful plot, the data from all the files should be collected before starting to plot.
import glob
import matplotlib.pyplot as plt
import numpy as np
files = glob.glob('........')
zs = []
for file in files:
x, z = np.loadtxt(file, skiprows=3, unpack=True, usecols=[0, 1])
zs.append(z)
# without creating a new x, the x from the last file will be used
# x = np.linspace(0, 15, 10)
y = np.linspace(-100, 1000, len(zs))
zs = np.array(zs)
fig, axs = plt.subplots(ncols=2)
axs[0].scatter(np.tile(x, y.size), np.repeat(y, x.size), c=zs)
axs[1].contour(x, y, zs)
plt.show()
With simulated random data, the scatter plot and the contour plot would look like:
I want to plot a coloured contour graph with x,y,z from 3 columns of a comma delimited text file, but each time I try the code below, I get ValueError: too many values to unpack (expected 3) error. I would be grateful if that could be resolved.
I would also like to know if there is another (probably better) code for plotting the 3 independent columns.
This is the code:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
import scipy.interpolate
N = 100000
long_col, lat_col, Bouguer_col = np.genfromtxt(r'data.txt', unpack=True)
xi = np.linspace(long_col.min(), long_col.max(), N)
yi = np.linspace(lat_col.min(), lat_col.max(), N)
zi = scipy.interpolate.griddata((long_col, lat_col), Bouguer_col, (xi[None,:], yi[:,None]), method='cubic')
fig = plt.figure()
plt.contourf(xi, yi, zi)
plt.xlabel("Long")
plt.ylabel("Lat")
plt.show()
This is the 'data.txt' sample data.
Lat, Long, Elev, ObsGrav, Anomalies
6.671482000000001022e+00,7.372505999999999560e+00,3.612977999999999952e+02,9.780274000000000233e+05,-1.484474523360840976e+02
6.093078000000000216e+00,7.480882000000001142e+00,1.599972999999999956e+02,9.780334000000000233e+05,-1.492942383352201432e+02
6.092045999999999850e+00,7.278669999999999973e+00,1.462445999999999913e+02,9.780663000000000466e+05,-1.190960417173337191e+02
6.402087429999999912e+00,7.393360939999999992e+00,5.237939999999999827e+02,9.780468000000000466e+05,-8.033459449396468699e+01
6.264082730000000154e+00,7.518244540000000420e+00,2.990849999999999795e+02,9.780529000000000233e+05,-1.114865156192099676e+02
6.092975000000000030e+00,7.482914000000000065e+00,1.416474000000000046e+02,9.780338000000000466e+05,-1.525697779102483764e+02
6.383570999999999884e+00,7.289616999999999791e+00,2.590403000000000020e+02,9.780963000000000466e+05,-8.300666170357726514e+01
6.318417000000000172e+00,7.557638000000000744e+00,1.672036999999999978e+02,9.780693000000000466e+05,-1.246774551668204367e+02
6.253779999999999895e+00,7.268805999999999656e+00,1.059429999999999978e+02,9.781026999999999534e+05,-9.986763240839354694e+01
6.384635000000000282e+00,7.291032000000000401e+00,2.615624000000000251e+02,9.780963000000000466e+05,-8.256190758384764194e+01
If the data file looks exactly like in the question you first of all have 5 columns, which you cannot unpack to 3 variables.
Next, you have a header line which you do not want to be part of the data. Also the header line is separated by ,<space>, while the data is separated by ,.
So in total you need
import numpy as np
a,b,c,d,e = np.genfromtxt("data.txt", unpack=True, delimiter=",", skip_header=1)