How to plot x versus y lines using matplotlib? - python

How to plot a x versus y line? By x versus y, I mean how to plot x vs y line if the x and y axes have already fixed, as if the axes are reversed for this line.
Update:
Some one asked me why not just reverse the arguments and axes labels. Here is my reason: this x vs y line is only a part of a 2D plot (the main plot) and the main axes are for the 2D plot. What's more, there are also y vs x lines in the same 2D plot. I do this because I want to show certain line clearly.
Update:
Here is a example what I want:
I want to plot the black line in the figure which I draw manually (actually I want to draw Gaussian curve). It is time vs voltage. I still want to keep the existed blue line and I should not reverse the time/voltage labels.

You can easily plot multiple curves in the same subplot in matplotlib. As an example see this annotated code:
import matplotlib.pyplot as plt
import numpy as np
# Data for plotting
t = np.arange(0.0, 2.0, 0.01)
s = 1 + np.sin(2 * np.pi * t)
# Note that using plt.subplots below is equivalent to using
# fig = plt.figure() and then ax = fig.add_subplot(111)
fig, ax = plt.subplots()
#plot sine wave
ax.plot(t, s, label = "sine wave")
#now create y values for the second plot
y = np.linspace(0, 2, 1000)
#calculate the values for the Gaussian curve
x = 2 * np.exp(-0.5 * np.square(-4 * (y - 1)))
#plot the Gaussian curve
ax.plot(x, y, label = "Gaussian curve")
ax.set(xlabel='time (s)', ylabel='voltage (mV)',
title='About as simple as it gets, folks')
ax.grid()
#show the legend
plt.legend()
plt.show()
Output:

Related

Plotting surface and curve in 3D and a curve in xy-plane, all in the same plot

To illustrate an optimization problem, I want all of this in the same 3D plot:
A surface.
A curve in the xy-plane.
A curve/path on the surface which marks out the points on the surface that lies directly above the curve in the xy-plane.
This is my code so far:
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.ticker import LinearLocator
import numpy as np
from mpl_toolkits import mplot3d
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
X = np.linspace(-5,5,100)
Y = X
X, Y = np.meshgrid(X, Y)
Z = 50 - X**2 - Y**2
#Plotting curve on the surface
ax = plt.axes(projection='3d')
yline = np.linspace(-5,5,100)
xline = -np.sqrt(4/(2+yline**2)) #the x-values of the curve in the xy-plane
zline = 50 - xline**2 - yline**2
ax.plot3D(xline, yline, zline, "black")
surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm)
ax.set_zlim(0, 50)
#Plotting curve in xy-plane
a = 5
g = 1 - 2*X - X*Y**2
plt.contour(X,Y,g, [a], offset=0)
plt.show()
Here is the plot from two different angles:
Some problems:
First of all, it seems like the axes have been numbered twice. Is that because I make a meshgrid, and later on use ax.plot3D? That I use two different ways of plotting something, and as a consequence make the 3D space twice?
The path on the surface appears weakly. Is there a way to make the path more visible?
From the picture in bird perspective, we see that the path does not lie directly above the curve in the xy-plane. What would be easier, was if Python had a built-in function who could project the curve in the xy-plane directly onto the surface. Am I missing something here? Does anyone know of such a function?
These questions might be dummy questions, but answers and tips are highly appreciated!
The code creates two axes objects (both assigned to the ax variable) in the same figure. This is not needed and results in double ticks marks.
To make the path on the surface more visible, plot it with a higher zorder.
The curve on the surface does not overlap with the curve on the xy plane because these are different curves. To plot the projection of the surface curve on the xy plane, set all z-coordinates of the curve to 0.
Below is the code with these changes.
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.ticker import LinearLocator
import numpy as np
from mpl_toolkits import mplot3d
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
X = np.linspace(-5, 5, 100)
Y = X
X, Y = np.meshgrid(X, Y)
Z = 50 - X**2 - Y**2
yline = np.linspace(-5, 5, 100)
xline = -np.sqrt(4 / (2 + yline**2))
zline = 50 - xline**2 - yline**2
ax.plot3D(xline, yline, zline, "b", zorder=10)
surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm, alpha=0.7)
ax.set_zlim(0, 50)
#Plotting curve in xy-plane
ax.plot3D(xline, yline, 0, "k")
plt.show()

