How to plot two plots with strings as x axis values - python

I want to plot two figures in one image using matplotlib. Data which I want to plot is:
x1 = ['sale','pseudo','test_mode']
y1 = [2374064, 515, 13]
x2 = ['ready','void']
y2 = [2373078, 1514]
I want to plot the bar plot for both the figure in one image. I used the code given below:
f, (ax1, ax2) = plt.subplots(1, 2, sharey=True)
ax1.plot(x1, y1)
ax1.set_title('Two plots')
ax2.plot(x2, y2)
but its giving error:
ValueError: could not convert string to float: PSEUDO
How I can plot them in one image using matplotlib?

Try this:
x1 = ['sale','pseudo','test_mode']
y1 = [23, 51, 13]
x2 = ['ready','void']
y2 = [78, 1514]
y = y1+y2
x = x1+x2
pos = np.arange(len(y))
plt.bar(pos,y)
ticks = plt.xticks(pos, x)
Separate figures in one image:
x1 = ['sale','pseudo','test_mode']
y1 = [23, 51, 13]
x2 = ['ready','void']
y2 = [78, 1514]
fig, (ax1, ax2) = plt.subplots(1, 2, sharey=True)
pos1 = np.arange(len(y1))
ax1.bar(pos1,y1)
plt.sca(ax1)
plt.xticks(pos1,x1)
pos2 = np.arange(len(y2))
ax2.bar(pos,y2)
plt.sca(ax2)
plt.xticks(pos2,x2)

The problem is that your x values are not numbers, but text. Instead, plot the y values and then change the name of the xticks (see this answer):
import matplotlib.pyplot as plt
x1 = ['sale','pseudo','test_mode']
y1 = [23, 51, 13]
x2 = ['ready','void']
y2 = [78, 1514]
f, axes = plt.subplots(1, 2, sharey=True)
for (x, y, ax) in zip((x1, x2), (y1, y2), axes):
ax.plot(y)
ax.set_xticks(range(len(x))) # make sure there is only 1 tick per value
ax.set_xticklabels(x)
plt.show()
This produces:
For a bar graph, switch out ax.plot(y) with ax.bar(range(len(x)), y). This will produce the following:

Related

The Matplotlib Result is Different From WolfarmAlpha

I want to plot some equation in Matplotlib. But it has different result from Wolframalpha.
This is the equation:
y = 10yt + y^2t + 20
The plot result in wolframalpha is:
But when I want to plot it in the matplotlib with these code
# Creating vectors X and Y
x = np.linspace(-2, 2, 100)
# Assuming α is 10
y = ((10*y*x)+((y**2)*x)+20)
# Create the plot
fig = plt.figure(figsize = (10, 5))
plt.plot(x, y)
The result is:
Any suggestion to modify to code so it has similar plot result as wolframalpha? Thank you
As #Him has suggested in the comments, y = ((10*y*x)+((y**2)*x)+20) won't describe a relationship, so much as make an assignment, so the fact that y appears on both sides of the equation makes this difficult.
It's not trivial to express y cleanly in terms of x, but it's relatively easy to express x in terms of y, and then graph that relationship, like so:
import numpy as np
import matplotlib.pyplot as plt
y = np.linspace(-40, 40, 2000)
x = (y-20)*(((10*y)+(y**2))**-1)
fig, ax = plt.subplots()
ax.plot(x, y, linestyle = 'None', marker = '.')
ax.set_xlim(left = -4, right = 4)
ax.grid()
ax.set_xlabel('x')
ax.set_ylabel('y')
Which produces the following result:
If you tried to plot this with a line instead of points, you'll get a big discontinuity as the asymptotic limbs try to join up
So you'd have to define the same function and evaluate it in three different ranges and plot them all so you don't get any crossovers.
import numpy as np
import matplotlib.pyplot as plt
y1 = np.linspace(-40, -10, 2000)
y2 = np.linspace(-10, 0, 2000)
y3 = np.linspace(0, 40, 2000)
x = lambda y: (y-20)*(((10*y)+(y**2))**-1)
y = np.hstack([y1, y2, y3])
fig, ax = plt.subplots()
ax.plot(x(y), y, linestyle = '-', color = 'b')
ax.set_xlim(left = -4, right = 4)
ax.grid()
ax.set_xlabel('x')
ax.set_ylabel('y')
Which produces this result, that you were after:

