seaborn not coloring bars in barplot - python

I have started working on my thesis and I already have a problem.
I am trying to do a bar plot of ca. 250 bars, but it seems like that seaborn is not showing colors for most of the bars. I thought it could cycle through the palette - but it just shows them white. If I take a smaller sample (up to 99 I think), every bar is colored.
Even having one single color (not a palette), shows white bars.
Here is the code and the graph:
Can someone help me with this? Thank you!

I think that this problem arises because, by default in seaborn, the bars in a barplot are outlined with a thin white boundary line. When the bars themselves are very thin this white boundary is the only thing that you see. Try changing the plot command to:
g = sb.barplot(x = x, y = y, palette = sb.color_palette("RdBu", n_colors=7), lw=0.)
The lw=0. removes the boundary line and you should then see the bar colours.

Here's a piece of code to test the palettes of seaborn:
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import seaborn as sb
print("Seaborn version : {0}".format(sb.__version__))
# Seaborn version : 0.10.0
print("Matplotlib version : {0}".format(matplotlib.__version__))
# Matplotlib version : 3.1.3
Just to let you know it worked with these versions
# simple color test without palette
n = 1000
x = np.arange(1,n+1,1)
y = np.random.randint(-100,100,n)*np.random.random(n)
sb.barplot(x,y)
plt.xticks([])
plt.show()
# with your color choices
plt.figure(figsize=(20,20))
sb.barplot(x,y, palette=sb.color_palette("RdBu",n_colors=7))
plt.xticks([])
plt.show()
So it seems to work with the arrays of my code.
Maybe:
Your data is not understood by seaborn (check you dataframe?)
You have a bugged version of seaborn or matplotlib (try pip install seaborn==0.10.0 and pip install matplotlib==3.1.3)
You can try another palette of color
Hope this helps!
EDIT:
Thanks to #ImportanceOfBeingErnest, I think I understood your problem. It cames from this style, just comment/uncomment to see the result
# sb.set_style("darkgrid")
Sadly, I did not find any kwargs option related to the darkgrid style to remove the bug... So I propose we recreate this style manually!
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.set_facecolor('whitesmoke')
# background color
ax.grid(color='white', linestyle='-', linewidth=1)
# the grid
sb.barplot(x,y,zorder=2, palette=sb.color_palette("RdBu",n_colors=7))
#zorder=2 to draw above the grid
plt.xticks([])
plt.show()

Try sns.reset_orig() before plotting.

Related

How to change colour of histograms in seaborn pairplot (when using jupyter themes)

I'm not sure if it's just the theme and darktheme that I'm using but I can't seem to change the colours of the histogram on my pairplot.
Is there a way to change them as they are very dark looking or is this just because of the theme?
g = sns.pairplot(df)
g.map_upper(sns.scatterplot,color='red')
g.map_lower(sns.scatterplot, color='green')
g.map_diag(plt.hist, color='blue')
Note that sns.pairplot creates a PairGrid and already draws the scatter dots and histogram. If you then draw your own histogram over it, thes probably don't coincide. Therefore, it can help to replace sns.pairplot with sns.PairGrid giving empty subplots.
The following code has been tested with Seaborn 0.11.1 and matplotlib 3.4.1.
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme('notebook', style='dark')
plt.style.use("dark_background")
df = sns.load_dataset('iris')
g = sns.PairGrid(df)
g.map_upper(sns.scatterplot, color='crimson')
g.map_lower(sns.scatterplot, color='limegreen')
g.map_diag(plt.hist, color='skyblue')
plt.show()

consistent colors after multiple calls of pd.DataFrame.plot()