I am having issues Increasing the space between my x axis labels and also increasing its size

I have successfully plotted my line graph as a newbie,but struggling to increase the space between my x axis labels and also the size because they are overlapping.
plt.figure(figsize=(10,8))
x = state_query_df['location_id']
y1 = state_query_df['Population']
y2 = state_query_df['professionals']
plt.plot(x, y1, label="Population", linewidth = 3)
plt.plot(x, y2, label="Professionals",linewidth = 3)
plt.tick_params(axis='x', which='major', labelsize=10)
plt.xlabel("location_id")
plt.ylabel("Population")
plt.show()
To Change Figure Size and xticks:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.1)
y = np.sin(x)
plt.figure(figsize=(20,8)) ## figure size change from 10x8 to 20x8
plt.plot(x, y)
plt.xticks(np.arange(0, 10, step=2.5)) ## xticks change
plt.show()
You can manage to do this with the command xticks
Check out this post:
Problems with matplotlib.pyplot.xticks()
Update:
This probably happens because you assign on x-axis the values of the first curve and the values of the second curve, as well. Try either removing the values of the one of the two x-axis OR assign your own with command xticks.

How to plot a contour plot if the difference between Zmax and Zmin is of the order of 10^(-5)?

I want to produce a ramachandran plot which would look like the following
basically it is a superposition of two plots: contour and scatter. I have the data file for plotting the contour and scatter plot. The data for contour plot is present as three different columns denoting x, y and z values. the value of x and y varies from -180 to 180. Whereas the value z varies from 0 to 1 and the difference between z values can be as low as 10^(-5). In my code I tried to plot the contour using tricontourf where the difference each entry of the level is 0.01. Whenever I tried to make gap between those levels to 0.00001, the code just doesn't get over. That's why I am unable to generate a graph that I want.
The code that I wrote is the following:
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.tri as tri
import matplotlib.cm as cm
x=[]
y=[]
z=[]
x1=[]
y1=[]
lst = []
plt.style.use('seaborn-whitegrid')
for line in open('rama_data.txt', 'r'):
values = [float(s) for s in line.split()]
x.append(values[0])
y.append(values[1])
z.append(values[2])
f=open('all_str_C-S-S-C_Acceptor.txt',"r")
lines=f.readlines()
for m in lines:
x1.append(m.split(' ')[8])
y1.append(m.split(' ')[9])
f.close()
norm = cm.colors.Normalize(vmax=max(z), vmin=min(z))
cmap = cm.OrRd
fig2, ax2 = plt.subplots()
#ax2.set_aspect('equal')
levels = np.arange(0, 1,0.01)
tcf = ax2.tricontourf(x, y, z, levels, cmap=cm.get_cmap(cmap, len(levels)-1),norm=norm)
ax2.set_xticks(np.arange(-180,181,45))
ax2.set_yticks(np.arange(-180,181,45))
ax2.set_xlabel('$\Phi$ Dihedral angle($\circ$)', fontsize=12, fontweight='bold')
ax2.set_ylabel('$\Psi\'$ Dihedral angle($\circ$)', fontsize=12, fontweight='bold')
#cbar=fig2.colorbar(tcf)
#cbar.ax.set_ylabel('Relative Electronic energy(kJ/mol)', fontsize=12, fontweight='bold')
ax2.autoscale(False) # To avoid that the scatter changes limits
ax2.scatter(x1,y1,s=0.15,c='black',zorder=1)
fig2.savefig("Ramachandran plot",dpi=300)
plt.show()
My code generates an image which looks this this:
What modifications should I do do produce the desirable plot?
I have attached the rama_data.txt file. Anyone can download and try it once.
The main problem seems to be that for 100 levels (as in levels = np.arange(0, 1,0.01)) the colors get very smoothed out. Just reducing the number of levels gets a plot much closer to the example plot.
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.tri as tri
xyz = np.loadtxt('rama.txt')
x = xyz[:, 0]
y = xyz[:, 1]
z = xyz[:, 2]
fig2, (ax1, ax2) = plt.subplots(ncols=2)
cmap = 'OrRd'
tcf = ax2.tricontourf(x, y, z, levels=5, cmap=cmap) # norm=norm)
filter = (z > 0.2) & (np.random.randint(0, 10, z.size) == 0)
ax2.scatter(x[filter], y[filter], marker='.', s=1, color='black')
ax1.scatter(x, y, c=z, cmap=cmap)
ax1.set_xticks(np.arange(-180, 181, 45))
ax1.set_yticks(np.arange(-180, 181, 45))
ax2.set_xticks(np.arange(-180, 181, 45))
ax2.set_yticks(np.arange(-180, 181, 45))
plt.show()
The plot shows a regular scatter plot of the given data at the left, and the contourf plot at the right.

