Plotly two bar charts overlaid - python

I have two bar plots, one is positive, other is negative. I want to overlay them with same x-axis in plotly. How can I do this? Here is a simple example of two bar plots:
import plotly.express as px
import pandas as pd
df1 = pd.DataFrame({'x1':[1,2,3], 'y1':[1,1,1], 'col':['A','A','B']})
df2 = pd.DataFrame({'x2':[1,2,3], 'y2':[-1,-1,-1], 'col':['A','A','B']})
fig1 = px.bar(df1, x="x1", y="y1", color="col")
fig2 = px.bar(df2, x="x2", y="y2", color="col")

If you rename your columns so that they have the same name (like 'x1' and 'y1') you can concatenate the dataframes. Plotly stacks them automatically:
df1 = pd.DataFrame({'x1':[1,2,3], 'y1':[1,1,1], 'col':['A','A','B']})
df2 = pd.DataFrame({'x1':[1,2,3], 'y1':[-1,-1,-1], 'col':['A','A','B']})
df = pd.concat((df1, df2))
px.bar(df, x='x1', y='y1', color='col')

Related

python plotly express mutiple layer graph (boxchart + scatter)

I want to create a multi layer graph with the same data frame from pandas.
One should be a boxplot and the other a scatter to see where the company is located.
Is there a way to combine both plots?
boxplot
scatterplot
import pandas as pd
import plotly.express as px
df = pd.read_csv("company_index.csv", sep=";", decimal=",")
print(df)
df_u9 = df.loc[df["company"].isin(["U9"])]
fig_1 = px.box(
df,
x="period",
y="index"
)
fig_2 = px.scatter(
df_u9,
x="period",
y="index"
)
fig_1.show()
fig_2.show()
company_index.csv
period;index;company
1;202,4;U1
1;226,69;U10
1;235,18;U9
1;236,49;U4
1;238,13;U2
1;244,05;U6
1;252,08;U3
1;256,68;U8
1;294,99;U5
1;299,391;U7
2;243,78;U1
2;264,26;U10
2;270,6;U2
2;272,89;U9
2;285,26;U5
2;289,29;U4
2;291,15;U6
2;291,19;U3
2;305,92;U7
2;314,65;U8
3;271,82;U1
3;278,65;U2
3;296,16;U10
3;297,21;U4
3;305,93;U6
3;308,96;U5
3;323,74;U9
3;335,93;U3
3;354,13;U8
3;381,2;U7
4;281,26;U5
4;308,5;U2
4;311,61;U1
4;334,03;U4
4;335,72;U9
4;344,32;U8
4;345,27;U6
4;355,44;U3
4;373,54;U7
4;381,68;U10
5;288,6;U1
5;305,66;U5
5;323,2;U2
5;358,46;U8
5;365,57;U3
5;366,96;U10
5;368,38;U7
5;371,23;U6
5;373,63;U4
5;422,93;U9
6;285,32;U5
6;291,65;U1
6;308,68;U2
6;372,04;U8
6;376,64;U3
6;403,55;U6
6;407,38;U4
6;420,65;U10
6;423,68;U9
6;453,09;U7
Found this solution. Works rather well.
Im still struggling to understand the ".data[0]" but i believe its referring to the first fig in use. Maybe if you have multiple graphs.
import pandas as pd
import plotly.express as px
df = pd.read_csv("company_index.csv", sep=";", decimal=",")
print(df)
df_u9 = df.loc[df["company"].isin(["U9"])].copy()
df_u9["size"] = 1
fig = px.box(
df,
x="period",
y="index"
)
fig.add_trace(px.scatter(
df_u9,
x="period",
y="index",
size="size",
size_max=15,
color_discrete_sequence=(203,153,201)
).data[0])
fig.show()

Plotly Distplot subplots

I am trying to write a for loop that for distplot subplots.
I have a dataframe with many columns of different lengths. (not including the NaN values)
fig = make_subplots(
rows=len(assets), cols=1,
y_title = 'Hourly Price Distribution')
i=1
for col in df_all.columns:
fig = ff.create_distplot([[df_all[[col]].dropna()]], col)
fig.append()
i+=1
fig.show()
I am trying to run a for loop for subplots for distplots and get the following error:
PlotlyError: Oops! Your data lists or ndarrays should be the same length.
UPDATE:
This is an example below:
df = pd.DataFrame({'2012': np.random.randn(20),
'2013': np.random.randn(20)+1})
df['2012'].iloc[0] = np.nan
fig = ff.create_distplot([df[c].dropna() for c in df.columns],
df.columns,show_hist=False,show_rug=False)
fig.show()
I would like to plot each distribution in a different subplot.
Thank you.
Update: Distribution plots
Calculating the correct values is probably both quicker and more elegant using numpy. But I often build parts of my graphs using one plotly approach(figure factory, plotly express) and then use them with other elements of the plotly library (plotly.graph_objects) to get what I want. The complete snippet below shows you how to do just that in order to build a go based subplot with elements from ff.create_distplot. I'd be happy to give further explanations if the following suggestion suits your needs.
Plot
Complete code
import numpy as np
import pandas as pd
import plotly.express as px
import plotly.figure_factory as ff
from plotly.subplots import make_subplots
import plotly.graph_objects as go
df = pd.DataFrame({'2012': np.random.randn(20),
'2013': np.random.randn(20)+1})
df['2012'].iloc[0] = np.nan
df = df.reset_index()
dfm = pd.melt(df, id_vars=['index'], value_vars=df.columns[1:])
dfm = dfm.dropna()
dfm.rename(columns={'variable':'year'}, inplace = True)
cols = dfm.year.unique()
nrows = len(cols)
fig = make_subplots(rows=nrows, cols=1)
for r, col in enumerate(cols, 1):
dfs = dfm[dfm['year']==col]
fx1 = ff.create_distplot([dfs['value'].values], ['distplot'],curve_type='kde')
fig.add_trace(go.Scatter(
x= fx1.data[1]['x'],
y =fx1.data[1]['y'],
), row = r, col = 1)
fig.show()
First suggestion
You should:
1. Restructure your data with pd.melt(df, id_vars=['index'], value_vars=df.columns[1:]),
2. and the use the occuring column 'variable' to build subplots for each year through the facet_row argument to get this:
In the complete snippet below you'll see that I've changed 'variable' to 'year' in order to make the plot more intuitive. There's one particularly convenient side-effect with this approach, namely that running dfm.dropna() will remove the na value for 2012 only. If you were to do the same thing on your original dataframe, the corresponding value in the same row for 2013 would also be removed.
import numpy as np
import pandas as pd
import plotly.express as px
df = pd.DataFrame({'2012': np.random.randn(20),
'2013': np.random.randn(20)+1})
df['2012'].iloc[0] = np.nan
df = df.reset_index()
dfm = pd.melt(df, id_vars=['index'], value_vars=df.columns[1:])
dfm = dfm.dropna()
dfm.rename(columns={'variable':'year'}, inplace = True)
fig = px.histogram(dfm, x="value",
facet_row = 'year')
fig.show()