I have a dataframe v with some numerical data in it.
v=pd.DataFrame(data=np.random.rand(300,3))
I am want to plot on the same matplotlib figure:
a scatter plot
a moving average of the same points
I do that using pd.DataFrame.plot()
plt.figure()
v.plot(style='o',legend=False,ax=plt.gca(),alpha=0.2,ls='')
v.rolling(7).mean().plot(legend=False,ax=plt.gca())
This works fine.
However, the points drawn with the first plot are colored according to their row number. Same happens for the lines in the second plot.
I would like the two colors to be consistent between the two plot commands, so
line obtained by moving average to have same color as in the scatter. How to get that?
Here is what I get running the code.
Obviously, I cannot figure out if the red lines correspond to the green orange or blue points...
ORIGINAL
I believe you need -
%matplotlib inline # only for jupyter notebooks
import pandas as pd
from matplotlib import pyplot as plt
import numpy as np
colors = {0: 'red', 1:'green', 2:'blue'}
v=pd.DataFrame(data=np.random.rand(300,3))
plt.figure()
v.plot(marker='o',legend=False,ax=plt.gca(),ls='', alpha=0.2, color=colors.values())
v.rolling(7).mean().plot(legend=False,ax=plt.gca(), color=colors.values())
UPDATE
Just go with -
Option 1 (no extra cm dependency)
colors_rand = np.random.rand(len(v.columns),3)
v.plot(marker='o',legend=False,ax=plt.gca(),ls='', alpha=0.5, color=colors_rand )
v.rolling(7).mean().plot(legend=False,ax=plt.gca(), color=colors_rand )
Option 2(as suggested by OP)
v.plot(marker='o',legend=False,ax=plt.gca(),ls='', alpha=0.5, colors=cm.rainbow(np.linspace(0,1,v.shape[1]) ))
v.rolling(7).mean().plot(legend=False,ax=plt.gca(), colors=cm.rainbow(np.linspace(0,1,v.shape[1]) ))

How do I fill a region with only hatch (no background colour) in matplotlib 2.0

With the recent updates to matplotlib fill_between and hatch (see links here), hatch filled regions are no longer behaving as they did previously. That is, the region is either filled with color, and hatches are black or the region isn't filled with color and hatches aren't visible.
Here is a side-by-side comparison of plots from the same code (from this answer)
import matplotlib.pyplot as plt
import matplotlib as mpl
plt.plot([0,1],[0,1],ls="--",c="b")
plt.fill_between([0,1],[0,1], color="none", hatch="X", edgecolor="b", linewidth=0.0)
plt.show()
is there a way to reproduce the 1.X plot in 2.X? I'm not at all familiar with back-ends but mpl.rcParams['hatch.color'] = 'b' and variations of the keywords color, edgecolor aren't helping.
Thanks in advance for helping to clear this up.
matplotlib > 2.0.1
Since there was a lot of discussion on GitHub about hatching, there were now some changes introduced which make hatching much more intuitive.
The example from the question now works again as expected, if the facecolor argument is used instead of the color argument.
import matplotlib.pyplot as plt
plt.plot([0,1],[0,1],ls="--",c="b")
plt.fill_between([0,1],[0,1], facecolor="none", hatch="X", edgecolor="b", linewidth=0.0)
plt.show()
matplotlib 2.0.0
To keep the original post, which has lead to this issue:
In matplotlib 2.0.0 you can get the old style back by using plt.style.use('classic').
##Classic!
import matplotlib.pyplot as plt
plt.style.use('classic')
plt.rcParams['hatch.color'] = 'b'
plt.plot([0,1],[0,1],ls="--",c="b")
plt.fill_between([0,1],[0,1], color="none", hatch="X", edgecolor="b", linewidth=0.0)
plt.show()
Without setting the old style the following works by not setting the color to none, but instead make it transparent.
## New
import matplotlib.pyplot as plt
plt.rcParams['hatch.color'] = 'b'
plt.plot([0,1],[0,1],ls="--",c="b")
plt.fill_between([0,1],[0,1], hatch="X", linewidth=0.0, alpha=0.0)
plt.show()
Both methods rely on setting the hatch-color via plt.rcParams['hatch.color'] = 'b'.
Unfortunately, there is currently no other way of setting the hatch color in matplotlib 2.0.0.
The matplotlib page that explains the changes states
There is no API level control of the hatch color or linewidth.
There is an issue on this topic open at github and API control may be (re)added in an upcoming version (which is indeed done with version 2.0.1).
With the release of matplotlib 2.0.1 we now have much better control of the hatching.
Currently, the only way I can find to remove the background colour (as asked) is to set color = None, alpha = 0 in the fill_between args. This works as requested but unfortunately results in pretty useless legends.
Thanks to QuLogic pointing out I should be using facecolor = 'none' this now works perfectly.
from matplotlib import pyplot as plt
import numpy as np
def plt_hist(axis, data, hatch, label):
counts, edges = np.histogram(data, bins=int(len(data)**.5))
edges = np.repeat(edges, 2)
hist = np.hstack((0, np.repeat(counts, 2), 0))
outline, = ax.plot(edges,hist,linewidth=1.3)
axis.fill_between(edges,hist,0,
edgecolor=outline.get_color(), hatch = hatch, label=label,
facecolor = 'none') ## < removes facecolor
axis.set_ylim(0, None, auto = True)
h1 = '//'
d1 = np.random.rand(130)
lab1 = 'Rand1'
h2 = '\\\\'
d2 = np.random.rand(200)
lab2 = 'Rand2'
fig, ax = plt.subplots(1)
plt_hist(ax,d1,h1,lab1)
plt_hist(ax,d2,h2,lab2)
ax.legend()

