How to draw a circle with matplotlib.pyplot [duplicate] - python
This question already has answers here:
Why is matplotlib plotting my circles as ovals?
(3 answers)
Closed 2 years ago.
I'm trying to draw a circle using pyplot. However, in the plot is looks like an ellipse.
The variable r can have any value.
theta = np.linspace(0, 2*np.pi, 100)
r= r/2
x = r*np.cos(theta)
y = r*np.sin(theta)
plt.plot(x,y)
Use the pyplot.axis('equal') method (documentation). This will tell matplotlib to automatically keep the x and y axis scaling equal and will work even if you change the axis limits:
import matplotlib.pyplot as plt
import numpy as np
theta = np.linspace(0, 2*np.pi, 100)
r= 2
x = r*np.cos(theta)
y = r*np.sin(theta)
plt.plot(x,y)
plt.axis('equal')
plt.show()
As you can see, this causes circles to be circles even if the x and y axis have different limits. It also allows for autoscaling if additional items are added to the plot and it will maintain the aspect ratio when the plot area is modified by adding axis labels or a plot title.
There are additional examples of this in the Matplotlib documentation: Axis Equal Demo.
Another option is to use pyplot.axis('scaled'), which changes the dimensions of the plot box to make the axis scaling equal. The difference is that this option will block further autoscaling after it has been set.
For example, with 'scaled' axes, matplotlib will respect the values you specify for the x- and y-axis limits:
import matplotlib.pyplot as plt
import numpy as np
theta = np.linspace(0, 2*np.pi, 100)
r= 2
x = r*np.cos(theta)
y = r*np.sin(theta)
plt.plot(x,y)
plt.axis('scaled')
plt.ylim(-3, 3)
plt.xlim(-3, 3)
plt.show()
Your code is correct. Most likely the aspect ratio of your figure is not equal. Setting the figsize to equal arguments should fix that
theta = np.linspace(0, 2*np.pi, 100)
r= r/2
x = r*np.cos(theta)
y = r*np.sin(theta)
plt.figure(figsize=(10,10))
plt.plot(x,y)
Related
How to convert a matrix to heatmap image in torch [duplicate]
Using Matplotlib, I want to plot a 2D heat map. My data is an n-by-n Numpy array, each with a value between 0 and 1. So for the (i, j) element of this array, I want to plot a square at the (i, j) coordinate in my heat map, whose color is proportional to the element's value in the array. How can I do this?
The imshow() function with parameters interpolation='nearest' and cmap='hot' should do what you want. Please review the interpolation parameter details, and see Interpolations for imshow and Image antialiasing. import matplotlib.pyplot as plt import numpy as np a = np.random.random((16, 16)) plt.imshow(a, cmap='hot', interpolation='nearest') plt.show()
Seaborn is a high-level API for matplotlib, which takes care of a lot of the manual work. seaborn.heatmap automatically plots a gradient at the side of the chart etc. import numpy as np import seaborn as sns import matplotlib.pylab as plt uniform_data = np.random.rand(10, 12) ax = sns.heatmap(uniform_data, linewidth=0.5) plt.show() You can even plot upper / lower left / right triangles of square matrices. For example, a correlation matrix, which is square and is symmetric, so plotting all values would be redundant. corr = np.corrcoef(np.random.randn(10, 200)) mask = np.zeros_like(corr) mask[np.triu_indices_from(mask)] = True with sns.axes_style("white"): ax = sns.heatmap(corr, mask=mask, vmax=.3, square=True, cmap="YlGnBu") plt.show()
I would use matplotlib's pcolor/pcolormesh function since it allows nonuniform spacing of the data. Example taken from matplotlib: import matplotlib.pyplot as plt import numpy as np # generate 2 2d grids for the x & y bounds y, x = np.meshgrid(np.linspace(-3, 3, 100), np.linspace(-3, 3, 100)) z = (1 - x / 2. + x ** 5 + y ** 3) * np.exp(-x ** 2 - y ** 2) # x and y are bounds, so z should be the value *inside* those bounds. # Therefore, remove the last value from the z array. z = z[:-1, :-1] z_min, z_max = -np.abs(z).max(), np.abs(z).max() fig, ax = plt.subplots() c = ax.pcolormesh(x, y, z, cmap='RdBu', vmin=z_min, vmax=z_max) ax.set_title('pcolormesh') # set the limits of the plot to the limits of the data ax.axis([x.min(), x.max(), y.min(), y.max()]) fig.colorbar(c, ax=ax) plt.show()
For a 2d numpy array, simply use imshow() may help you: import matplotlib.pyplot as plt import numpy as np def heatmap2d(arr: np.ndarray): plt.imshow(arr, cmap='viridis') plt.colorbar() plt.show() test_array = np.arange(100 * 100).reshape(100, 100) heatmap2d(test_array) This code produces a continuous heatmap. You can choose another built-in colormap from here.
Here's how to do it from a csv: import numpy as np import matplotlib.pyplot as plt from scipy.interpolate import griddata # Load data from CSV dat = np.genfromtxt('dat.xyz', delimiter=' ',skip_header=0) X_dat = dat[:,0] Y_dat = dat[:,1] Z_dat = dat[:,2] # Convert from pandas dataframes to numpy arrays X, Y, Z, = np.array([]), np.array([]), np.array([]) for i in range(len(X_dat)): X = np.append(X, X_dat[i]) Y = np.append(Y, Y_dat[i]) Z = np.append(Z, Z_dat[i]) # create x-y points to be used in heatmap xi = np.linspace(X.min(), X.max(), 1000) yi = np.linspace(Y.min(), Y.max(), 1000) # Interpolate for plotting zi = griddata((X, Y), Z, (xi[None,:], yi[:,None]), method='cubic') # I control the range of my colorbar by removing data # outside of my range of interest zmin = 3 zmax = 12 zi[(zi<zmin) | (zi>zmax)] = None # Create the contour plot CS = plt.contourf(xi, yi, zi, 15, cmap=plt.cm.rainbow, vmax=zmax, vmin=zmin) plt.colorbar() plt.show() where dat.xyz is in the form x1 y1 z1 x2 y2 z2 ...
Use matshow() which is a wrapper around imshow to set useful defaults for displaying a matrix. a = np.diag(range(15)) plt.matshow(a) https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.matshow.html This is just a convenience function wrapping imshow to set useful defaults for displaying a matrix. In particular: Set origin='upper'. Set interpolation='nearest'. Set aspect='equal'. Ticks are placed to the left and above. Ticks are formatted to show integer indices.
Here is a new python package to plot complex heatmaps with different kinds of row/columns annotations in Python: https://github.com/DingWB/PyComplexHeatmap
Plotting a heatmap with interpolation in Python using excel file
I need to plot a HEATMAP in python using x, y, z data from the excel file. All the values of z are 1 except at (x=5,y=5). The plot should be red at point (5,5) and blue elsewhere. But I am getting false alarms which need to be removed. The COLORMAP I have used is 'jet' X=[0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,9] Y=[0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9] Z=[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1] Code I have used is: import matplotlib.pyplot as plt import numpy as np from numpy import ravel from scipy.interpolate import interp2d import pandas as pd import matplotlib as mpl excel_data_df = pd.read_excel('test.xlsx') X= excel_data_df['x'].tolist() Y= excel_data_df['y'].tolist() Z= excel_data_df['z'].tolist() x_list = np.array(X) y_list = np.array(Y) z_list = np.array(Z) # f will be a function with two arguments (x and y coordinates), # but those can be array_like structures too, in which case the # result will be a matrix representing the values in the grid # specified by those arguments f = interp2d(x_list,y_list,z_list,kind="linear") x_coords = np.arange(min(x_list),max(x_list)) y_coords = np.arange(min(y_list),max(y_list)) z= f(x_coords,y_coords) fig = plt.imshow(z, extent=[min(x_list),max(x_list),min(y_list),max(y_list)], origin="lower", interpolation='bicubic', cmap= 'jet', aspect='auto') # Show the positions of the sample points, just to have some reference fig.axes.set_autoscale_on(False) #plt.scatter(x_list,y_list,400, facecolors='none') plt.xlabel('X Values', fontsize = 15, va="center") plt.ylabel('Y Values', fontsize = 15,va="center") plt.title('Heatmap', fontsize = 20) plt.tight_layout() plt.show() For your ease you can also use the X, Y, Z arrays instead of reading excel file. The result that I am getting is: Here you can see dark blue regions at (5,0) and (0,5). These are the FALSE ALARMS I am getting and I need to REMOVE these. I am probably doing some beginner's mistake. Grateful to anyone who points it out. Regards
There are at least three problems in your example: x_coords and y_coords are not properly resampled; the interpolation z does to fill in the whole grid leading to incorrect output; the output is then forced to be plotted on the original grid (extent) that add to the confusion. Leading to the following interpolated results: On what you have applied an extra smoothing with imshow. Let's create your artificial input: import matplotlib.pyplot as plt import numpy as np x = np.arange(0, 11) y = np.arange(0, 11) X, Y = np.meshgrid(x, y) Z = np.ones(X.shape) Z[5,5] = 9 Depending on how you want to proceed, you can simply let imshow smooth your signal by interpolation: fig, axe = plt.subplots() axe.imshow(Z, origin="lower", cmap="jet", interpolation='bicubic') And you are done, simple and efficient! If you aim to do it by yourself, then choose the interpolant that suits you best and resample on a grid with a higher resolution: interpolant = interpolate.interp2d(x, y, Z.ravel(), kind="linear") xlin = np.linspace(0, 10, 101) ylin = np.linspace(0, 10, 101) zhat = interpolant(xlin, ylin) fig, axe = plt.subplots() axe.imshow(zhat, origin="lower", cmap="jet") Have a deeper look on scipy.interpolate module to pick up the best interpolant regarding your needs. Notice that all methods does not expose the same interface for imputing parameters. You may need to reshape your data to use another objects. MCVE Here is a complete example using the trial data generated above. Just bind it to your excel columns: # Flatten trial data to meet your requirement: x = X.ravel() y = Y.ravel() z = Z.ravel() # Resampling on as square grid with given resolution: resolution = 11 xlin = np.linspace(x.min(), x.max(), resolution) ylin = np.linspace(y.min(), y.max(), resolution) Xlin, Ylin = np.meshgrid(xlin, ylin) # Linear multi-dimensional interpolation: interpolant = interpolate.NearestNDInterpolator([r for r in zip(x, y)], z) Zhat = interpolant(Xlin.ravel(), Ylin.ravel()).reshape(Xlin.shape) # Render and interpolate again if necessary: fig, axe = plt.subplots() axe.imshow(Zhat, origin="lower", cmap="jet", interpolation='bicubic') Which renders as expected:
How to produce a revolution of a 2D plot with matplotlib in Python [duplicate]
This question already has an answer here: How to draw a solid of revolution of a polynomial function around the y-axis? (1 answer) Closed 3 years ago. I have created a 2D plot using matplotlib in Python, an example being this one: It has been produced using 2 lists: import matplotlib.pyplot as plt import numpy as np plt.plot(X, Y) #X and Y are lists, containing the x and y coordinates of points respectively plt.show() Now I want to create a revolution of that plot around the Y-axis, and visualizing it in a way that the Y-axis is vertical. How can that be done using matplotlib?
If you have a curve defined as a collection of x and y points in two 1D arrays and you want to revolve them about the y axis you simply need to construct 2D arrays to satisfy matplotlib's Axes3D.plot_surface by taking the outer products, using np.outer(), of x with np.cos(theta) and np.sin(theta) for theta in [0, 2π]. This will give you a collection of cartesian points in xy space, which will represent the circles created by revolving each original point about the z axis. Constructing the z array is a bit tricky because of the shape expected by plot_surface(). Here is a complete example which demonstrates this method and compares it with the original 2D plot from mpl_toolkits.mplot3d import Axes3D import matplotlib.pyplot as plt import numpy as np n = 100 fig = plt.figure(figsize=(12,6)) ax1 = fig.add_subplot(121) ax2 = fig.add_subplot(122,projection='3d') y = np.linspace(np.pi/8, np.pi*4/5, n) x = np.sin(y) t = np.linspace(0, np.pi*2, n) xn = np.outer(x, np.cos(t)) yn = np.outer(x, np.sin(t)) zn = np.zeros_like(xn) for i in range(len(x)): zn[i:i+1,:] = np.full_like(zn[0,:], y[i]) ax1.plot(x, y) ax2.plot_surface(xn, yn, zn) plt.show()
Rasterization of contours in filled contour plot [duplicate]
This question already has an answer here: Reducing size of vectorized contourplot (1 answer) Closed 5 years ago. I have a filled contour plot, which I wish to save as an .svg or .pdf file. The following is a simplified example. I want to rasterize the contour plot itself (the colorful part!), while keeping everything else (all axes, labels etc.) as vector graphics. import numpy as np import matplotlib.pylab as plt x = np.linspace(0, 2*np.pi, 100) y = np.linspace(0, 2*np.pi, 100) xi, yi = np.meshgrid(x, y) zi = np.cos(xi)**2 + np.sin(yi)**2 plt.figure() plt.contourf(xi, yi, zi, rasterized=True) plt.savefig('fig.svg', dpi=100) However, when I inspect fig.svg or open it for editing in Inkscape (I am able to ungroup the filled contour into vector shapes) it is clear that rasterization has not worked! That's fine for such a simple plot, but if my plot has a higher number of contour levels (below) the vector image will need many many curves and the filesize would be much bigger. plt.close() plt.figure() plt.contourf(xi, yi, zi, 100, rasterized=True) plt.savefig('fig.svg', dpi=100) Can someone please suggest a solution and explain why this rasterized=True flag has not done what I require?
I just found this is a duplicate of this question. Using rasterized=True as argument to contour or contourf should show a UserWarning: The following kwargs were not used by contour: 'rasterized' In order to rasterize a contour plot, you need to rasterize its individual parts, i.e. cs = plt.contour(...) for c in cs.collections: c.set_rasterized(True) The example from the question would hence look like import numpy as np import matplotlib.pylab as plt x = np.linspace(0, 2*np.pi, 100) y = np.linspace(0, 2*np.pi, 100) xi, yi = np.meshgrid(x, y) zi = np.cos(xi)**2 + np.sin(yi)**2 plt.figure() cs = plt.contourf(xi, yi, zi) for c in cs.collections: c.set_rasterized(True) plt.savefig('fig.svg', dpi=100)
How to change the axis dimension from pixel to length in matplotlib? is there any code in general?
Since the complete simulation is to big to post it right here only the code to plot the spectrum is given (I think this is enough) d = i.sum(axis=2) pylab.figure(figsize=(15,15)) pylab = imshow(d) plt.axis('tight') pylab.show() This spectrum is given in pixel. But I would like to have this in the units of length. I will hope you may give me some advices.
Do you mean that you want axis ticks to show your custom dimensions instead of the number of pixels in d? If yes, use the extent keyword of imshow: import numpy import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt d = numpy.random.normal(size=(20, 40)) fig = plt.figure() s = fig.add_subplot(1, 1, 1) s.imshow(d, extent=(0, 1, 0, 0.5), interpolation='none') fig.tight_layout() fig.savefig('tt.png')
I'm guess a bit at what your problem is, so let's start by stating my interpretation/ You have some 2D data d that you plot using imshow and the units on the x and y axes are in the number of pixels. For example in the following we see the x axis labelled from 0 -> 10 for the number of data points: import numpy as np import matplotlib.pyplot as plt # Generate a fake d x = np.linspace(-1, 1, 10) y = np.linspace(-1, 1, 10) X, Y = np.meshgrid(x, y) d = np.sin(X**2 + Y**2) plt.imshow(d) If this correctly describes your issue, then the solution is to avoid using imshow, which is designed to plot images. Firstly this will help as imshow attemps to interpolate to give a smoother image (which may hide features in the spectrum) and second because it is an image, there is no meaningful x and y data so it doesn't plot it. The best alternative would be to use plt.pcolormesh which generate a psuedocolor plot of a 2D array and takes as arguments X and Y, which are both 2D arrays of points to which the values of d correspond. For example: # Generate a fake d x = np.linspace(-1, 1, 10) y = np.linspace(-1, 1, 10) X, Y = np.meshgrid(x, y) d = np.sin(X**2 + Y**2) plt.pcolormesh(X, Y, d) Now the x and y values correspond to the values of X and Y.