Set xticks visible in when plotting using pandas - python

Consider the following snippet
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
data = np.random.rand(10,5)
cols = ["a","b","c","d","e"]
df = pd.DataFrame(data=data, columns = cols)
df.index.name="Time (s)"
fig,axes = plt.subplots(3,2,sharex=True, squeeze=False)
axes = axes.T.flat
axes[5].remove()
df.plot(subplots=True,grid=True,legend=True,ax = axes[0:5])
that produces the following plot
I wish to show the xticks in the subplots where they are missing as I wrote in red with reference to the above picture.
I wish to show only the xticks where I marked in red, not the labels. The labels are fine where they currently are and shall be kept there.
After some search, I tried with
for ax in axes:
ax.tick_params(axis="x")
and
for ax in axes:
ax.spines.set(visible=True)
but with no success.
Any hints?
EDIT: As someone kindly suggested, if I set sharex=False, then when I horizontally zoom on one axes I will not have the same zoom effect on the other axes and this is not what I want.
What I want is to: a) show the xticks in all axes, b) when I horizontally zoom on one axes all the other axes are horizontally zoomed of the same amount.

You need to turn off sharing x properties by setting sharex=False (which is the default value by the way in matplotlib.pyplot.subplots):
Replace this:
fig,axes = plt.subplots(3,2,sharex=True, squeeze=False)
By this:
fig,axes = plt.subplots(3,2, squeeze=False)
# Output:

Related

Put the legend of pandas bar plot with secondary y axis in front of bars

I have a pandas DataFrame with a secondary y axis and I need a bar plot with the legend in front of the bars. Currently, one set of bars is in front of the legend. If possible, I would also like to place the legend in the lower-left corner. Any ideas appreciated!
I have attempted to set the legend=false and add a custom legend, but it has the same issue. I've tried reordering the columns but there's no way to clear a space for this on the chart.
import pandas as pd
import matplotlib.pyplot as plt
df_y = pd.DataFrame([['jade',12,800],['lime',12,801],['leaf',12,802],
['puke',12,800]], columns=['Territory','Cuisines','Restaurants'])
df_y.set_index('Territory', inplace=True)
plt.figure()
ax=df_y.plot(kind='bar', secondary_y=['Restaurants'])
ax.set_ylabel('Cuisines')
ax.right_ax.set_ylabel('Restaurants')
plt.show()
One set of bars appears behind the legend, and one set appears in front of the legend. The link below goes to an image showing the problem. Thank you!
You can create the legend yourself.
Use the color cycler to get the colors correct when zipped with the columns. Make sure to set legend=False in the barplot. loc=3 is the lower left.
import matplotlib.patches as mpatches
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
df_y.plot(kind='bar', secondary_y=['Restaurants'], legend=False, ax=ax)
ax.set_ylabel('Cuisines')
ax.right_ax.set_ylabel('Restaurants')
L = [mpatches.Patch(color=c, label=col)
for col,c in zip(df_y.columns, plt.rcParams['axes.prop_cycle'].by_key()['color'])]
plt.legend(handles=L, loc=3)
plt.show()

bar plot does not respect order of the legend text in matplotlib

Just noticed that the legend text doesnt have the same order as the plot bars. I would expect to see the "Banana" in first place of the legend. Is it possible to correct such behavior? Thanks
My code is:
import matplotlib.pyplot as plt
import pandas as pd
df = pd.DataFrame({"Apple" : [2,3,4,1], "Banana" : [4,2,1,2]})
ax = df.plot.barh()
ax.legend()
plt.show()
And my graph:
The legend labels are actually ordered correctly. Matplotlib's vertical axes by default start at the bottom and reach upwards. Hence the blue bars come first, just as in the legend.
You can invert the legend handles and labels:
h, l = ax.get_legend_handles_labels()
ax.legend(h[::-1], l[::-1])
You may also decide to invert the y axis.
ax = df.plot.barh()
ax.invert_yaxis()
Order of legend handlers is selected by columns ordering, you have to sort columns' names of dataframe in reversed order (use reindex_axis for column axis).
import matplotlib.pyplot as plt
import pandas as pd
df = pd.DataFrame({"Apple" : [2,3,4,1], "Banana" : [4,2,1,2]})
df = df.reindex_axis(reversed(sorted(df.columns)), axis = 1)
ax = df.plot.barh()
ax.legend()
plt.show()

