Graph bars stacked and I need them separated into individual bars - python

I have the following code, which almost does what I need it to do. I am graphing the importance of each feature for two different models on the same graph for comparison. I can't seem to get them to show side by side as two separate bars. I am fairly new to python and brand new to this forum. here is the code:
def plot_importances1(model1, feature_names1, label1, model2=None,feature_names2=None, label2=None):
if model2 is None:
importances1 = model1.feature_importances_
indices1 = np.argsort(importances1)
plt.figure(figsize=(8, 8)) # Set figure size
# plot the first list of feature importances as a horizontal bar chart
plt.barh(range(len(indices1)), importances1[indices1], color="violet", align="center", label=label1)
# set the y-axis tick labels to be the feature names
plt.yticks(range(len(indices1)), [feature_names1[i] for i in indices1])
else:
importances1 = model1.feature_importances_
indices1 = np.argsort(importances1)
importances2 = model2.feature_importances_
indices2 = np.argsort(importances2)
plt.figure(figsize=(8, 8)) # Set figure size
# plot the first list of feature importances as a horizontal bar chart
plt.barh(range(len(indices1)), importances1[indices1], color="violet", align="center", label=label1)
# plot the second list of feature importances as a horizontal bar chart
plt.barh(range(len(indices2)), importances2[indices2], color="orange", align="center", label=label2)
# set the y-axis tick labels to be the feature names
plt.yticks(range(len(indices1)), [feature_names1[i] for i in indices1])
# add a title and x- and y-axis labels
plt.title("Feature Importances")
plt.xlabel("Relative Importance")
plt.ylabel("Feature")
# add a legend to the plot
plt.legend()
# set the tick locations and labels for the first bar graph
plt.gca().tick_params(axis='x', which='both', length=0)
plt.gca().xaxis.set_ticks_position('top')
plt.gca().xaxis.set_label_position('top')
# set the tick locations and labels for the second bar graph
plt.twinx()
plt.gca().tick_params(axis='x', which='both', length=0)
plt.gca().xaxis.set_ticks_position('bottom')
plt.gca().xaxis.set_label_position('bottom')
plt.show()
Then I call the function:
plot_importances1(
dTree_treat_out,
list(X1_train),
"Outliers present",
dTree,
list(X_train),
"No outliers",
)
The two bars are both showing, but I can't get them to separate completely and I am getting this error:
Output for the code
I have ran several version of this, including one that does not return the matplotlib error. The problem with the other function definitions that I have is that the bars are stacked and I can't see both of them. If I knew how to make one less opaque? I am super stuck. I so not want them stacked, I need the first one to be its own graph with the second one NEXT to it, not overlaying or stacked on top, similar to the image I uploaded, but the bars need to be completely separated.
Any input to fix this issue will be greatly appreciated.

Related

Matplotlib align x-axes on subplots

I am trying to put together a plot that incorporates multiple different data frames that share a common index. Despite setting all the X-axes to the same labels and ticks they still don't lineup within the as be seen with the top x-axis. Causing whitespace on the right y-axis.
Output Graph Here
fig,axe=plt.subplots()
axe.set_xlabel('Total Collectors in Array')
axe.set_ylabel('Energy Generated (MJ)')
plt.xticks(ticks=df.index.values,labels=df.index.values)
axe.plot(df,label= label_list,zorder=0,marker='o')
labelLines(axe.get_lines())
ax3=axe.twiny()
ax2=axe.twinx()
ax3.plot(df3,label=label_list,zorder=1,linewidth=1,linestyle='--')
ax3.axes.xaxis.set_visible(True)
labelLines(ax3.get_lines(),align=False,xvals=[1.5]*10,zorder=2.5)
ax2.set_ylabel('DHW Draw Rate')
ax2.imshow(df2,zorder=2,
cmap='CMRmap',alpha=0.3,origin='lower')
a=ax2.get_xticks().tolist()
label_list1=label_list[:]
ax2.set(xticks=x_lab,xticklabels=x_lab,yticks=y_ticks,yticklabels=label_list1)
fig.tight_layout()
plt.show()

How to create a double axis for one graph

