How do you plot an upside down histogram in matplotlib? - matplotlib

Can you plot a histogram in matplotlib so that it appears upside down, i.e. the base of the histogram is along the top axis and it "hangs" down? Or, alternatively, if plotting with orientation='horizontal', so that the base of the histogram is on the right hand axis?

Yes, use invert_yaxis:
df = pd.DataFrame({'a':[1,2,3,1,2,2,2],
'b':[1,1,1,3,2,2,2]})
ax = df.plot.hist()
ax.invert_yaxis()
Output:

Related

Seaborn: how to make a Log base 2 axis in a small multiples plot?

I'm doing a small multiples plot with seaborn using relplot:
g = sns.relplot(data=df,
kind='scatter',
col='mycol', row='arow',
x='a', y='b',
hue='c',
legend=False,
alpha=.5)
I can easily tranform the axis for a log scale in base 10:
g.set(xscale="log")
g.set(yscale="log")
If I were ploting a simple plot with matplotlib I'd be able to use a log scale in base 2:
ax.set_xscale('log', basex=2)
ax.set_yscale('log', basey=2)
But how do I make a Log2 plot in Seaborn?
Just discovered how to do it using a global function:
plt.xscale('log', basex=2)
plt.yscale('log', basey=2)

Scatter plot without x-axis

I am trying to visualize some data and have built a scatter plot with this code -
sns.regplot(y="Calls", x="clientid", data=Drop)
This is the output -
I don't want it to consider the x-axis. I just want to see how the data lie w.r.t y-axis. Is there a way to do that?
As #iayork suggested, you can see the distribution of your points with a striplot or a swarmplot (you could also combine them with a violinplot). If you need to move the points closer to the y-axis, you can simply adjust the size of the figure so that the width is small compared to the height (here i'm doing 2 subplots on a 4x5 in figure, which means that each plot is roughly 2x5 in).
fig, (ax1,ax2) = plt.subplots(1,2, figsize=(4,5))
sns.stripplot(d, orient='vert', ax=ax1)
sns.swarmplot(d, orient='vert', ax=ax2)
plt.tight_layout()
However, I'm going to suggest that maybe you want to use distplot instead. This function is specifically created to show the distribution of you data. Here i'm plotting the KDE of the data, as well as the "rugplot", which shows the position of the points along the y-axis:
fig = plt.figure()
sns.distplot(d, kde=True, vertical=True, rug=True, hist=False, kde_kws=dict(shade=True), rug_kws=dict(lw=2, color='orange'))

Relocating legend from GeoPandas plot

I'm plotting a map with legends using the GeoPandas plotting function. When I plot, my legends appear in the upper right corner of the figure. Here is how it looks like:
I wanted to move the legends to the lower part of the graph. I would normally would have done something like this for a normal matplotlib plot:
fig, ax = plt.subplots(1, figsize=(4.5,10))
lima_bank_num.plot(ax=ax, column='quant_cuts', cmap='Blues', alpha=1, legend=True)
ax.legend(loc='lower left')
However, this modification is not taken into account.
This could be done using the legend_kwds argument:
df.plot(column='values', legend=True, legend_kwds={'loc': 'lower right'});
You can access the legend defined on the ax instance with ax.get_legend(). You can then update the location of the legend using the method set_bbox_to_anchor. This doesn't provide the same ease of use as the loc keyword when creating a legend from scratch, but does give control over placement. So, for your example, something like:
leg = ax.get_legend()
leg.set_bbox_to_anchor((0., 0., 0.2, 0.2))
A bit of documentation of set_bbox_to_anchor, though I don't find it extraordinarily helpful.
If you have a horizontal legend and you're trying to simply reduce the gap between the legend and plot, I recommend the colorbar approach detailed at https://gis.stackexchange.com/a/330175/32531 along with passing the pad legend_kwd argument:
legend_kwds={"orientation": "horizontal", "pad": 0.01}

Reducing the distance between two boxplots

I'm drawing the bloxplot shown below using python and matplotlib. Is there any way I can reduce the distance between the two boxplots on the X axis?
This is the code that I'm using to get the figure above:
import matplotlib.pyplot as plt
from matplotlib import rcParams
rcParams['ytick.direction'] = 'out'
rcParams['xtick.direction'] = 'out'
fig = plt.figure()
xlabels = ["CG", "EG"]
ax = fig.add_subplot(111)
ax.boxplot([values_cg, values_eg])
ax.set_xticks(np.arange(len(xlabels))+1)
ax.set_xticklabels(xlabels, rotation=45, ha='right')
fig.subplots_adjust(bottom=0.3)
ylabels = yticks = np.linspace(0, 20, 5)
ax.set_yticks(yticks)
ax.set_yticklabels(ylabels)
ax.tick_params(axis='x', pad=10)
ax.tick_params(axis='y', pad=10)
plt.savefig(os.path.join(output_dir, "output.pdf"))
And this is an example closer to what I'd like to get visually (although I wouldn't mind if the boxplots were even a bit closer to each other):
You can either change the aspect ratio of plot or use the widths kwarg (doc) as such:
ax.boxplot([values_cg, values_eg], widths=1)
to make the boxes wider.
Try changing the aspect ratio using
ax.set_aspect(1.5) # or some other float
The larger then number, the narrower (and taller) the plot should be:
a circle will be stretched such that the height is num times the width. aspect=1 is the same as aspect=’equal’.
http://matplotlib.org/api/axes_api.html#matplotlib.axes.Axes.set_aspect
When your code writes:
ax.set_xticks(np.arange(len(xlabels))+1)
You're putting the first box plot on 0 and the second one on 1 (event though you change the tick labels afterwards), just like in the second, "wanted" example you gave they are set on 1,2,3.
So i think an alternative solution would be to play with the xticks position and the xlim of the plot.
for example using
ax.set_xlim(-1.5,2.5)
would place them closer.
positions : array-like, optional
Sets the positions of the boxes. The ticks and limits are automatically set to match the positions. Defaults to range(1, N+1) where N is the number of boxes to be drawn.
https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.pyplot.boxplot.html
This should do the job!
As #Stevie mentioned, you can use the positions kwarg (doc) to manually set the x-coordinates of the boxes:
ax.boxplot([values_cg, values_eg], positions=[1, 1.3])

matplotlib using twinx and twiny together (like twinxy)

Can I have both twinx and twiny together (i.e. something like twinxy)?
I want to put a CDF on a bar plot where the X axis of the bar plot is in log-scale. I cannot make the Ys together, because the bar plot y range is very large comparing [0,1] for CDF.
Any ideas?
Thanks,
If I understand your question right, you want to plot two things on the same axes with no shared axis. There is probably a better way to do this, but you can stack twinx (doc) and twiny (doc) as such
ax # your first axes
ax_new = ax.twinx().twiny()
Which will give you tick marks on all sides of the plot. ax will plot against the bottom and left, ax_new will plot against the top and right.