Question about plotting a 2D array in python - python

I have a question regarding the plotting of a 2D array with matplotlib. In my code, I have a 2D array named z of len(z) = 20 , and z has the values :
[[ 642.3774486 662.59980588 706.80142179 764.78786911 831.67963477
904.67872269 982.01426528 1062.49208551 1145.27029231 1229.73549967
1315.42936618 1402.00251422 1489.18433714 1576.7625077 1664.56866033
1752.46813939 1840.35250424 1928.13395024 2015.74109019 2103.11572013]
[ 554.60565024 560.31827232 591.87923587 638.51633542 695.03697015
758.44479983 826.83191468 898.90395242 973.74278531 1050.67523901
1129.19496311 1208.91328775 1289.52693752 1370.79606051 1452.52883572
1534.57042218 1616.79485775 1699.09901217 1781.39800199 1863.6216653 ]
[ 484.80770831 476.01059519 494.93090638 530.21865818 576.36816197
630.18473341 689.62342052 753.28967576 820.18913475 889.58883479
960.93441647 1033.79791772 1107.84339435 1182.80346976 1258.46286755
1334.64656142 1411.2110677 1488.03793055 1565.02877024 1642.1014669 ]
[ 432.98362283 409.67677451 415.95643334 439.89483737 475.67321023
519.89852343 570.3887828 625.64925554 684.60934062 746.47628701
810.64772628 876.65640413 944.13370762 1012.78473545 1082.37075581
1152.6965571 1223.60113409 1294.95070536 1366.63339492 1438.55512495]
[ 399.13339379 361.31681026 354.95581673 367.54487301 392.95211493
427.58616989 469.12800152 515.98269176 567.00340294 621.33759567
678.33489253 737.48874699 798.39787733 860.73985757 924.25250052
988.72040921 1053.96505692 1119.83733661 1186.21187604 1252.98263943]
[ 383.25702119 330.93070245 311.92905657 313.16876508 328.20487607
353.24767279 385.84107667 424.28998442 467.37132169 514.17276077
563.99591521 616.29494628 670.63590348 726.66883614 784.10810167
842.71811777 902.30283619 962.6978243 1023.76421361 1085.38401036]
[ 385.35450503 318.51845109 286.87615284 276.7665136 281.43149365
296.88303213 320.52800827 350.57113352 385.71309689 424.98178231
467.63079434 513.07500201 560.84778607 610.57167115 661.93755925
714.68968276 768.6144719 823.53216843 879.29040761 935.75923772]
[ 405.4258453 324.08005616 279.79710556 258.33811855 252.63196767
258.49224791 273.18879631 294.82613906 322.02872853 353.76466029
389.23952991 427.82891418 469.0335251 512.44836259 557.74087328
604.6351042 652.89996405 702.340369 752.79045805 804.10832153]
[ 443.47104202 347.61551768 290.69191471 257.88357994 241.80629812
238.07532013 243.82344079 257.05500104 276.3182166 300.52139471
328.82212191 360.55668279 395.19312056 432.29891048 471.51804375
512.55438207 555.15931264 599.12242601 644.26436494 690.43126177]
[ 499.49009518 389.12483563 319.56058031 275.40289778 248.95448502
235.63224878 232.43194171 237.25771947 248.58156112 265.25198557
286.37857036 311.25830784 339.32657247 370.12331481 403.26907065
438.44751639 475.39251767 513.87833946 553.71212826 594.72805845]
[ 573.48300477 448.60801002 366.40310234 310.89607205 274.07652836
251.16303388 239.01429907 235.43429433 238.81876207 247.95643287
261.90887525 279.93378933 301.43388082 325.92157557 352.993954
382.31450714 413.59957914 446.60810935 481.13374802 516.99871158]
[ 665.44977081 526.06504086 431.21948081 364.36310276 317.17242814
284.66767542 263.57051287 251.58472563 247.02981947 248.63473661
255.41303657 266.58312726 281.51504561 299.69369278 320.69269378
344.15535434 369.78049705 397.31173568 426.52922422 457.24322114]
[ 775.39039329 621.49592813 514.00971573 435.80398992 378.24218436
336.1461734 306.10058311 285.70901337 273.2147333 267.28689679
266.89105434 271.20632163 279.57006684 291.43966643 306.36529001
323.97005797 343.9352714 365.98921845 389.89855687 415.46158715]
[ 903.3048722 734.90067184 614.77380708 525.21873351 457.28579702
405.59852782 366.60450978 337.80715755 317.37350358 303.91291341
296.34292854 293.80337244 295.5989445 301.15949651 310.01174267
321.75861805 336.06390219 352.64055766 371.24174595 391.65380959]
[1049.19320756 866.27927199 733.51175488 632.60733354 554.30326611
493.02473868 445.0822929 407.87915817 379.50613029 358.51278647
343.76865919 334.37427969 329.60167861 328.85318304 331.63205178
337.52103456 346.16638942 357.26575331 370.55879147 385.81988847]
[1213.05539936 1015.63172859 870.22355911 757.96979001 669.29459165
598.42480597 541.53393246 495.92501523 459.61261345 431.08651597
409.16824628 392.91904338 381.57826916 374.520726 371.22621733
371.25730752 374.24273309 379.8648054 387.84969343 397.9598238 ]
[1394.89144759 1182.95804162 1024.90921978 901.30610293 802.25977363
721.79872971 655.95942846 601.94472873 557.69295304 521.63410191
492.5416898 469.43766351 451.52871614 438.16212541 428.79423931
422.96743691 420.2929332 420.43771393 423.11445184 428.07361556]
[1594.70135227 1368.25821109 1197.5687369 1062.61627228 953.19881205
863.14650989 788.3587809 725.93829867 673.74714907 630.15554429
593.88898977 563.93014008 539.45301957 519.77738125 504.33611774
492.65142275 484.31698975 478.9844789 476.35306668 476.16126376]
[1812.48511338 1571.532237 1388.20211045 1241.90029807 1122.11170691
1022.46814651 938.73198977 867.90572504 807.77520155 756.65084311
713.21014617 676.39647309 645.35117944 619.36649354 597.8518526
580.30926502 566.31490274 555.50510031 547.56553796 542.22276841]
[2048.24273094 1792.78011936 1596.80934044 1439.1581803 1308.9984582
1199.76363956 1107.07905509 1027.84700786 959.77711046 901.11999837
850.50515902 806.83666254 769.22319574 736.92946227 709.34144391
685.94096373 666.28667217 649.99957816 636.75186568 626.25812949]]
I wanted to plot the first 20 set of data of z, so z[0] against my other variable M. I did the following:
M = np.arange(15.5,16.5, 0.05)
plt.plot(M, Z[0], label = r'$\chi^2$ for $\Omega_m[0] $ ')
and it gave me the folllwing plot (ignore the label whith color blue, there were 2 same datas plotted and only one label) :
Then I tried the following code, which gave me the other pic.
plt.plot(M, Z[0:20], label = r'$\chi^2$ for$\Omege_m = 0$ ')
But I don't understand why, with the same data, the shape of the function is obviously different between the two pics. Could anyone explain me why the second image is different from the first one, and what does it plot exactly ? How does matplotlib plot a 2D array ?
And if i can explain a bit the background of z, it is a function that depends on 2 parameters, M and Omega_M, Omega_m = np.arange(0.0, 1.0, 0.05) (len(Omega_m) =20) and z[0] corresponds to the 20 values of the Z function for each value of Omega_m and for M[0], z1 correspond of the 20 values of the Z function for each values of Omega_m for M1 etc, until the function is calculated for each value of each parameter.