Finding intersection of two graphs with different numpy sizes

I would like to find the intersection of two graphs. It took me 674 points to plot the first graph and only 14 points to plot the second graph.
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
df = pd.read_csv("test1.csv",,skiprows=range(9),names=['A', 'B', 'C','D'])
df2 = pd.read_csv("test2.csv",skiprows=range(1),names=['X','Y'])
x1 = df['A'].tolist()
x1 = np.array(x1)
y1 = df['D'].tolist()
y1 = np.array(y1)
x2 = df2['X'].tolist()
x2 = np.array(x2)
y2 = df2['Y'].tolist()
y2 = np.array(y2)
idx = np.argwhere(np.diff(np.sign(y1 - y2))).flatten()
fig, ax = plt.subplots()
ax.plot(x1, y1, 'blue')
ax.plot(x2, y2, 'red')
plt.show()
However, I am getting this error from the code above due to the different sizes of numpy. Any ways I can solve this?
operands could not be broadcast together with shapes (674,) (14,)
You should compute interpolations of both curves with scipy.interpolate.interp1d, then you can calculate indeces of intersection points with the method you used.
I assume you have two curves with x1, x2, y1 and y2 coordinates, with different lengths and x axis limits:
x1 = np.linspace(-2, 12, 674)
x2 = np.linspace(0, 8, 14)
y1 = np.sin(x1)
y2 = np.cos(x2) + 1
So, you have to compute interpolation functions:
f1 = interp1d(x1, y1, kind = 'linear')
f2 = interp1d(x2, y2, kind = 'linear')
Then, you need to evaluate new curves on a common x axis, so new curves will have the same length:
xx = np.linspace(max(x1[0], x2[0]), min(x1[-1], x2[-1]), 1000)
y1_interp = f1(xx)
y2_interp = f2(xx)
Finally, you can compute indices of interpolation points as you already did:
idx = np.argwhere(np.diff(np.sign(y1_interp - y2_interp))).flatten()
Complete Code
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import interp1d
x1 = np.linspace(-2, 12, 674)
x2 = np.linspace(0, 8, 14)
y1 = np.sin(x1)
y2 = np.cos(x2) + 1
f1 = interp1d(x1, y1, kind = 'linear')
f2 = interp1d(x2, y2, kind = 'linear')
xx = np.linspace(max(x1[0], x2[0]), min(x1[-1], x2[-1]), 1000)
y1_interp = f1(xx)
y2_interp = f2(xx)
idx = np.argwhere(np.diff(np.sign(y1_interp - y2_interp))).flatten()
fig, ax = plt.subplots()
ax.plot(x1, y1, 'blue', label = 'y1')
ax.plot(x2, y2, 'red', label = 'y2')
for index in idx:
ax.plot(xx[index], y1_interp[index], marker = 'o', markerfacecolor = 'black', markeredgecolor = 'black')
plt.show()
Plot

Change the size of subplot so histogram and heatmap x-axes lineup [duplicate]

