I use the following to reduce width of bars in Panda:
for container in ax.containers:
plt.setp(container, width=.25)
However, on doing this, the labels on the x-axis remain at original position, as seen below. How can I move them to correspond to new bar width. In other words, is there a function to get the x coordinate of the center of each bar?
You may want to set the width during plot(), something like this:
df.plot(kind='bar', stacked=True, width=0.25, align='center')
In the document it doesn't show you can set the width, but in fact it will take it as **kwds
It will plot with the desired width with aligned x-axis labels.
Related
I am using plotly (python) in Dash to create a bar plot. I want to set the absolute height of the yaxis (not the full plot).
So each bar should have a maximum height of x pixels and the whole plot area including the tick labels can expand as necessary for the labels.
Is this possible?
figure explaining desired height
I'm having trouble with the location of the bars on the scale. I understand it to be that some of the hue amounts are 0, so this is throwing off the position of the bars. In the image, the top right plot shows the green and brown bars for 'labour' with a gap between, presumably because that color is 0. Is there a way to put the bars together, and in line with their correspondence on the y-axis?
grid = sns.catplot(x='Type', y='count',
row='Age', col='Gender',
hue='Nationality',
data=dfNorthumbria2, kind='bar', ci=None,legend=True)
grid.set(ylim=(0,5), yticks=[0,1,2,3,4,5])
grid.set(xlabel="Type of Exploitation",ylabel="Total Referrals")
for ax in grid.axes.flatten():
ax.tick_params(labelbottom=True, rotation=90)
ax.tick_params(labelleft=True)
grid.fig.tight_layout()
leg = grid._legend
leg.set_bbox_to_anchor([1.1,0.5])
You can pass a hue_order argument to sns.barplot() via sns.catplot, e.g.
grid = sns.catplot(..., hue_order=['British', 'Romanian', 'Vietnamese',
'Albanian', 'Pakistani', 'Slovak'])
This should close the gap between the green and brown bars, and they will be centered at the tick mark, as they are now in the middle of the list. However, groups of other bars will still not be centered around their tick mark.
This may be an unavoidable consequence of how this plotting function works, it's not designed for such sparse data. So if you want all the different groups of bars to be centered at their respective tick marks, you may have to use a more flexible matplotlib plotting function and create the color subsets manually.
I have the following function that makes boxplots given a pandas dataframe:
def plot_boxplots(data, ylabel):
ax = data.plot.box()
ax.set_ylabel(ylabel)
for label in ax.get_xticklabels():
label.set_rotation(90)
plt.tight_layout()
The reason I rotate the labels is that the label names can be long, and otherwise overlap one another. The y-axis label can also be long.
In the end, I get figures where the actual boxes are compressed in one fourth of the height of the figure, the space being mainly occupied by labels.
For instance:
test_df = pd.DataFrame({
"very_very_very_very_long_name_of_first_series" : np.random.normal(loc=-2, scale=2, size=10),
"very_very_very_very_long_name_of_second_series" : np.random.normal(loc=3, scale=1.5, size=10)})
plot_boxplots(test_df, "vertical_axis_with_long_label")
How can I stretch the canvas (or however it is named: the part with the boxes) vertically?
Ideally, I would like to have something automatic, for instance based on a desired proportion between the canvas and the labels part, or some minimal height for the canvas.
Partial solution
Following comments by Andrey Sobolev, I now have something working with a fixed total aspect ratio:
def plot_boxplots(data, ylabel):
fig = plt.figure(figsize=(6, 12))
ax = fig.add_subplot(111)
data.plot.box(ax=ax)
ax.set_ylabel(ylabel)
for label in ax.get_xticklabels():
label.set_rotation(90)
plt.tight_layout()
I'm still interested in a solution to set the canvas size independently of the total figure size.
It is often sufficient to adjust figure size in the way it's shown in the comments, but if you want to change the size of the axes, here is one way to do it:
ax = plt.axes([x_bl, y_bl, x_tr, y_tr])
So, instead of getting the Axes instance from add_subplot, you can explicitly add it with plt.axes, where x_bl, y_bl are the coordinates of bottom left corner, and x_tr, y_tr are the coordinates of top right corner of the canvas in Figure coordinates, i.e. 0., 0. is the bottom left corner of the Figure, and 1., 1. is the top right corner of the Figure.
I currently use the align=’edge’ parameter and positive/negative widths in pyplot.bar() to plot the bar data of one metric to each axis. However, if I try to plot a second set of data to one axis, it covers the first set. Is there a way for pyplot to automatically space this data correctly?
lns3 = ax[1].bar(bucket_df.index,bucket_df.original_revenue,color='c',width=-0.4,align='edge')
lns4 = ax[1].bar(bucket_df.index,bucket_df.revenue_lift,color='m',bottom=bucket_df.original_revenue,width=-0.4,align='edge')
lns5 = ax3.bar(bucket_df.index,bucket_df.perc_first_priced,color='grey',width=0.4,align='edge')
lns6 = ax3.bar(bucket_df.index,bucket_df.perc_revenue_lift,color='y',width=0.4,align='edge')
This is what it looks like when I show the plot:
The data shown in yellow completely covers the data in grey. I'd like it to be shown next to the grey data.
Is there any easy way to do this? Thanks!
The first argument to the bar() plotting method is an array of the x-coordinates for your bars. Since you pass the same x-coordinates they will all overlap. You can get what you want by staggering the bars by doing something like this:
x = np.arange(10) # define your x-coordinates
width = 0.1 # set a width for your plots
offset = 0.15 # define an offset to separate each set of bars
fig, ax = plt.subplots() # define your figure and axes objects
ax.bar(x, y1) # plot the first set of bars
ax.bar(x + offset, y2) # plot the second set of bars
Since you have a few sets of data to plot, it makes more sense to make the code a bit more concise (assume y_vals is a list containing the y-coordinates you'd like to plot, bucket_df.original_revenue, bucket_df.revenue_lift, etc.). Then your plotting code could look like this:
for i, y in enumerate(y_vals):
ax.bar(x + i * offset, y)
If you want to plot more sets of bars you can decrease the width and offset accordingly.
I'm making a bar chart in Matplotlib with a call like this:
xs.bar(bar_lefts, bar_heights, facecolor='black', edgecolor='black')
I get a barchart that looks like this:
What I'd like is one with no white gap between consecutive bars, e.g. more like this:
Is there a way to achieve this in Matplotlib using the bar() function?
Add width=1.0 as a keyword argument to bar(). E.g.
xs.bar(bar_lefts, bar_heights, width=1.0, facecolor='black', edgecolor='black').
This will fill the bars gaps vertically.
It has been 8 years since this question was asked, and the matplotlib API now has built-in ways to produce filled, gapless bars: pyplot.step() and pyplot.stairs() with the argument fill=True.
See the docs for a fuller comparison, but the primary difference is that step() defines the step positions with N x and N y values just like plot() would, while stairs() defines the step positions with N heights and N+1 edges, like what hist() returns. It is a subtle difference, and I think both tools can create the same outputs.
Just set the width 1 over the number of bars, so:
width = 1 / len(bar_lefts)
xs.bar(bar_lefts, bar_heights, width=width, color='black')
You can set the width equal to the distance between two bars:
width = bar_lefts[-1] - bar_lefts[-2]
xs.bar(bar_lefts, bar_heights, width=width)