First, let's explain why the two graphs differ. Because in the first graph, you're plotting the first row of Z with M. In the second graph, you're drawing the columns of Z with M. And this became so clear when I tried to plot the first three columns of Z:
plt.plot(M, Z[:, 0], label = r'$\chi^2$ for $\Omega_m[0] $ ')
plt.plot(M, Z[:, 1], label = r'$\chi^2$ for $\Omega_m[0] $ ')
plt.plot(M, Z[:, 2], label = r'$\chi^2$ for $\Omega_m[0] $ ')
plt.show()
Which produced this graph:
And that makes total sense as it will throw an error when I pass Z with one less row:
plt.plot(M, Z[0:19], label = r'$\chi^2$ for $\Omega_m[0] $ ')
ValueError: x and y must have same first dimension, but have shapes (20,) and (19, 20)
So, to produce 20 curves that match the rows of Z, not the columns, you need to transpose your Z array using Z.T notation like so:
plt.plot(M, Z.T, label = r'$\chi^2$ for $\Omega_m[0] $ ')
plt.show()
Which will get this graph:

Related

Python homogeneous to inhomogeneous plot line

I found an article which is about epipolar geometry.
I calculated the fundamental matrix. Now Iam trying to find the line on which a corresponding point lays as described in the article:
I calculated the line which is in homogeneous coordinates. How could I plot this line into the picture like in the example? I thought about transforming the line from homogeneous to inhomogeneous coordinates. I think this can be achieved by dividing x and y by z
For example, homogeneous:
x=0.0295
y=0.9996
z=-265.1531
to inhomogeneous:
x=0.0295/-265.1531
y=0.9996/-265.1531
so:
x=-0.0001112564778612809
y=0.0037698974667842843
Those numbers seem wrong to me, because theyre so small. Is this the correct approach?
How could I plot my result into an image?
the x, y and z you have are the parameters of the "Epipolar Lines" equation that appear under the "line in the image" formula in the slides, but labelled a, b and c respectively, i.e:
au + bv + c = 0
solutions to this are points on the line. e.g. in Python I'd define a as some points on the picture's x-axis, and solve for b:
import numpy as np
F = np.array([
[-0.00310695, -0.0025646, 2.96584],
[-0.028094, -0.00771621, 56.3813],
[13.1905, -29.2007, -9999.79],
])
p_l = np.array([
[343.53],
[221.70],
[ 1.0],
])
lt = F # p_l
# if you want to normalise
lt /= np.sqrt(sum(lt[:2] ** 2))
# should give your values [0.0295, 0.9996, -265.2]
print(lt)
a, b, c = lt.ravel()
x = np.array([0, 400])
y = -(x*a + c) / b
and then just draw a line between these points