For a correlation plot I would like to have a plot that is optically square (same length of x and y in pixels) but also has a certain axis limit on x and y. I can get each of the 2 separately but not at the same time:
import matplotlib.pyplot as plt
f, (ax1, ax2) = plt.subplots(1, 2)
x = [1 , 4 , 6]
y1 = [4, 7, 9]
y2 = [20, 89, 99]
ax1.plot(x, y1, 'o')
ax2.plot(x, y2, 'o')
myXlim = [0, 8]
ax1.set_xlim(myXlim)
ax2.set_xlim(myXlim)
ax1.axis('square')
ax2.axis('square')
# limit is gone here
ax1.set_xlim(myXlim)
ax2.set_xlim(myXlim)
# square is gone here
plt.show()
If I just use the ax1.set_xlim(myXlim) (and not square) then I can manually adjust the window size to get what I want but how can I do this automatically?
An option to get square subplots is to set the subplot parameters such that the resulting subplots automatically adjust to be square. This is a little involved, because all the margins and spacings need to be taken into account.
import matplotlib.pyplot as plt
f, (ax1, ax2) = plt.subplots(1, 2)
x = [1 , 4 , 6]
y1 = [4, 7, 9]
y2 = [20, 89, 99]
def square_subplots(fig):
rows, cols = ax1.get_subplotspec().get_gridspec().get_geometry()
l = fig.subplotpars.left
r = fig.subplotpars.right
t = fig.subplotpars.top
b = fig.subplotpars.bottom
wspace = fig.subplotpars.wspace
hspace = fig.subplotpars.hspace
figw,figh = fig.get_size_inches()
axw = figw*(r-l)/(cols+(cols-1)*wspace)
axh = figh*(t-b)/(rows+(rows-1)*hspace)
axs = min(axw,axh)
w = (1-axs/figw*(cols+(cols-1)*wspace))/2.
h = (1-axs/figh*(rows+(rows-1)*hspace))/2.
fig.subplots_adjust(bottom=h, top=1-h, left=w, right=1-w)
ax1.plot(x, y1, 'o')
ax2.plot(x, y2, 'o')
#f.tight_layout() # optionally call tight_layout first
square_subplots(f)
plt.show()
The benefit here is to be able to freely zoom and autoscale. The drawback is that once the figure size changes, the subplot sizes are not square any more. To overcome this drawback, one may in addition register a callback on size changes of the figure.
import matplotlib.pyplot as plt
f, (ax1, ax2) = plt.subplots(1, 2)
x = [1 , 4 , 6]
y1 = [4, 7, 9]
y2 = [20, 89, 99]
class SquareSubplots():
def __init__(self, fig):
self.fig = fig
self.ax = self.fig.axes[0]
self.figw,self.figh = 0,0
self.params = [self.fig.subplotpars.left,
self.fig.subplotpars.right,
self.fig.subplotpars.top,
self.fig.subplotpars.bottom,
self.fig.subplotpars.wspace,
self.fig.subplotpars.hspace]
self.rows, self.cols = self.ax.get_subplotspec().get_gridspec().get_geometry()
self.update(None)
self.cid = self.fig.canvas.mpl_connect('resize_event', self.update)
def update(self, evt):
figw,figh = self.fig.get_size_inches()
if self.figw != figw or self.figh != figh:
self.figw = figw; self.figh = figh
l,r,t,b,wspace,hspace = self.params
axw = figw*(r-l)/(self.cols+(self.cols-1)*wspace)
axh = figh*(t-b)/(self.rows+(self.rows-1)*hspace)
axs = min(axw,axh)
w = (1-axs/figw*(self.cols+(self.cols-1)*wspace))/2.
h = (1-axs/figh*(self.rows+(self.rows-1)*hspace))/2.
self.fig.subplots_adjust(bottom=h, top=1-h, left=w, right=1-w)
self.fig.canvas.draw_idle()
s = SquareSubplots(f)
ax1.plot(x, y1, 'o')
ax2.plot(x, y2, 'o')
plt.show()
The above solution works by restricting the space the subplot has inside of its grid. An opposite approach, where the size of the subplot is somehow fixed, would be shown in the answer to Create equal aspect (square) plot with multiple axes when data limits are different?.

ticker.FixedFormatter strategy to show the tics of the ax2 axis