Plot 2D image in 3D axes

Using matplotlib is it possible to take a 2D image of something and place it in a 3D figure? I'd like to take a 2D image and place it at z position of 0. I want to then move the other pixels in the image along the z-axis separately based on a calculation I am making.
Look for example: https://matplotlib.org/gallery/mplot3d/2dcollections3d.html
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.gca(projection='3d')
# Plot a sin curve using the x and y axes.
x = np.linspace(0, 1, 100)
y = np.sin(x * 2 * np.pi) / 2 + 0.5
ax.plot(x, y, zs=0, zdir='z', label='curve in (x,y)')
# Plot scatterplot data (20 2D points per colour) on the x and z axes.
colors = ('r', 'g', 'b', 'k')
# Fixing random state for reproducibility
np.random.seed(19680801)
x = np.random.sample(20 * len(colors))
y = np.random.sample(20 * len(colors))
c_list = []
for c in colors:
c_list.extend([c] * 20)
# By using zdir='y', the y value of these points is fixed to the zs value 0
# and the (x,y) points are plotted on the x and z axes.
ax.scatter(x, y, zs=0, zdir='y', c=c_list, label='points in (x,z)')
# Make legend, set axes limits and labels
ax.legend()
ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
ax.set_zlim(0, 1)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
# Customize the view angle so it's easier to see that the scatter points lie
# on the plane y=0
ax.view_init(elev=20., azim=-35)
plt.show()
If your image is a coloured image you must first ensure that it is an indexed image. This means that you can only have 2d matrix (and not 3 matricies for the RGB components). Command rgb2ind can help.
Then you can directly show you image in a 3D way. Use the mesh or surf command.
You can also adjust perspective with angle and azimuth.

Two y axes for a single plot

I'm trying to create a plot with two Y axes (left and right) for the same data, that is, one is a scaled version of the other. I would like also to preserve the tick positions and grid positions, so the grid will match the ticks at both sides.
I'm trying to do this by plotting twice the same data, one as-is and the other scaled, but they are not coincident.
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(17, 27, 0.1)
y1 = 0.05 * x + 100
fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
ax1.plot(x, y1, 'g-')
ax2.plot(x, y1/max(y1), 'g-')
ax1.set_xlabel('X data')
ax1.set_ylabel('Y data', color='g')
ax2.set_ylabel('Y data normalized', color='b')
plt.grid()
plt.show()
Any help will be appreciated.
Not sure if you can achieve this without getting ugly-looking numbers on your normalized axis. But if that doesn't bother you, try adding this to your code:
ax2.set_ylim([ax1.get_ylim()[0]/max(y1),ax1.get_ylim()[1]/max(y1)])
ax2.set_yticks(ax1.get_yticks()/max(y1))
Probably not the most elegant solution, but it scales your axis limits and tick positions similarly to what you do with the data itself so the grid matches both axes.

Categories