create box plot of subcolumns of pandas dataframe

I have following pandas dataframe. I would like to create box (sub)plots of all the 5 columns (in one plot). How can I achieve this.
I am using following python statement but I am not getting the output.
df.boxplot(column=['synonym']['score'])
Here is an example of boxplot via plotly.express:
import plotly.express as px
df = pd.DataFrame(dict(x1=[1,2,3], x2=[4,8,12],x3=[1,5,10]))
df = df.melt(value_vars=['x1','x2','x3'])
fig = px.box(df, x='variable', y='value', color='variable')
fig.show()

Plotly: How to plot on secondary y-Axis with plotly express

How do I utilize plotly.express to plot multiple lines on two yaxis out of one Pandas dataframe?
I find this very useful to plot all columns containing a specific substring:
fig = px.line(df, y=df.filter(regex="Linear").columns, render_mode="webgl")
as I don't want to loop over all my filtered columns and use something like:
fig.add_trace(go.Scattergl(x=df["Time"], y=df["Linear-"]))
in each iteration.
It took me some time to fiddle this out, but I feel this could be useful to some people.
# import some stuff
import plotly.express as px
from plotly.subplots import make_subplots
import pandas as pd
import numpy as np
# create some data
df = pd.DataFrame()
n = 50
df["Time"] = np.arange(n)
df["Linear-"] = np.arange(n)+np.random.rand(n)
df["Linear+"] = np.arange(n)+np.random.rand(n)
df["Log-"] = np.arange(n)+np.random.rand(n)
df["Log+"] = np.arange(n)+np.random.rand(n)
df.set_index("Time", inplace=True)
subfig = make_subplots(specs=[[{"secondary_y": True}]])
# create two independent figures with px.line each containing data from multiple columns
fig = px.line(df, y=df.filter(regex="Linear").columns, render_mode="webgl",)
fig2 = px.line(df, y=df.filter(regex="Log").columns, render_mode="webgl",)
fig2.update_traces(yaxis="y2")
subfig.add_traces(fig.data + fig2.data)
subfig.layout.xaxis.title="Time"
subfig.layout.yaxis.title="Linear Y"
subfig.layout.yaxis2.type="log"
subfig.layout.yaxis2.title="Log Y"
# recoloring is necessary otherwise lines from fig und fig2 would share each color
# e.g. Linear-, Log- = blue; Linear+, Log+ = red... we don't want this
subfig.for_each_trace(lambda t: t.update(line=dict(color=t.marker.color)))
subfig.show()
The trick with
subfig.for_each_trace(lambda t: t.update(line=dict(color=t.marker.color)))
I got from nicolaskruchten here: https://stackoverflow.com/a/60031260
Thank you derflo and vestland! I really wanted to use Plotly Express as opposed to Graph Objects with dual axis to more easily handle DataFrames with lots of columns. I dropped this into a function. Data1/2 works well as a DataFrame or Series.
import plotly.express as px
from plotly.subplots import make_subplots
import pandas as pd
def plotly_dual_axis(data1,data2, title="", y1="", y2=""):
# Create subplot with secondary axis
subplot_fig = make_subplots(specs=[[{"secondary_y": True}]])
#Put Dataframe in fig1 and fig2
fig1 = px.line(data1)
fig2 = px.line(data2)
#Change the axis for fig2
fig2.update_traces(yaxis="y2")
#Add the figs to the subplot figure
subplot_fig.add_traces(fig1.data + fig2.data)
#FORMAT subplot figure
subplot_fig.update_layout(title=title, yaxis=dict(title=y1), yaxis2=dict(title=y2))
#RECOLOR so as not to have overlapping colors
subplot_fig.for_each_trace(lambda t: t.update(line=dict(color=t.marker.color)))
return subplot_fig

Changing the within-group order of a grouped bar plot in plotly

I'd like to change the order of my within-group variable in a plotly bar plot in Python.
For example, how can I switch the order of lunch and dinner here?
import plotly.express as px
df = px.data.tips()
fig = px.bar(df, x='sex', y='total_bill', color='time', barmode='group')
fig.show()
categoryorder can only change the order of groups, i.e. Male and Female.
Sort the df in descending order basis the column time.
import plotly.express as px
df = px.data.tips()
df.sort_values(['time'],ascending=[False],inplace=True)
fig = px.bar(df, x='sex', y='total_bill', color='time', barmode='group')
fig.show()
OUTPUT:

Categories

Resources