I'm trying to have two y-axes with the same x-axis.
This is what I have tried. But the suicide rates are not showing up on the graph.
I'm new to this, so I was wondering if anyone could spot why its not showing.
The picture is supposed to look like this with suicide rates in red and trust in blue with country as the x-axis
def suicidevstrustcountryplot(dat):
# Does income index change trust for female led countries?
# dat.plot(x ='Country', y='Income', kind = 'line')
# plt.show()
# create figure and axis objects with subplots()
fig,ax = plt.subplots()
# make a plot
ax.plot(dat.Country, dat.Trust, color="red", marker="o")
# set x-axis label
ax.set_xlabel("Country",fontsize=14)
for label in ax.get_xticklabels():
label.set_rotation(90)
label.set_ha('right')
# set y-axis label
ax.set_ylabel("Trust",color="red",fontsize=14)
# twin object for two different y-axis on the sample plot
ax2=ax.twinx()
# make a plot with different y-axis using second axis object
ax2.plot(dat.Country, dat.Trust,color="blue",marker="o")
ax2.set_ylabel("Suicide rate",color="blue",fontsize=14)
plt.show()
# save the plot as a file
fig.savefig('two_different_y_axis_for_single_python_plot_with_twinx.jpg',
format='jpeg',
dpi=100,
bbox_inches='tight')
suicidevstrustcountryplot(Femaletrust)
suicidevstrustcountryplot.suicidevstrustcountryplot.sort_values(ascending=False)[:10].plot(kind='scatter' ,title='Country')

Label Matplotlib subplot y-axes with list of strings

I'm using Matplotlib to create 2 side-by-side horizontal bar charts showing regression coefficient importance across several words. I'd like to label the y-axes with each word in the list.
Every other word is appended to the y-axis when I try this:
# plot word importance bar graphs
fig, axes = plt.subplots(1,2,figsize=(5,10))
plt.subplots_adjust(wspace = 1)
axes[0].set_title('Low revenue')
axes[0].invert_yaxis()
axes[0].barh(np.arange(len(lowrev_topten)), lowrev_topten['Coefficient'])
axes[0].set_yticklabels(list(lowrev_topten['Word']))
axes[0].set_xlabel('Coefficient')
axes[1].set_title('High revenue')
axes[1].invert_yaxis()
axes[1].barh(np.arange(len(highrev_topten)), highrev_topten['Coefficient'])
axes[1].set_yticklabels(list(highrev_topten['Word']))
axes[1].set_xlabel('Coefficient')
However, when I remind it that I'd like to have 10 ticks for 10 words (plt.yticks(np.arange(0,10))), it fixes the second subplot:
# plot word importance bar graphs
fig, axes = plt.subplots(1,2,figsize=(5,10))
plt.subplots_adjust(wspace = 1)
plt.yticks(np.arange(0,10))
axes[0].set_title('Low revenue')
axes[0].invert_yaxis()
axes[0].barh(np.arange(len(lowrev_topten)), lowrev_topten['Coefficient'])
axes[0].set_yticklabels(list(lowrev_topten['Word']))
axes[0].set_xlabel('Coefficient')
axes[1].set_title('High revenue')
axes[1].invert_yaxis()
axes[1].barh(np.arange(len(highrev_topten)), highrev_topten['Coefficient'])
axes[1].set_yticklabels(list(highrev_topten['Word']))
axes[1].set_xlabel('Coefficient')
How do I get both subplots to have the proper y-tick labels?
Seems like you just need to set_yticks for each subplot.
fig, axes = plt.subplots(1,2,figsize=(5,10))
...
axes[0].set_yticks(np.arange(0,10))
axes[1].set_yticks(np.arange(0,10))

Matplotlib center alignment for pie chart labels

I have produced a very simple pie chart in Python using Matplotlib and I am wanting to edit the alignment of my labels. I have used \n within my labels to split the line as the labels are too long for one line. But as you can see from the picture called 'pie chart image', it's a mix of weird alignments at the moment. I would really like to have it center alignment.
For other chart/graph types in Matplotlib there is an argument called align where you can set it to center, however, plt.pie(...) does not seem to have this attribute.
Here is my code:
import matplotlib.pyplot as plt
k = [7,15]
labels = 'Strongly and Mostly \n Agree', 'Strongly/Mostly Disagree \n and In the Middle'
plt.pie(k, labels= labels)
plt.show()
Any ideas?
You can pass a dictionary of text properties to plt.pie via the textprops argument. For example:
plt.pie(k, labels=labels, textprops={'weight': 'bold'})
However, if you try to specify the horizontalalignment property, you'll get an error saying that you provided that parameter twice. Obviously you didn't, but matplotlib passed both it's hard-coded value and your value to some internal function.
But that's probably a good thing. The way I see it, there's not so much a mix of alignments, but a consistent alignment of the text against the pie.
Back to your question
pie returns both the patches and the labels for each wedge. So you can loop through the labels after your initial call to pie to modify their alignment. That looks like this:
k = [7, 15]
labels = 'Strongly and Mostly\nAgree', 'Strongly/Mostly Disagree\nand In the Middle'
fig, ax = plt.subplots()
ax.set_aspect('equal')
wedges, labels = ax.pie(k, labels=labels, textprops={'weight': 'bold'})
for label in labels:
label.set_horizontalalignment('center')
As you can see, the labels now overlap with the wedges, diminishing legibility.
The labels also have a set_position method (i.e., label.set_position((x, y))), but recomputing the positions for N labels in a pie chart sounds like a Bad Time to me.