Given 3 arrays:
X1 = 10.00, 30.10, 50.20, 70.30 ...
X2 = 1.9976433815311, 2.0109630315475, 2.0372702369401, 2.0665284897891 ...
Y = -0.0000008764356, -0.0000149459573, -0.0000326996870, -0.0000513717121 ...
There is a one-to-one correspondence between X1, X2 and Y, i.e.
the i-th element of X1 has an i-th associated value of X2 and a i-th value of Y.
The following is the plot of Y as a function of X1 (blue dots).
I would need the X2 axis to show all the corresponding X2 values for each X1 value.
Following the second answer on this post,
I have partially accomplished this thorugh the ticker.FixedFormatter strategy,
by which: the X2 array needs to be transformed to a tuple, and each element of this tuple needs to be a string.
As can be seen, not all red values of X2 are displayed for each value of X1, e.g. for X1 = 10.0 the corresponding X2 = 2.00 appears to be displaced.
I do not understand very well why this is occurring. I would appreciate if you could help me.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import sys
X1 = np.array([10.0000000000000, 30.1000000000000, 50.2000000000000, 70.3000000000000, 90.4000000000000, 110.5100000000000, 130.6100000000000, 150.7100000000000, 170.8100000000000, 190.9100000000000, 211.0100000000000, 231.1100000000000, 251.2100000000000, 271.3100000000000, 291.4100000000000, 311.5200000000000, 331.6200000000000 ])
Y = np.array([-0.0000008764356, -0.0000149459573, -0.0000326996870, -0.0000513717121, -0.0000652350399, -0.0000842214902, -0.0001003825474, -0.0001214363281, -0.0001376971422, -0.0001572720132, -0.0001971891337, -0.0002203926200, -0.0002747064193, -0.0003217228112, -0.0003764577474, -0.0004657478828, -0.0006232016207])
X2 = np.array([1.9976433815311, 2.0109630315475, 2.0372702369401, 2.0665284897891, 2.0995743328944, 2.1392386324550, 2.1789200955649, 2.2290243968267, 2.2872281293691, 2.3180577547912, 2.4100643103912, 2.4826981368480, 2.5794602952095, 2.6764219232389, 2.7963983991814, 2.9740753305878, 3.3107035136072])
##### Plotting:
fig, ax1 = plt.subplots()
ax1.plot(X1, Y, linestyle='--', marker="o", markersize=6, color='blue')
ax1.set_ylabel('Y', fontsize=20)
# Make the ax1-ticks and ax1-tick-labels match the line color (blue):
ax1.set_xlabel('X1', fontsize=20, color='blue')
plt.setp(ax1.get_xticklabels(), rotation='45') # rotate them
# Create a new axis:
ax2 = ax1.twiny()
# Make the ax2-ticks and ax2-tick-labels match the red color:
ax2.set_xlabel('X2', fontsize=20, color='red')
ax2.tick_params('x', colors='red')
fig.tight_layout()
ax2.set_xlim(1.9, 3.4)
ax1.set_ylim(-0.0007, 1.1e-5)
ax2.set_ylim(-0.0007, 1.1e-5)
ax1.grid()
# Convert all X2 elements to a list of strings:
X2_string_all = []
for i in X2:
aux = "%.2f" % i
X2_string = str(aux)
X2_string_all.append(X2_string)
# Convert that list into a tuple:
X2_string_all_tuple = tuple(X2_string_all)
ax1.xaxis.set_major_locator(ticker.FixedLocator((X1)))
ax2.xaxis.set_major_formatter(ticker.FixedFormatter((X2_string_all_tuple)))
plt.show()
Something like this would be the desired plot (the red lines that come across the plot are not necessary):
In your code ax2 does not know that it should behave exactly as ax1, just with different labels. So you need to tell it,
ax2.set_xlim(ax1.get_xlim())
Then just use the same tick locations for both axes,
ax1.set_xticks(X1)
ax2.set_xticks(X1)
and label the ticks of ax2 with values from X2
ax2.set_xticklabels(["%.2f" % i for i in X2])
Complete code:
import numpy as np
import matplotlib.pyplot as plt
X1 = np.array([10., 30.1, 50.2, 70.3, 90.4, 110.510, 130.610, 150.710, 170.810,
190.910, 211.010, 231.110, 251.210, 271.310, 291.410, 311.52, 331.62])
Y = np.array([-0.00000087, -0.0000149, -0.0000326, -0.0000513, -0.00006523, -0.0000842,
-0.0001003, -0.0001214, -0.00013769, -0.0001572, -0.0001971, -0.0002203,
-0.00027470, -0.0003217, -0.0003764, -0.0004657, -0.00062320])
X2 = np.array([1.997, 2.0109, 2.0372, 2.0665, 2.099, 2.1392, 2.1789, 2.2290,
2.287, 2.3180, 2.4100, 2.4826, 2.579, 2.6764, 2.7963, 2.9740, 3.310])
##### Plotting:
fig, ax1 = plt.subplots()
ax1.grid()
ax2 = ax1.twiny()
ax1.plot(X1, Y, linestyle='--', marker="o", markersize=6, color='blue')
ax1.set_ylabel('Y', fontsize=20)
ax1.set_xlabel('X1', fontsize=20, color='blue')
plt.setp(ax1.get_xticklabels(), rotation='45') # rotate them
ax2.set_xlabel('X2', fontsize=20, color='red')
plt.setp(ax2.get_xticklabels(), rotation='45', color='red')
# Set xlimits of ax2 the same as ax1
ax2.set_xlim(ax1.get_xlim())
# Set ticks at desired position
ax1.set_xticks(X1)
ax2.set_xticks(X1)
# Label ticks of ax2 with values from X2
ax2.set_xticklabels(["%.2f" % i for i in X2])
fig.tight_layout()
plt.show()