How to change the positions of subplot titles and axis labels in Seaborn FacetGrid?

I am trying to plot a polar plot using Seaborn's facetGrid, similar to what is detailed on seaborn's gallery
I am using the following code:
sns.set(context='notebook', style='darkgrid', palette='deep', font='sans-serif', font_scale=1.25)
# Set up a grid of axes with a polar projection
g = sns.FacetGrid(df_total, col="Construct", hue="Run", col_wrap=5, subplot_kws=dict(projection='polar'), size=5, sharex=False, sharey=False, despine=False)
# Draw a scatterplot onto each axes in the grid
g.map(plt.plot, 'Rad', ''y axis label', marker=".", ms=3, ls='None').set_titles("{col_name}")
plt.savefig('./image.pdf')
Which with my data gives the following:
I want to keep this organisation of 5 plots per line.
The problem is that the title of each subplot overlap with the values of the ticks, same for the y axis label.
Is there a way to prevent this behaviour? Can I somehow shift the titles slightly above their current position and can I shift the y axis labels slightly on the left of their current position?
Many thanks in advance!
EDIT:
This is not a duplicate of this SO as the problem was that the title of one subplot overlapped with the axis label of another subplot.
Here my problem is that the title of one subplot overlaps with the ticks label of the same subplot and similarly the axis label overlaps with the ticks label of the same subplot.
I also would like to add that I do not care that they overlap on my jupyter notebook (as it as been created with it), however I want the final saved image with no overlap, so perhaps there is something I need to do to save the image in a slightly different format to avoid that, but I don't know what (I am only using plt.savefig to save it).
EDIT 2: If someone would like to reproduce the problem here is a minimal example:
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns
sns.set()
sns.set(context='notebook', style='darkgrid', palette='deep', font='sans-serif', font_scale=1.5)
# Generate an example radial datast
r = np.linspace(0, 10000, num=100)
df = pd.DataFrame({'label': r, 'slow': r, 'medium-slow': 1 * r, 'medium': 2 * r, 'medium-fast': 3 * r, 'fast': 4 * r})
# Convert the dataframe to long-form or "tidy" format
df = pd.melt(df, id_vars=['label'], var_name='speed', value_name='theta')
# Set up a grid of axes with a polar projection
g = sns.FacetGrid(df, col="speed", hue="speed",
subplot_kws=dict(projection='polar'), size=4.5, col_wrap=5,
sharex=False, sharey=False, despine=False)
# Draw a scatterplot onto each axes in the grid
g.map(plt.scatter, "theta", "label")
plt.savefig('./image.png')
plt.show()
Which gives the following image in which the titles are not as bad as in my original problem (but still some overlap) and the label on the left hand side overlap completely.
In order to move the title a bit higher you can set at new position,
ax.title.set_position([.5, 1.1])
In order to move the ylabel a little further left, you can add some padding
ax.yaxis.labelpad = 25
To do this for the axes of the facetgrid, you'd do:
for ax in g.axes:
ax.title.set_position([.5, 1.1])
ax.yaxis.labelpad = 25
The answer provided by ImportanceOfBeingErnest in this SO question may help.

Setting xticks in pandas bar plot

I came across this different behaviour in the third example plot below. Why am I able to correctly edit the x-axis' ticks with pandas line() and area() plots, but not with bar()? What's the best way to fix the (general) third example?
import numpy as np
import pandas as pd
import matplotlib.ticker as ticker
import matplotlib.pyplot as plt
x = np.arange(73,145,1)
y = np.cos(x)
df = pd.Series(y,x)
ax1 = df.plot.line()
ax1.xaxis.set_major_locator(ticker.MultipleLocator(10))
ax1.xaxis.set_minor_locator(ticker.MultipleLocator(2.5))
plt.show()
ax2 = df.plot.area(stacked=False)
ax2.xaxis.set_major_locator(ticker.MultipleLocator(10))
ax2.xaxis.set_minor_locator(ticker.MultipleLocator(2.5))
plt.show()
ax3 = df.plot.bar()
ax3.xaxis.set_major_locator(ticker.MultipleLocator(10))
ax3.xaxis.set_minor_locator(ticker.MultipleLocator(2.5))
plt.show()
Problem:
The bar plot is meant to be used with categorical data. Therefore the bars are not actually at the positions of x but at positions 0,1,2,...N-1. The bar labels are then adjusted to the values of x.
If you then put a tick only on every tenth bar, the second label will be placed at the tenth bar etc. The result is
You can see that the bars are actually positionned at integer values starting at 0 by using a normal ScalarFormatter on the axes:
ax3 = df.plot.bar()
ax3.xaxis.set_major_locator(ticker.MultipleLocator(10))
ax3.xaxis.set_minor_locator(ticker.MultipleLocator(2.5))
ax3.xaxis.set_major_formatter(ticker.ScalarFormatter())
Now you can of course define your own fixed formatter like this
n = 10
ax3 = df.plot.bar()
ax3.xaxis.set_major_locator(ticker.MultipleLocator(n))
ax3.xaxis.set_minor_locator(ticker.MultipleLocator(n/4.))
seq = ax3.xaxis.get_major_formatter().seq
ax3.xaxis.set_major_formatter(ticker.FixedFormatter([""]+seq[::n]))
which has the drawback that it starts at some arbitrary value.
Solution:
I would guess the best general solution is not to use the pandas plotting function at all (which is anyways only a wrapper), but the matplotlib bar function directly:
fig, ax3 = plt.subplots()
ax3.bar(df.index, df.values, width=0.72)
ax3.xaxis.set_major_locator(ticker.MultipleLocator(10))
ax3.xaxis.set_minor_locator(ticker.MultipleLocator(2.5))

Xaxis-Tick labels have disappeared plotting with pandas onto subplot, but are still stored

Using a complicated script that nests among other pandas.DataFrame.plot() and GridSpec in a subplot setting, I have the following problem:
When I create a 2-cols 1-row gridspec, the tick lables are all correct. When I create a 1-col 2-rows gridspec however, as soon as I plot onto the first (upper row) axes using pandas.DataFrame.plot(), the x-ticklabels for the top row disappear (the ticks remain).
It is not the case that the top ticks change once I draw something on the lower ax, sharex appears to not be the issue.
However, my x-labels are still stored:
axes[0].get_xaxis().get_ticklabels()
Out[59]:
<a list of 9 Text major ticklabel objects>
It's just that they're not displayed. I suspected a NullFormatter, but that's not the case either:
axes[0].get_xaxis().get_major_formatter()
Out[57]:
<matplotlib.ticker.ScalarFormatter at 0x7f7414330710>
I get both ticks and labels on the top of the first axes when I do
axes[0].get_xaxis().tick_top()
However, when I then go back to tick_bottom(), I only have ticks on bottom, not the labels.
What can cause my stored labels to not to be displayed despite a "normal" formatter?
Here's a simple example:
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import gridspec
df = pd.DataFrame(np.random.rand(100,2), columns=['A', 'B'])
figure = plt.figure()
GridSpec = gridspec.GridSpec(nrows=2, ncols=1)
[plt.subplot(gsSpec) for gsSpec in GridSpec]
axes = figure.axes
df.plot(secondary_y=['B'], ax=axes[0], sharex=False)
It's the secondary_y=['B'] that causes the xticks to disappear. I'm not sure why it does that.
Fortunately, you can use plt.setp(ax.get_xticklabels(), visible=True) (docs) to turn them back on manually:
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import gridspec
df = pd.DataFrame(np.random.rand(100,2), columns=['A', 'B'])
figure = plt.figure()
GridSpec = gridspec.GridSpec(nrows=2, ncols=1)
axes = [plt.subplot(gsSpec) for gsSpec in GridSpec]
ax = axes[0]
df.plot(secondary_y=['B'], ax=ax, sharex=True)
plt.setp(ax.get_xticklabels(), visible=True)

Categories