Matplotlib - axvspan vs subplots

I'm writing a pythonic script for a coastal engineering application which should output, amongst other things, a figure with two subplots.
The problem is that I would like to shade a section of both subplots using plt.axvspan() but for some reason it only shades one of them.
Please find below an excerpt of the section of the code where I set up the plots as well as the figure that it's currently outputting (link after code).
Thanks for your help, and sorry if this is a rookie question (but it just happens that I am indeed a rookie in Python... and programming in general) but I couldn't find an answer for this anywhere else.
Feel free to add any comments to the code.
# PLOTTING
# now we generate a figure with the bathymetry vs required m50 and another figure with bathy vs Hs
#1. Generate plots
fig = plt.figure() # Generate Figure
ax = fig.add_subplot(211) # add the first plot to the figure.
depth = ax.plot(results[:,0],results[:,1]*-1,label="Depth [mDMD]") #plot the first set of data onto the first set of axis.
ax2 = ax.twinx() # generate a secondary vertical axis with the same horizontal axis as the first
m50 = ax2.plot(results[:,0],results[:,6],"r",label="M50 [kg]") # plot the second set of data onto the second vertical axis
ax3 = fig.add_subplot(212) # generate the second subplot
hs = ax3.plot(results[:,0],results[:,2],"g",label="Hs(m)")
#Now we want to find where breaking starts to occur so we shade it on the plot.
xBreakingDistance = results[numpy.argmax(breakingIndex),0]
# and now we plot a box from the origin to the depth of breaking.
plt.axvspan(0,xBreakingDistance,facecolor="b",alpha=0.1) # this box is called a span in matplotlib (also works for axhspan)
# and then we write BREAKING ZONE in the box we just created
yLimits = ax.get_ylim() # first we get the range of y being plotted
yMiddle = (float(yLimits[1])-float(yLimits[0])) / 2 + yLimits[0] # then we calculate the middle value in y (to center the text)
xMiddle = xBreakingDistance / 2 # and then the middle value in x (to center the text)
#now we write BREAKING ZONE in the center of the box.
ax.text(xMiddle,yMiddle,"BREAKING ZONE",fontweight="bold",rotation=90,verticalalignment="center",horizontalalignment="center")
#FIGURE FORMATTING
ax.set_xlabel("Distance [m]") # define x label
ax.set_ylabel("Depth [mDMD]") # define y label on the first vertical axis (ax)
ax2.set_ylabel("M50 [kg]") # define y label on the second vertical axis (ax2)
ax.grid() # show grid
ax3.set_xlabel("Distance[m]") #define x label
ax3.set_ylabel("Hs[m]") # define y label
ax3.grid()
plt.tight_layout() # minimize subplot labels overlapping
# generating a label on a plot with 2 vertical axis is not very intuitive. Normally we would just write ax.label(loc=0)
combined_plots = depth+m50 #first we need to combine the plots in a vector
combined_labels = [i.get_label() for i in combined_plots] # and then we combine the labels
ax.legend(combined_plots,combined_labels,loc=0) # and finally we plot the combined_labels of the combined_plots
plt.savefig("Required M50(kg) along the trench.png",dpi=1000)
plt.close(fig)
Output Figure:
By just calling plt.axvspan, you are telling matplotlib to create the axvspan on the currently active axes (i.e. in this case, the last one you created, ax3)
You need to plot the axvspan on both of the axes you would like for it to appear on. In this case, ax and ax3.
So, you could do:
ax.axvspan(0,xBreakingDistance,facecolor="b",alpha=0.1)
ax3.axvspan(0,xBreakingDistance,facecolor="b",alpha=0.1)
or in one line:
[this_ax.axvspan(0,xBreakingDistance,facecolor="b",alpha=0.1) for this_ax in [ax,ax3]]
It's difficult to analyze your code and not being able to reproduce it. I advise you to build a minimal example. In any case notice that you are calling "plt.axvspan(" which is general call to the library.
You need to specifically state that you want this in both "ax" and "ax2" (i think).
Also if you need more control consider using Patches (I don't know axvspan):
import matplotlib.pyplot as plt
import matplotlib.patches as patches
fig1 = plt.figure()
ax1 = fig1.add_subplot(111, aspect='equal')
ax1.add_patch(
patches.Rectangle(
(0.1, 0.1), # (x,y)
0.5, # width
0.5, # height
)
)
fig1.savefig('rect1.png', dpi=90, bbox_inches='tight')
See that call to "ax1" in the example? Just make something similar to yours. Or just add axvspan to each of your plots.

Categories

Resources