subplots with multiple colorbar

I am trying to plot a figure with 4 subplots and 2 colorbars. Here is my code:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.ticker import MaxNLocator
from matplotlib import rcParams
rcParams["savefig.dpi"] = 100
rcParams["font.size"] = 18
x1 = np.linspace(100, 1000, 10)
y1 = np.linspace(10, 17, 10)
z1 = np.linspace(4, 18, 10)
t1 = np.linspace(-0.3, 0.4, 10)
fig, axes = plt.subplots(2, 2, sharey = True, figsize = (10, 10))
a0 = axes[0][0].scatter(x1, y1, s = 40, c = z1, marker = 'o')
cbar1 = fig.colorbar(a0)
axes[0][0].set_ylabel('y1')
axes[0][0].set_xlabel('x1')
axes[0][0].xaxis.set_major_locator(MaxNLocator(4))
a1 = axes[0][1].scatter(t1, y1, s = 40, c = z1, marker = 'o')
axes[0][1].xaxis.set_major_locator(MaxNLocator(4))
axes[0][1].set_xlabel('t1')
cbar1.ax.set_ylabel('z1', rotation = 270)
x2 = np.linspace(450, 900, 20)
y2 = np.linspace(11, 12.5, 20)
z2 = np.linspace(12, 60, 20)
t2 = np.linspace(-0.3, 0.4, 20)
a0 = axes[1][0].scatter(x2, y2, c = z2, marker = 'o')
cbar2 = fig.colorbar(a0)
axes[1][0].set_ylabel('y2')
axes[1][0].set_xlabel('x2')
axes[1][0].xaxis.set_major_locator(MaxNLocator(4))
a1 = axes[1][1].scatter(t2, y2, c = z2, marker = 'o')
axes[1][0].xaxis.set_major_locator(MaxNLocator(4))
axes[1][1].set_xlabel('t2')
cbar2.ax.set_ylabel('z2', rotation = 270)
plt.show()
Here is the figure:
The thing I want to fix is:
the colorbars are at the far end to the right. I want 1 colorbar to be on the right of the first row and another colorbar to be on the right of the second row (basically, where it simply is).
How can I do this? Thanks!
You can enter another parameter to select on which axes to plot the colorbar.
Here is the change in your code:
cbar1 = fig.colorbar(a0, ax=axes[0][1])
cbar2 = fig.colorbar(a0, ax=axes[1][1])
Which produce this plot:

Categories

Resources