legend setting (numpoints and scatterpoints) in matplotlib does not work

I tried to get the legend right for the dashed line so I played with the rcParams a little bit, but it for some reasons wouldn't work on my computer.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
matplotlib.rcParams['legend.numpoints'] = 5
matplotlib.rcParams['legend.scatterpoints'] = 5
fig, axs = plt.subplots()
axs.plot(range(10), '--k', label="line")
axs.plot(range(10), range(10)[::-1], ':k', label="scatter")
axs.legend(loc=9)
plt.show()
And the resultant figure is:
And as can be seen, the numpoints for the dashed line is not enough. Would anyone please help?
Thanks!
If you make a plot with markers, matplotlib.rcParams['legend.numpoints'] adjust the number of points drawn on the legend lines.
If you substitute your plot by these:
axs.plot(range(10), '--k', label="line", marker='d')
axs.plot(range(10), range(10)[::-1], ':k', label="scatter", marker='o')
you get this image:
I don't know what does matplotlib.rcParams['legend.scatterpoints'] do, but I guess regulates the number of points in the legend of scatter plots.
If you want to change the length of the lines in the legend give a try with matplotlib.rcParams['legend.handlelength'] and/or matplotlib.rcParams['legend.handleheight']. More info about rc file can be found here
As suggested by #tcaswell, you don't have to set rc parameters. All the legend.* parameters are available as keywords for the legend function. See matplotlib.pyplot.legend documentation

Matplotlib Errorbar Caps Missing

I'm attempting to create a scatter plot with errorbars in matplotlib. The following is an example of what my code looks like:
import matplotlib.pyplot as plt
import numpy as np
import random
x = np.linspace(1,2,10)
y = np.linspace(2,3,10)
err = [random.uniform(0,1) for i in range(10)]
plt.errorbar(x, y,
yerr=err,
marker='o',
color='k',
ecolor='k',
markerfacecolor='g',
label="series 2",
capsize=5,
linestyle='None')
plt.show()
The problem is the plot which is output contains no caps at all!
For what it's worth, I'm on Ubuntu 13.04, Python 2.7.5 |Anaconda 1.6.1 (64-bit)|, and Matplotlib 1.2.1.
Could this be a hidden rcparam that needs to be overwritten?
What worked for me was adding this (as per: How to set the line width of error bar caps, in matplotlib):
(_, caps, _) = plt.errorbar(x,y, yerr=err, capsize=20, elinewidth=3)
for cap in caps:
cap.set_color('red')
cap.set_markeredgewidth(10)
Slight simplification of astromax's answer:
plt.errorbar(x,y, yerr=err, capsize=20, elinewidth=3, markeredgewidth=10)
It seems that somehow markeredgewidth is defaulting to 0 sometimes.
It has to do with the rcParams in matplotlib. To solve it, add the following lines at the beginning of your script:
import matplotlib
matplotlib.rcParams.update({'errorbar.capsize': 2})
It also works with plt.bar().

Categories