I am currently trying to have two plots in one figure. I am stuck on this for a while now and I don't have any idea why it wouldn't work like I want it to. I have two functions, which return similar axes. The data comes from a csv file, where I get the frequency (y-axis) according to the size of specific objects (x-axis). I expect to have one figure displaying the plots on top of each other. However my plot only contains the legend to axs[1] and the data also only contains axs[1].
My code:
fig, axs = plt.subplots(2)
axs[0].plot(ax=return_some_ax())
axs[1].plot(ax=return_similar_ax())
plt.savefig('plot.png')
I hope that you can help me out :)
Thank you!
This is how you do it in general. You can substitute your functions in place of x and y in here if they return a list of those values:
x_data = list(range(10))
y = [x**2 for x in x_data]
y1 = [x+5 for x in x_data]
fig, [ax1, ax2] = plt.subplots(2)
ax1.plot(x_data, y, label = "quadratic", color = 'red')
ax2.plot(x_data, y1, label = "linear", color = 'blue')
ax1.legend()
ax2.legend()
plt.show()
plt.savefig('plot.png')
Here is the same code using two functions:
def function1(x):
return x**2
def function2(x):
return x+5
x_data = list(range(10))
fig, [ax1, ax2] = plt.subplots(2)
ax1.plot(x_data, [function1(x) for x in x_data], label = "quadratic", color = 'red')
ax2.plot(x_data, [function2(x) for x in x_data], label = "linear", color = 'blue')
ax1.legend()
ax2.legend()
plt.show()
plt.savefig('plot.png')
Related
Picture of Plot
This should really not be this difficult. I am plotting a 3d surface plot from an array. The code looks like this:
z = arr
y = np.arange(len(z))
x = np.arange(len(z[0]))
(x ,y) = np.meshgrid(x,y)
plt.figure(figsize=(100,100))
ax.plot_surface(x,y,z, cmap=cm.coolwarm)
ax.set_xlabel("Bonus to AC")
ax.set_ylabel("Current AC")
ax.set_zlabel("Reduction in Damage")
plt.show()
It does not matter if I set the fig size to 10,10 or 1000,1000, the image still shows up the same size.
What kind of works is adding subplots,
ax = fig.add_subplot(211, projection='3d')
but this splits it up into one okay plot and one empty plot. Not sure how to use the subplots function.
you are referencing ax from a different figure than the one produced by plt.figure
you should instead use ax= fig.add_subplot after you assign fig= plt.figure as follows.
z = np.ones((100,100))
y = np.arange(len(z))
x = np.arange(len(z[0]))
(x ,y) = np.meshgrid(x,y)
fig = plt.figure(figsize=(10,10))
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(x,y,z)
ax.set_xlabel("Bonus to AC")
ax.set_ylabel("Current AC")
ax.set_zlabel("Reduction in Damage")
plt.show()
note i just swapped the z=np.ones((100,100)) in the first line so viewers can get this working.
I want to write the operations and parameters that I usually use in drawing in a function. In the future, just pass x and y to draw according to the default parameters. But now the question I am facing is, how do I determine which picture plt.plot is drawing on? For example, I want to draw two curves on a picture.
def draw(x,y):
... %some operations
plt.plot(x,y) % draw picture operations
... %some operations
draw(x,y),
dray(x2,y2)
How to ensure that these two curves are drawn on a picture. That is, what parameters do I need to pass to make plt.plot focus on the picture I specify.
def plotLine(coordinate,figName='test',xylabel=[],ax=None):
# assert(len(coordinate)<=2)
if (len(coordinate)==2) :
x=coordinate[0]
y=coordinate[1]
assert(len(x)==len(y))
else:
y=coordinate
x =np.linspace(0,len(y)-1,len(y))
minn=min(y)
maxx=max(y)
plt.switch_backend('Agg')
if ax == None:
fig,ax = plt.subplots()
fig = plt.figure(num=None, figsize=(3.5, 1.5), dpi=300, facecolor='w')
plt.subplots_adjust(right = 0.98, top = 0.98, bottom=0.35,left=0.32,wspace=0, hspace=0.2)
ax.set_xlim([0,len(x)])
ax.set_ylim([0,maxx+maxx/3])
plt.xticks(fontsize=5)
plt.yticks(fontsize=5)
bar_width = 0.35
opacity = 0.8
lsmarkersize = 2.5
lslinewidth = 0.6
ax.plot(x,y,'-', linewidth=1, markersize=lsmarkersize, markeredgewidth=0)
plt.savefig(figName+".png",bbox_inches='tight',dpi=500)
# os.system("code "+figName+".png")
if ax!=None:
return ax
else:
return plt.gca()
x=[1,2,3,4,5,6]
y=[1,2,3,4,4,5]
ax = plotLine([x,y])
x=[1,2,3,4,5,6]
y=[12,13,14,15,16,17]
plotLine([x,y],ax=ax)
I tried to pass ax as a parameter. But the picture drawn at the end is blank.
You can use subplots to specify the axes to plot on. For example, create a figure with a single subplot:
fig, ax = plt.subplots()
ax.plot(x, y)
For your function you could do the following
fig, ax = plt.subplots()
def draw(x, y, ax):
ax.plot(x, y)
def dray(x2, y2, ax):
ax.plot(x2, y2)
I am not attempting to modify your code. This is more a general approach answer. Imho, it is better (in terms of keeping track of what's going on) to define the figure and plots outside the function and doing only the actual plotting inside the function.
import numpy as np
from matplotlib import pyplot as plt
np.random.seed(123)
#the plotting function, taking ax and label as optional parameters
def draw_the_line(x, y, current_ax=None, current_label=None):
if not current_ax:
current_ax=plt.gca()
if not current_label:
current_label="missing label"
current_ax.plot(x, y, label=current_label)
plt.sca(current_ax)
fig, (ax1, ax2) = plt.subplots(2, figsize=(6, 8))
#normal plot into panel 1
x1 = np.arange(6)
y1 = np.random.randint(1, 10, len(x1))
draw_the_line(x1, y1, ax1, "data1")
#normal plot into panel 2
x2 = np.arange(5)
y2 = np.random.randint(10, 20, len(x2))
draw_the_line(x2, y2, ax2, "data2")
#plot into panel 1 with missing label
x3 = np.arange(4)
y3 = np.random.randint(20, 30, len(x3))
draw_the_line(x3, y3, ax1)
#plot into the last panel used
x4 = np.arange(3)
y4 = np.random.randint(30, 40, len(x4))
draw_the_line(x4, y4, current_label="data4")
ax1.legend()
ax2.legend()
plt.show()
Sample output:
I am trying to plot three variables, in a graph using primary and secondary axis with one variable on primary axis and two on secondary axis. My code
vav = floor_data[floor_data['vavId'] == i]
vav = vav.reset_index()
x = vav.index
y1 = vav['nvo_temperature_sensor_pps']
y2 = vav['nvo_airflow']
y3 = vav['nvo_air_damper_position']
fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
ax1.plot(x, y1, 'g-')
ax2.plot(x, y2, 'b-')
ax2.plot(x, y3, 'r-')
ax2 = ax1.twinx()
ax1.set_xlabel('VAV '+str(i))
ax1.set_ylabel('temperature ', color='g')
ax2.set_ylabel('air flow, temperature', color='b')
plt.show()
I have added all the three variables but I am facing problem in y-ticks of secondary axis. My plot looks like
Is it possible to have a single y tick values on secondary axis for better readability?
You need to create new twix axis on host and shrink subplot to create space for additional axis on right side. Then move new axis at right position. Some descriptions in code.
import matplotlib.pyplot as plt
import numpy as np
fig, host = plt.subplots()
# shrink subplot
fig.subplots_adjust(right=0.75)
# create new axis on host
par1 = host.twinx()
par2 = host.twinx()
# place second axis at far right position
par2.spines["right"].set_position(("axes", 1.2))
# define plot functions
def function_sin(x):
return np.sin(x)
def function_parabola(x):
return x**2
def function_line(x):
return x+1
# plot data
x = np.linspace(0, 10, 100)
y_sin = function_sin(x)
y_parabola = function_parabola(x)
y_line = function_line(x)
host.plot(x, y_sin, "b-")
par1.plot(x, y_parabola, "r-")
par2.plot(x, y_line, "g-")
# set labels for each axis
host.set_xlabel("VAV 16")
host.set_ylabel("Temperature")
par1.set_ylabel("Temperature")
par2.set_ylabel("Air Flow")
plt.show()
Output:
I'm trying to make a bar plot with a color bar, each bar's hight is one variable (y) and each bar should have a color depending on another variable (c).
What I've got to is this (simple example):
data_x = [0,1,2,3]
data_hight = [60,60,80,100]
data_color = [1000,500,1000,900]
data_color = [x / max(data_color) for x in data_color]
fig, ax = plt.subplots(figsize=(15, 4))
my_cmap = plt.cm.get_cmap('GnBu')
colors = my_cmap(data_color)
rects = ax.bar(data_x, data_hight, color=colors)
CS = plt.contourf([data_x, data_color],cmap=my_cmap)
cbar = plt.colorbar(CS, cmap=my_cmap)
cbar.set_label('Color', rotation=270,labelpad=25)
plt.xticks(data_x)
plt.ylabel("Y")
plt.show()
The main problem is that the histogram colors are fine but the color bar is in a diferent scale. besides that I can see a blue line at y=0, it shouldn't be there.
Any help will be a preciated.
Thanks!
You are creating a contourf plot inside your bar plot. That makes no sense.
Instead you would need to create a mappable without any visual representation to supply to the colorbar. This would be a ScalarMappable.
import matplotlib.pyplot as plt
from matplotlib.cm import ScalarMappable
data_x = [0,1,2,3]
data_hight = [60,60,80,100]
data_color = [1000.,500.,1000.,900.]
data_color = [x / max(data_color) for x in data_color]
fig, ax = plt.subplots(figsize=(15, 4))
my_cmap = plt.cm.get_cmap('GnBu')
colors = my_cmap(data_color)
rects = ax.bar(data_x, data_hight, color=colors)
sm = ScalarMappable(cmap=my_cmap, norm=plt.Normalize(0,max(data_color)))
sm.set_array([])
cbar = plt.colorbar(sm)
cbar.set_label('Color', rotation=270,labelpad=25)
plt.xticks(data_x)
plt.ylabel("Y")
plt.show()
I am using bar-charts for my Exploratory data analysis.I have generated around 18 bar-charts in the entire analysis with similar peace of code.So i don't want to write the same code all the time for every bar-chart. the code i have used for the bar-chart is
y = textranges_freq['smstext']
xlabels = textranges_freq['buckets']
bar_width = 0.50
x = np.arange(len(y))
fig, ax = plt.subplots()
ax.bar(x, y, width=bar_width)
ax.set_xticks(x+(bar_width/2.0))
ax.set_xticklabels(xlabels)
ax.set_title('Avg text Frequency by range')
ax.set_xlabel('buckets')
ax.set_ylabel('Avg text messages')
plt.show()
I have used the same code around 18 times in my analysis because i need to
change y,xlabels,title,ax.set_title,ax.set_xlabel,ax.set_ylabel.
so how can i write the function for this to use further.
In the above code textranges_freq is my dataframe and smstext,buckets are my variables.
please help me on this. I am new to python.
Just wrap the whole thing in a function:
y = textranges_freq['smstext']
xlabels = textranges_freq['buckets']
def makebar(y, xlabels, xlabel, ylabel, title):
bar_width = 0.50
x = np.arange(len(y))
fig, ax = plt.subplots()
ax.bar(x, y, width=bar_width)
ax.set_xticks(x+(bar_width/2.0))
ax.set_xticklabels(xlabels)
ax.set_title(title)
ax.set_xlabel(xlabel)
ax.set_ylabel(ylabel)
plt.show()
However, an even easier approach would be to plot from the DataFrame directly:
ax = textranges_freq.plot(x='buckets',y='smstext',kind='bar',title='Avg text Frequency by range', width=0.5, legend=False)
ax.set_xlabel('buckets')
ax.set_ylabel('Avg text messages')
plt.show()
This isn't much more work than just calling the function directly, but if you really wanted you could wrap it in a function, too:
def df_bar(df, xcol, ycol, xlabel=None, ylabel=None, title=None):
if xlabel is None:
xlabel = xcol
if ylabel is None:
ylabel = xcol
ax = textranges_freq.plot(x=xcol,y=ycol,kind='bar',title=title, width=0.5, legend=False)
ax.set_xlabel(xlabel)
ax.set_ylabel(ylabel)
plt.show()
This also has the advantage that if the x or y label is the same as the column name (as is the case for the xlabel in the example), you can just skip the corresponding label and it will use the column name instead. You also can leave the title blank.
I would structure your data into lists.
for example:
yn = [[1,2,3],[2,3,4], [3,4,5],[4,5,6], ...]
x = [[1,2,3],[2,3,4], [3,4,5],[4,5,6], ...]
labels = ['label1', 'label2', 'label3', ...]
and then:
fig = plot.figure(figsize=(11.69, 8.27), dpi=100)
for i,y in enumerate(yn):
#new subplot
ax=fig.add_subplot(18,1,i+1)
#plot
ax.plot(x[i], y, 'bo-')
#y labels
ax.set_ylabel(labels[i])
# grid
ax.grid(True)
plot.show()