How to convert A[x,y] = z to [ [ x0...xN ], [ y0...yN], [ z0...zN] ]

I have a 2D Numpy array that represents an image, and I want to create a surface plot of image intensity using matplotlib.surface_plot. For this function, I need to convert the 2D array A[x,y] => z into three arrays: [x0,...,xN], [y0,...,yN] and [z0,...,zN]. I can see how to do this conversion element-by-element:
X = []
Y = []
Z = []
for x in range( A.shape[ 0 ] ):
for y in range( A.shape[ 1 ] ):
X.append( x )
Y.append( y )
Z.append( A[x,y] )
but I'm wondering whether there is a more Pythonic way to do this?
a very simple way to do this could be to basically use the code shown in the matplotlib example. assuming x and y representing the sizes of the two dims in your image array A, you could do
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
# generate some input data that looks nice on a color map:
A = np.mgrid[0:10:0.1,0:10:0.1][0]
X = np.arange(0, A.shape[0], 1)
Y = np.arange(0, A.shape[1], 1)
X, Y = np.meshgrid(X, Y)
fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(X, Y, A, cmap='viridis',
linewidth=0, antialiased=False)
gives
You possibly don't need to construct the actual grid, because some pyplot functions accept 1d arrays for x and y, implying that a grid is to be constructed. It seems that Axes3D.plot_surface (which I presume you meant) does need 2d arrays as input, though.
So to get your grid the easiest way is using np.indices to get the indices corresponding to your array:
>>> import numpy as np
...
... # dummy data
... A = np.random.random((3,4)) # randoms of shape (3,4)
...
... # get indices
... x,y = np.indices(A.shape) # both arrays have shape (3,4)
...
... # prove that the indices correspond to the values of A
... print(all(A[i,j] == A[x[i,j], y[i,j]] for i in x.ravel() for j in y.ravel()))
True
The resulting arrays all have the same shape as A, which should be correct for most use cases. If for any reason you really need a flattened 1d array, you should use x.ravel() etc. to get a flattened view of the same 2d array.
I should note though that the standard way to visualize images (due to the short-wavelength variation of the data) is pyplot.imshow or pyplot.pcolormesh which can give you pixel-perfect visualization, albeit in two dimensions.
We agree X, Y and Z have different sizes (N for X and Y and N^2 for Z) ? If yes:
X looks not correct (you add several times the same values)
something like:
X = list(range(A.shape[0])
Y = list(range(A.shape[1])
Z = [A[x,y] for x in X for y in Y]

How to crop and interpolate part of an image with python [duplicate]

I have used interp2 in Matlab, such as the following code, that is part of #rayryeng's answer in: Three dimensional (3D) matrix interpolation in Matlab:
d = size(volume_image)
[X,Y] = meshgrid(1:1/scaleCoeff(2):d(2), 1:1/scaleCoeff(1):d(1));
for ind = z
%Interpolate each slice via interp2
M2D(:,:,ind) = interp2(volume_image(:,:,ind), X, Y);
end
Example of Dimensions:
The image size is 512x512 and the number of slices is 133. So:
volume_image(rows, columns, slices in 3D dimenson) : 512x512x133 in 3D dimenson
X: 288x288
Y: 288x288
scaleCoeff(2): 0.5625
scaleCoeff(1): 0.5625
z = 1 up to 133 ,hence z: 1x133
ind: 1 up to 133
M2D(:,:,ind) finally is 288x288x133 in 3D dimenson
Aslo, Matlabs syntax for size: (rows, columns, slices in 3rd dimenson) and Python syntax for size: (slices in 3rd dim, rows, columns).
However, after convert the Matlab code to Python code occurred an error, ValueError: Invalid length for input z for non rectangular grid:
for ind in range(0, len(z)+1):
M2D[ind, :, :] = interpolate.interp2d(X, Y, volume_image[ind, :, :]) # ValueError: Invalid length for input z for non rectangular grid
What is wrong? Thank you so much.
In MATLAB, interp2 has as arguments:
result = interp2(input_x, input_y, input_z, output_x, output_y)
You are using only the latter 3 arguments, the first two are assumed to be input_x = 1:size(input_z,2) and input_y = 1:size(input_z,1).
In Python, scipy.interpolate.interp2 is quite different: it takes the first 3 input arguments of the MATLAB function, and returns an object that you can call to get interpolated values:
f = scipy.interpolate.interp2(input_x, input_y, input_z)
result = f(output_x, output_y)
Following the example from the documentation, I get to something like this:
from scipy import interpolate
x = np.arange(0, volume_image.shape[2])
y = np.arange(0, volume_image.shape[1])
f = interpolate.interp2d(x, y, volume_image[ind, :, :])
xnew = np.arange(0, volume_image.shape[2], 1/scaleCoeff[0])
ynew = np.arange(0, volume_image.shape[1], 1/scaleCoeff[1])
M2D[ind, :, :] = f(xnew, ynew)
[Code not tested, please let me know if there are errors.]
You might be interested in scipy.ndimage.zoom. If you are interpolating from one regular grid to another, it is much faster and easier to use than scipy.interpolate.interp2d.
See this answer for an example:
https://stackoverflow.com/a/16984081/1295595
You'd probably want something like:
import scipy.ndimage as ndimage
M2D = ndimage.zoom(volume_image, (1, scaleCoeff[0], scaleCoeff[1])

flipping and rotating numpy arrays for contour plots

Short Version:
I have a 10x10 numpy array whose contour plot (plotted with pyplot.contourf) looks like this
Now, I want it look something like this - assuming the plot is symmetric across X and Y axes.
Long version
I have a 10x10 numpy array z as a function of x and y. where x=y=np.arange(0.002,0.022,0.002). Here is what I tried
import numpy as np
import matplotlib.pyplot as plt
z=np.array([[ 2.08273679, -0.06591932, -1.14525488, -1.49923222, -1.74361248,
-1.81418446, -1.90115591, -1.94329043, -1.93130228, -1.96064259],
[ 0.20180514, -0.94522815, -1.34635828, -1.58844515, -1.7528935 ,
-1.84438752, -1.86257547, -1.9439332 , -1.99009407, -1.94829146],
[-1.09749238, -1.48234452, -1.64234357, -1.75344742, -1.83019763,
-1.88547473, -1.92958533, -1.940775 , -1.95535063, -1.9629588 ],
[-1.62892483, -1.70176401, -1.76263555, -1.84966414, -1.87139241,
-1.91879916, -1.90796703, -1.96632612, -1.95794984, -1.94585536],
[-1.71551518, -1.91806287, -1.86999609, -1.90800839, -1.92515012,
-1.93386969, -1.96487487, -1.95405297, -1.97032435, -1.96087146],
[-1.81904322, -1.94790171, -2. , -1.96932249, -1.91842475,
-1.98101775, -1.98521938, -1.97618539, -1.95892852, -2.01410874],
[-1.8138236 , -1.90877811, -1.93966404, -1.98406259, -1.95253807,
-1.95867436, -1.96679456, -2.01126218, -1.99885932, -1.99369292],
[-1.9927308 , -1.97658099, -1.91586737, -1.96813381, -1.98416011,
-1.98639893, -1.99997964, -1.99746813, -1.98126505, -1.97767361],
[-1.96406473, -1.92609437, -1.99171257, -1.94687523, -1.9823819 ,
-1.97786533, -2.02323228, -1.98559114, -1.99172681, -2.00881064],
[-1.92470024, -1.99537152, -1.99419303, -1.97261023, -1.9673841 ,
-1.98801505, -2.02412735, -2.01394008, -2.01956817, -2.04963448]])
x=y=np.arange(0.002,0.022,0.002)
#The following gives the plot I currently have
plt.figure()
plt.contourf(x,y,z)
plt.show()
#Tried to flip the matrix z using np.flipud and np.fliplr
plt.figure()
plt.contourf(x,y,z)
plt.contourf(-x,y,np.fliplr(z))
plt.contourf(x,-y,np.flipud(z))
plt.contourf(-x,-y,np.flipud(np.fliplr(z)))
plt.show()
#Also tried to rotate the matrix z using np.rot90
plt.figure()
plt.contourf(x,y,z)
plt.contourf(x,-y,np.rot90(z))
plt.contourf(-x,-y,np.rot90(z,2))
plt.contourf(-x,y,np.rot90(z,3))
plt.show()
I get the following plots with the above code
and
Ideally I would also like to fill the discontinuity at the origin by interpolation of the plot. But for starters, would like to get the orientation right. Any help is greatly appreciated.
Your problem is that, even though you negate x and y, their order stays the same, so with negative x, you go from -0.002 to -0.022, which means that the flipped z gets flipped back during the plotting. To achieve what you want, you can do the following:
#either don't flip z
plt.figure()
plt.contourf(x,y,z)
plt.contourf(-x,y,z)
plt.contourf(x,-y,z)
plt.contourf(-x,-y,z)
plt.show()
#or reverse also -x and -y:
plt.figure()
plt.contourf(x,y,z)
plt.contourf(-x[::-1],y,np.fliplr(z))
plt.contourf(x,-y[::-1],np.flipud(z))
plt.contourf(-x[::-1],-y[::-1],np.flipud(np.fliplr(z)))
plt.show()
If you would have just concatenated z and the flipped z, everything would have worked as expected. plt.contourf takes care of the interpolation itself.
ztotal = np.concatenate([np.fliplr(z),z],axis=1)
ztotal = np.concatenate([np.flipud(ztotal),ztotal],axis=0)
xtotal = np.concatenate([-x[::-1],x],axis=0)
ytotal = np.concatenate([-y[::-1],y],axis=0)
plt.figure()
plt.contourf(xtotal,ytotal,ztotal)
plt.show()
Combine results of fliplr and flipud of your array z to a new double sized array zz then plot it. You have to skip x and y in interval (-0.002; +0.002) with nan values according to your first figure:
import numpy as np
import matplotlib.pyplot as plt
z=np.array([[ 2.08273679, -0.06591932, -1.14525488, -1.49923222, -1.74361248,
-1.81418446, -1.90115591, -1.94329043, -1.93130228, -1.96064259],
[ 0.20180514, -0.94522815, -1.34635828, -1.58844515, -1.7528935 ,
-1.84438752, -1.86257547, -1.9439332 , -1.99009407, -1.94829146],
[-1.09749238, -1.48234452, -1.64234357, -1.75344742, -1.83019763,
-1.88547473, -1.92958533, -1.940775 , -1.95535063, -1.9629588 ],
[-1.62892483, -1.70176401, -1.76263555, -1.84966414, -1.87139241,
-1.91879916, -1.90796703, -1.96632612, -1.95794984, -1.94585536],
[-1.71551518, -1.91806287, -1.86999609, -1.90800839, -1.92515012,
-1.93386969, -1.96487487, -1.95405297, -1.97032435, -1.96087146],
[-1.81904322, -1.94790171, -2. , -1.96932249, -1.91842475,
-1.98101775, -1.98521938, -1.97618539, -1.95892852, -2.01410874],
[-1.8138236 , -1.90877811, -1.93966404, -1.98406259, -1.95253807,
-1.95867436, -1.96679456, -2.01126218, -1.99885932, -1.99369292],
[-1.9927308 , -1.97658099, -1.91586737, -1.96813381, -1.98416011,
-1.98639893, -1.99997964, -1.99746813, -1.98126505, -1.97767361],
[-1.96406473, -1.92609437, -1.99171257, -1.94687523, -1.9823819 ,
-1.97786533, -2.02323228, -1.98559114, -1.99172681, -2.00881064],
[-1.92470024, -1.99537152, -1.99419303, -1.97261023, -1.9673841 ,
-1.98801505, -2.02412735, -2.01394008, -2.01956817, -2.04963448]])
x=y=np.linspace(-0.020,0.020,21)
zz = np.empty((21,21)); zz[:,:] = np.nan
zz[11:,11:] = z
zz[11:,:10] = np.fliplr(z)
zz[:10,:] = np.flipud(zz[11:,:])
plt.figure()
plt.contourf(x,y,zz)
plt.show()
To fill the gap skip one point of coordinate arrays:
...
x=y=np.linspace(-0.020,0.020,20)
zz = np.empty((20,20)); zz[:,:] = np.nan
zz[10:,10:] = z
zz[10:,:10] = np.fliplr(z)
zz[:10,:] = np.flipud(zz[10:,:])
...

I have this list with x and y coordinates that are in interval of [-2,2]. But when I plot the list, x exceeds the value of 2 by far. Python

clist=[(-1.2720626442476508, 0.023952387163360456),
(1.509233613482305, -1.196551723413994),
(-0.37776845297034178, -1.9620288805522699),
(-0.95028695770255522, -1.5670871848691932),
(-0.19286972570683192, -1.2638500626369975),
(1.19847548993563, 0.32781113190011446),
(-0.93998357957640977, 0.74954973932266267),
(-0.65151553614971647, -0.65350263688351395),
(-0.65151553614971647, -0.65350263688351395)]
fig = plt.figure()
ax = plt.axes(xlim=(-2, 200), ylim=(-2, 2))
plt.plot(clist,'ro')
plt.show()
As you can see the x coordinate exceeds the value 2. The y coordinate is right.
plt.plot(array) will plot an array of assumed y coordinates over a sequence of x coordinates. You'll need to explicitly pass plt.plot(xdata,ydata) to plot correctly.
In this case plot(array) is taking your input to mean: (y-value, y-value) at x = 0, (y-value, y-value) at x = 1, etc.

Categories