I want to create a bar plot (vertical) using seaborn, each x axis label will have n (2 in the example) bars of different colors - but each bar will be floating - in other words it uses the matplotlib bar bottom parameter
this works without the bottom part as follows, but fails with it
import pandas as pd
import seaborn as sns
d = {'month':['202001','202002','202003','202001','202002','202003'],
'range' : [0.94,4.47,0.97,4.70,0.98,1.23],
'bottom' : [8.59,17.05,8.35,17.78,8.32,5.67],
'group' : ['a','a','a','b','b','b']
}
df = pd.DataFrame(data=d)
sns.barplot(data=df,x = "month", y = "range",hue='group')
(Sorry I can't upload the picture for some reason, I think the service is blocked from my work, but the code will display it if run)
but when I add the bottom parameters it fails
sns.barplot(data=df,x = "month", y = "range",hue='group',bottom='bottom')
I appreciate the help, and perhaps an explanation of why it is failing, as logically it should work
The bars indicate a range of forecasts for a measure, and I want to show them as a rectangle
sns itself doesn't handle bottom, so it's passed to plt.bar. But plt.bar requires bottom to have the same shape/size with x and y which is not the case when data is passed by sns.
Let's try a work around with pandas plot function:
to_plot = df.pivot(index='month',columns='group')
fig,ax = plt.subplots()
to_plot['range'].add(to_plot['bottom']).plot.bar(ax=ax)
# cover the bars up to `bottom`
# replace `w` with background color of your choice
to_plot['bottom'].plot.bar(ax=ax, color='w', legend=None)
Output:
sns.set()
to_plot = df.pivot(index='month',columns='group')
For another approach that allows a specific style:
# set sns plot style
sns.set()
fig,ax = plt.subplots()
for i,(label,r) in enumerate(to_plot.iterrows()):
plt.bar([i-0.1,i+0.1],r['range'],
bottom=r['bottom'],
color=['C0','C1'],
width=0.2)
plt.xticks(np.arange(len(to_plot)), to_plot.index);
Output:
Related
How do you change the colors of the y-axis labels in a joyplot using joypy package?
Here is a sample code where i can change the color if the x-axis labels, but not the y-axis.
import joypy
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
## DATA
url = "https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data"
new_names = ['SepalLength','SepalWidth','PetalLength','PetalWidth','Name']
iris = pd.read_csv(url, names=new_names, skiprows=0, delimiter=',')
## PLOT
fig, axes = joypy.joyplot(iris)
## X AXIS
plt.tick_params(axis='x', colors='red')
## Y AXIS (NOT WORKING)
plt.tick_params(axis='y', colors='red')
I'm pretty sure the issue is because there are mutliple sub-y-axis's, one for each density plot, and they are actually hidden already.
Not sure how to access the y-axis that is actually shown (I want to change the color of "SepalLength")
Joyplot is using Matplotlib
r-beginners' comment worked for me. If you want to change the colors of all the y-axis labels, you can iterate through them like this:
for ax in axes:
label = ax.get_yticklabels()
ax.set_yticklabels(label, fontdict={'color': 'r'})
This results in a warning that you're not supposed to use set_xticklabels() before fixing the tick positions using set_xticks (see documentation here) but with joypy it didn't result in any errors for me.
Here's another solution that just changes the color of the label directly:
for ax in axes:
label = ax.get_yticklabels()
label[0].set_color('red')
I have a straightforward countplot in seaborn.
Code is:
ax = sns.countplot(x="days", data=df,color ='cornflowerblue')
ax.set_xticklabels(ax.get_xticklabels(),rotation=90)
ax.set(xlabel='days', ylabel='Conversions')
ax.set_title("Days to Conversion")
for p in ax.patches:
count = p.get_height()
x = p.get_x() + p.get_width()/1.25
y = p.get_height()*1.01
ax.annotate(count, (x, y),ha='right')
Which produces:
I'm trying to make the chart a bit 'prettier'. Specifically I want to raise the height of the outline so it wont cross the count numbers on first bar, and make the count numbers centered with a small space about the bar. Can't get it to work.
Guidance please.
To set the labels, in the latest matplotlib version (3.4.2), there is a new function bar_label() which takes care of positioning. In older versions you could use your code, but use x = p.get_x() + p.get_width()/2 and set ax.text(..., ha='center').
To make room for the labels, an extra margin can be added via ax.margins(y=0.1).
import matplotlib.pyplot as plt
import seaborn as sns
df = sns.load_dataset('tips')
ax = sns.countplot(x="day", data=df, color='cornflowerblue')
ax.tick_params(axis='x', labelrotation=90)
ax.bar_label(ax.containers[-1])
ax.margins(y=0.1)
plt.tight_layout()
plt.show()
Is there a way to adjust the axes limits of pairplot(), but not as individual plots? Maybe a setting to produce better axes limits?
I would like to have the plots with a bigger range for the axes. My plots axes allows all the data to be visualized, but it is too 'zoomed in'.
My code is:
import pandas as pd
mport matplotlib.pyplot as plt
import seaborn as sns
sns.set_style('darkgrid')
g = sns.pairplot(iris, hue = 'species', diag_kind = 'hist', palette = 'Dark2', plot_kws={"s": 20})
The link for my plot and what I would like to plot to look like is here:
pairplot
To change the subplots, g.map(func, <parameters>) can be used. A small problem is that func needs to accept color as parameter, and plt.margins() gives an error when color is used. Moreover, map uses x and y to indicate the row and column variables. You could write a dummy function that simply calls plt.margin(), for example g.map(lambda *args, **kwargs: plt.margins(x=0.2, y=0.3)).
An alternative is to loop through g.axes.flat and call ax.margins() on each of them. Note that many axes are shared in x and/or y direction. The diagonal is treated differently; for some reason ax.margins needs to be called a second time on the diagonal.
To have the histogram for the different colors stacked instead of overlapping, diag_kws={"multiple": "stack"} can be set.
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_style('darkgrid')
iris = sns.load_dataset('iris')
g = sns.pairplot(iris, hue='species', diag_kind='hist', palette='Dark2',
plot_kws={"s": 20}, diag_kws={"multiple": "stack"})
# g.map(plt.margins, x=0.2, y=0.2) # gives an error
for ax in g.axes.flat:
ax.margins(x=0.2, y=0.2)
for ax in g.diag_axes:
ax.margins(y=0.2)
plt.show()
PS: still another option, is to change the rcParams which will have effect on all the plots created later in the code:
import matplotlib as mpl
mpl.rcParams['axes.xmargin'] = 0.2
mpl.rcParams['axes.ymargin'] = 0.2
I don't know if it's possible with Matplotlib or seaborn or another tools to plot 1 line and 1 bar (candlestick style) , both in one figure . Like the image below (in excel) :
The x-axis and y-axis are the same
following the response below , I choose mplfinance : mplfinance
i have the following dataframe (daily)
and with the following function we can plot :
def ploting_chart(daily):
# Take marketcolors from 'yahoo'
mc = mpf.make_marketcolors(base_mpf_style='yahoo',up='#ff3300',down='#009900',inherit=True)
# Create a style based on `seaborn` using those market colors:
s = mpf.make_mpf_style(base_mpl_style='seaborn',marketcolors=mc,y_on_right=True,
gridstyle = 'solid' , mavcolors = ['#4d79ff','#d24dff']
)
# **kwargs
kwargs = dict(
type='candle',mav=(7,15),volume=True, figratio=(11,8),figscale=2,
title = 'Covid-19 Madagascar en traitement',ylabel = 'Total en traitement',
update_width_config=dict(candle_linewidth=0.5,candle_width=0.5),
ylabel_lower = 'Total'
)
# Plot my new custom mpf style:
mpf.plot(daily,**kwargs,style=s,scale_width_adjustment=dict(volume=0.4))
I get the final result
Yes, the plt.figure or plt.subplots gives you a figure object and then you can plot as many figures as you want. In fact if you use
import seaborn as sns
fmri = sns.load_dataset("fmri")
f,ax = plt.subplots(1,1,figsize=(10,7)) # make a subplot of 1 row and 1 column
g1 = sns.lineplot(x="timepoint", y="signal", data=fmri,ax=ax) # ax=axis object is must
g2 = sns.some_other_chart(your_data, ax=ax)
g3 = ax.some_matlotlib_chart(your_data) # no need to use ax=ax
Seaborn does not support Candlestick but you can plot using the matplotlib on the same axis.
from matplotlib.finance import candlestick_ohlc
candlestick_ohlc(ax, data.values, width=0.6, colorup='g', colordown='r') # just a dummy code to explain. YOu can see the ax object here as first arg
You can even use the pandas df.plot(data,kind='bar',ax=ax,**kwargs) to plot within the same axis object.
Note: Some of the seaborn charts do not support plotting on the same ax because they use their own grid such as relplot
Yes, mplfinance allows you to plot multiple data sets, on the same plot, or on multiple subplots, where each one can be any of candlestick, ohlc-bars, line, scatter, or bar chart.
For more information, see for example:
Adding Your Own Technical Studies to Plots
Subplots: Multiple Plots on a Single Figure, including:
The Panels Method
External Axes Method
Note, as a general rule, it is recommended to not use the "External Axes Method" if what you are trying to accomplish can be done otherwise with mplfinance in panels mode.
I plot boxplots using sns.boxplot and pandas.DataFrame.boxplot in python 3.x.
And I want to ask is it possible to adjust the spacing between boxes in boxplot, so the box of Group_b is farther right to the box of Group_a than in the output figures. Thanks
Codes:
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns
dict_a = {'value':[1,2,3,7,8,9],'name':['Group_a']*3+['Group_b']*3}
dataframe = pd.DataFrame(dict_a)
sns.boxplot( y="value" , x="name" , data=dataframe )
Output figure:
dataframe.boxplot("value" ,by = "name" )
Output figure 2:
The distance between the two boxes is determined by the x axis limits. For a constant distance in data units between the boxes, what makes them spaced more or less appart is the fraction of this data unit distance compared to the overall data space shown on the axis.
For example, in the seaborn case, the first box sits at x=0, the second at x=1. The difference is 1 unit. The maximal distance between the two boxplots is hence achieved by setting the x axis limits to those exact limits,
ax.set_xlim(0, 1)
Of course this will cut half of each box.
So a more useful value would be ax.set_xlim(0-val, 1+val) with val being somewhere in the range of the width of the boxes.
One needs to mention that pandas uses different units. The first box is at x=1, the second at x=2. Hence one would need something like ax.set_xlim(1-val, 2+val).
The following would add a slider to the plot to see the effect of different values.
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
dict_a = {'value':[1,2,3,7,8,9],'name':['Group_a']*3+['Group_b']*3}
dataframe = pd.DataFrame(dict_a)
fig, (ax, ax2, ax3) = plt.subplots(nrows=3,
gridspec_kw=dict(height_ratios=[4,4,1], hspace=1))
sns.boxplot( y="value" , x="name" , data=dataframe, width=0.1, ax=ax)
dataframe.boxplot("value", by = "name", ax=ax2)
from matplotlib.widgets import Slider
slider = Slider(ax3, "", valmin=0, valmax=3)
def update(val):
ax.set_xlim(-val, 1+val)
ax2.set_xlim(1-val, 2+val)
slider.on_changed(update)
plt.show()