I want use a for cycle to call a charting function and then represent the outcome chart into a section of a multi charting pageExample single chart
expected outcome
I have a charting function (see below Charting Function Section) that i recall in a the main script with a for cycle to get several charts in sequence. Now I would like to represent all the charts, in compact size (2 columns 4 rows) in one single page. In literature I find that Subplot allows me to do so but I struggle to find the right command to represent the outcome from the charting function.
I thought something like the below in the Main Section would work but it is not
---------- Main Section ---------
import pandas as pd
import numpy as np
import plotly.graph_objs as go
from sklearn.cluster import KMeans
from plotly.subplots import make_subplots
for cont in range(8):
fig = charting_func(cont)
fig_all.add_trace(fig,
row=1, col=1
) #row and col incrementing function to be defined
fig_all.update_layout(height=600, width=800, title_text="Side By Side Subplots")
fig_all.show()
----- Charting Function ------
def charting_func(n_chrt):
# Arbitrarily 10 colors for up to 10 clusters
#colors = ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet', 'purple','pink', 'silver']
# Create Scatter plot, assigning each point a color where
# point group = color index.
fig = btc.plot.scatter(
x=btc.index,
y="Adj Close",
color=[colors[i] for i in lists_clusters[n_chrt]],
title="k-values = {0}".format(n_chrt+2)
)
# Add horizontal lines
for cluster_avg in output[n_chrt][1:-1]:
fig.add_hline(y=cluster_avg, line_width=1, line_color="blue")
# Add a trace of the price for better clarity
fig.add_trace(go.Scatter(
x=btc.index,
y=btc['Adj Close'],
line_color="black",
line_width=1
))
# Make it pretty
layout = go.Layout(
plot_bgcolor='#D9D9D9',
showlegend=False,
# Font Families
font_family='Monospace',
font_color='#000000',
font_size=20,
xaxis=dict(
rangeslider=dict(
visible=False
))
)
fig.update_layout(layout)
return fig
type here
The basic form of a subplot is to add a location arrangement to the graph setup. So the functionalization needs to have matrix information or something like that. I have no data to present, so I have taken the stock prices of 4 companies and graphed them. As for the clustering by price, it is not included in the code, so the binning process is used to get the values and labels for the horizontal line. Please rewrite this part to your own logic. If you are good enough, the functionalization should work well.
import pandas as pd
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import itertools
import yfinance as yf
stock = ['TSLA','MSFT','AAPL','AMD']
#fig = go.Figure()
fig = make_subplots(rows=2, cols=2, subplot_titles=['MSFT','TSLA','AMD','AAPL'])
for s,rc in zip(stock, itertools.product([1,2],[2,1])):
#print(s, rc[0], rc[1])
df = yf.download(s, start="2017-09-01", end="2022-04-01", interval='1mo', progress=False)
colors = ['blue', 'red', 'green', 'purple', 'orange']
s_cut, bins = pd.cut(df['Adj Close'], 5, retbins=True, labels=colors)
fig.add_trace(go.Scatter(mode='markers+lines',
x=df.index,
y=df['Adj Close'],
marker=dict(
size=10,
color=s_cut.tolist()
)),
row=rc[0], col=rc[1]
)
for b in bins[1:-1]:
fig.add_hline(y=b, line_width=1, line_color="blue", row=rc[0], col=rc[1])
fig.update_layout(autosize=True, height=600, title_text="Side By Side Subplots")
fig.show()
Creating a parallel_categories with ploty express
import plotly.express as px
df = px.data.tips()
fig = px.parallel_categories(df)
fig.show()
gives a diagram with blue base color.
I would like to change the base color without using graph object. Just the overall color from blue to e.g. gray.
Assigning a color via a column is in my example not possible. Using color_continuous_scale also aims at a different color change.
Thanks for your input.
express
I have found that this can be achieved with plotly.express. Create a color list and specify a continuous color scale gray.
import plotly.express as px
import numpy as np
color = np.zeros(len(df), dtype='uint8')
df = px.data.tips()
fig = px.parallel_categories(df, color=color, color_continuous_scale='gray')
fig.update_layout(coloraxis_showscale=False)
fig.show()
Note:
Once again, there is a discrepancy in the output graph. The data specified for color is also added to the graph, which defeats the purpose of the express.
graph_objects
The same graph can be created by specifying each category using the graph object. So we are creating a list of numbers to give to the colors, either 0 or 1. Then we set the color scale to gray for both 0 and 1. This approach was inspired by the official reference.
import plotly.graph_objects as go
import plotly.express as px
import numpy as np
df = px.data.tips()
color = np.zeros(len(df), dtype='uint8')
colorscale = [[0, 'gray'],[1, 'gray']]
fig = go.Figure(go.Parcats(
dimensions=[
{'label': 'sex',
'values':df['sex'].tolist()},
{'label': 'smoker',
'values':df['smoker'].tolist()},
{'label': 'day',
'values':df['day'].tolist()},
{'label': 'time',
'values':df['time'].tolist()},
{'label': 'size',
'values':df['size'].tolist()}],
line={'colorscale':colorscale, 'cmin':0,'cmax':1,'color':color,'shape':'hspline'}
))
fig.show()
Original answer here is helpful but missed that there is a parameter in px.parallel_categories() for dimensions, and you can use that to only show what you want - that is, to not show the final column called color.
The below code is the same as the other answer except has the dimensions=[...] included (and also the df was defined out of order).
import plotly.express as px
import numpy as np
df = px.data.tips()
color = np.zeros(len(df), dtype="uint8")
fig = px.parallel_categories(
df,
dimensions=["sex", "smoker", "day", "time", "size"],
color=color,
color_continuous_scale="gray",
)
fig.update_layout(coloraxis_showscale=False)
fig.show()
I made a bar chart with python plotly, and I want to put a marker on a particular bar, example non-smoking females.
Does anyone know how to specify this?
I took an example from the plotly documentation, if I try to put the marker it just takes the center of the main category.
import plotly.express as px
df = px.data.tips()
fig = px.histogram(df, x="sex", y="total_bill",
color='smoker', barmode='group',
height=400)
#trying to set the marker
fig.add_trace(
go.Scatter(x=["Female"],
y=[1100]
))
fig.show()
inspired by this: https://community.plotly.com/t/grouped-bar-charts-with-corresponding-line-chart/19562/4
use xaxis2, work out position, have hardcoded it, but 0.15 has relationship to number of traces in bargoup and x value
import plotly.express as px
import plotly.graph_objects as go
import numpy as np
df = px.data.tips()
fig = px.histogram(
df, x="sex", y="total_bill", color="smoker", barmode="group", height=400
)
# trying to set the marker
fig.add_trace(
go.Scatter(
x=[0.15],
y=[1100],
customdata=[["No", "Female"]],
xaxis="x2",
hovertemplate="smoker=%{customdata[0]}<br>sex=%{customdata[1]}<br>sum of total_bill=%{y}<extra></extra>",
)
)
fig.update_layout(xaxis2={"overlaying": "x", "range": [0, 1], "showticklabels": False})
fig
I want to plot this data to evaluate data availability. I used the following plotting code in Plotly.
import datetime
import plotly.express as px
fig = px.bar(df, x=df.index, y="variable", color='value', orientation="h",
hover_data=[df.index],
height=350,
color_continuous_scale=['firebrick', '#2ca02c'],
title='',
template='plotly_white',
)
The result is just like what I want below.
But, the x-index show numbers. I want a timestamp (month+year) on the x-axis, instead.
Edit
Adding the fllowing
fig.update_layout(yaxis=dict(title=''),
xaxis=dict(
title='Timestamp',
tickformat = '%Y-%b',
)
)
Gives
which seems that the x-axis is not read from the data index.
If you want to use bars it seems to me that you need to find a nice workaround. Have you considered to use Heatmap?
import pandas as pd
import plotly.graph_objs as go
df = pd.read_csv("availability3.txt",
parse_dates=["Timestamp"])\
.drop("Unnamed: 0", axis=1)
# you want to have variable as columns
df = pd.pivot_table(df,
index="Timestamp",
columns="variable",
values="value")
fig = go.Figure()
fig.add_trace(
go.Heatmap(
z=df.values.T,
x=df.index,
y=df.columns,
colorscale='RdYlGn',
xgap=1,
ygap=2)
)
fig.show()
These resources show how to take data from a single Pandas DataFrame and plot different columns subplots on a Plotly graph. I'm interested in creating figures from separate DataFrames and plotting them to the same graph as subplots. Is this possible with Plotly?
https://plot.ly/python/subplots/
https://plot.ly/pandas/subplots/
I'm creating each figure from a dataframe like this:
import pandas as pd
import cufflinks as cf
from plotly.offline import download_plotlyjs, plot,iplot
cf.go_offline()
fig1 = df.iplot(kind='bar',barmode='stack',x='Type',
y=mylist,asFigure=True)
Edit:
Here is an example based on Naren's feedback:
Create the dataframes:
a={'catagory':['loc1','loc2','loc3'],'dogs':[1,5,6],'cats':[3,1,4],'birds':[4,12,2]}
df1 = pd.DataFrame(a)
b={'catagory':['loc1','loc2','loc3'],'dogs':[12,3,5],'cats':[4,6,1],'birds':[7,0,8]}
df2 = pd.DataFrame(b)
The plot will just show the information for the dogs, not the birds or cats:
fig = tls.make_subplots(rows=2, cols=1)
fig1 = df1.iplot(kind='bar',barmode='stack',x='catagory',
y=['dogs','cats','birds'],asFigure=True)
fig.append_trace(fig1['data'][0], 1, 1)
fig2 = df2.iplot(kind='bar',barmode='stack',x='catagory',
y=['dogs','cats','birds'],asFigure=True)
fig.append_trace(fig2['data'][0], 2, 1)
iplot(fig)
Here's a short function in a working example to save a list of figures all to a single HTML file.
def figures_to_html(figs, filename="dashboard.html"):
with open(filename, 'w') as dashboard:
dashboard.write("<html><head></head><body>" + "\n")
for fig in figs:
inner_html = fig.to_html().split('<body>')[1].split('</body>')[0]
dashboard.write(inner_html)
dashboard.write("</body></html>" + "\n")
# Example figures
import plotly.express as px
gapminder = px.data.gapminder().query("country=='Canada'")
fig1 = px.line(gapminder, x="year", y="lifeExp", title='Life expectancy in Canada')
gapminder = px.data.gapminder().query("continent=='Oceania'")
fig2 = px.line(gapminder, x="year", y="lifeExp", color='country')
gapminder = px.data.gapminder().query("continent != 'Asia'")
fig3 = px.line(gapminder, x="year", y="lifeExp", color="continent",
line_group="country", hover_name="country")
figures_to_html([fig1, fig2, fig3])
You can get a dashboard that contains several charts with legends next to each one:
import plotly
import plotly.offline as py
import plotly.graph_objs as go
fichier_html_graphs=open("DASHBOARD.html",'w')
fichier_html_graphs.write("<html><head></head><body>"+"\n")
i=0
while 1:
if i<=40:
i=i+1
#______________________________--Plotly--______________________________________
color1 = '#00bfff'
color2 = '#ff4000'
trace1 = go.Bar(
x = ['2017-09-25','2017-09-26','2017-09-27','2017-09-28','2017-09-29','2017-09-30','2017-10-01'],
y = [25,100,20,7,38,170,200],
name='Debit',
marker=dict(
color=color1
)
)
trace2 = go.Scatter(
x=['2017-09-25','2017-09-26','2017-09-27','2017-09-28','2017-09-29','2017-09-30','2017-10-01'],
y = [3,50,20,7,38,60,100],
name='Taux',
yaxis='y2'
)
data = [trace1, trace2]
layout = go.Layout(
title= ('Chart Number: '+str(i)),
titlefont=dict(
family='Courier New, monospace',
size=15,
color='#7f7f7f'
),
paper_bgcolor='rgba(0,0,0,0)',
plot_bgcolor='rgba(0,0,0,0)',
yaxis=dict(
title='Bandwidth Mbit/s',
titlefont=dict(
color=color1
),
tickfont=dict(
color=color1
)
),
yaxis2=dict(
title='Ratio %',
overlaying='y',
side='right',
titlefont=dict(
color=color2
),
tickfont=dict(
color=color2
)
)
)
fig = go.Figure(data=data, layout=layout)
plotly.offline.plot(fig, filename='Chart_'+str(i)+'.html',auto_open=False)
fichier_html_graphs.write(" <object data=\""+'Chart_'+str(i)+'.html'+"\" width=\"650\" height=\"500\"></object>"+"\n")
else:
break
fichier_html_graphs.write("</body></html>")
print("CHECK YOUR DASHBOARD.html In the current directory")
Result:
You can also try the following using cufflinks:
cf.subplots([df1.figure(kind='bar',categories='category'),
df2.figure(kind='bar',categories='category')],shape=(2,1)).iplot()
And this should give you:
New Answer:
We need to loop through each of the animals and append a new trace to generate what you need. This will give the desired output I am hoping.
import pandas as pd
import numpy as np
import cufflinks as cf
import plotly.tools as tls
from plotly.offline import download_plotlyjs, plot,iplot
cf.go_offline()
import random
def generate_random_color():
r = lambda: random.randint(0,255)
return '#%02X%02X%02X' % (r(),r(),r())
a={'catagory':['loc1','loc2','loc3'],'dogs':[1,5,6],'cats':[3,1,4],'birds':[4,12,2]}
df1 = pd.DataFrame(a)
b={'catagory':['loc1','loc2','loc3'],'dogs':[12,3,5],'cats':[4,6,1],'birds':[7,0,8]}
df2 = pd.DataFrame(b)
#shared Xaxis parameter can make this graph look even better
fig = tls.make_subplots(rows=2, cols=1)
for animal in ['dogs','cats','birds']:
animal_color = generate_random_color()
fig1 = df1.iplot(kind='bar',barmode='stack',x='catagory',
y=animal,asFigure=True,showlegend=False, color = animal_color)
fig.append_trace(fig1['data'][0], 1, 1)
fig2 = df2.iplot(kind='bar',barmode='stack',x='catagory',
y=animal,asFigure=True, showlegend=False, color = animal_color)
#if we do not use the below line there will be two legend
fig2['data'][0]['showlegend'] = False
fig.append_trace(fig2['data'][0], 2, 1)
#additional bonus
#use the below command to use the bar chart three mode
# [stack, overlay, group]
#as shown below
#fig['layout']['barmode'] = 'overlay'
iplot(fig)
Output:
Old Answer:
This will be the solution
Explanation:
Plotly tools has a subplot function to create subplots you should read the documentation for more details here. So I first use cufflinks to create a figure of the bar chart. One thing to note is cufflinks create and object with both data and layout. Plotly will only take one layout parameter as input, hence I take only the data parameter from the cufflinks figure and append_trace it to the make_suplots object. so fig.append_trace() the second parameter is row number and third parameter is column number
import pandas as pd
import cufflinks as cf
import numpy as np
import plotly.tools as tls
from plotly.offline import download_plotlyjs, plot,iplot
cf.go_offline()
fig = tls.make_subplots(rows=2, cols=1)
df = pd.DataFrame(np.random.randint(0,100,size=(100, 4)), columns=list('ABCD'))
fig1 = df.iplot(kind='bar',barmode='stack',x='A',
y='B',asFigure=True)
fig.append_trace(fig1['data'][0], 1, 1)
df2 = pd.DataFrame(np.random.randint(0,100,size=(100, 4)), columns=list('EFGH'))
fig2 = df2.iplot(kind='bar',barmode='stack',x='E',
y='F',asFigure=True)
fig.append_trace(fig2['data'][0], 2, 1)
iplot(fig)
If you want to add a common layout to the subplot I suggest that you do
fig.append_trace(fig2['data'][0], 2, 1)
fig['layout']['showlegend'] = False
iplot(fig)
or even
fig.append_trace(fig2['data'][0], 2, 1)
fig['layout'].update(fig1['layout'])
iplot(fig)
So in the first example before plotting, I access the individual parameters of the layout object and change them, you need to go through layout object properties for refernce.
In the second example before plotting, I update the layout of the figure with the cufflinks generated layout this will produce the same output as we see in cufflinks.
You've already received a few suggestions that work perfectly well. They do however require a lot of coding. Facet / trellis plots using px.bar() will let you produce the plot below using (almost) only this:
px.bar(df, x="category", y="dogs", facet_row="Source")
The only extra steps you'll have to take is to introduce a variable on which to split your data, and then gather or concatenate your dataframes like this:
df1['Source'] = 1
df2['Source'] = 2
df = pd.concat([df1, df2])
And if you'd like to include the other variables as well, just do:
fig = px.bar(df, x="category", y=["dogs", "cats", "birds"], facet_row="Source")
fig.update_layout(barmode = 'group')
Complete code:
# imports
import plotly.express as px
import pandas as pd
# data building
a={'category':['loc1','loc2','loc3'],'dogs':[1,5,6],'cats':[3,1,4],'birds':[4,12,2]}
df1 = pd.DataFrame(a)
b={'category':['loc1','loc2','loc3'],'dogs':[12,3,5],'cats':[4,6,1],'birds':[7,0,8]}
df2 = pd.DataFrame(b)
# data processing
df1['Source'] = 1
df2['Source'] = 2
df = pd.concat([df1, df2])
# plotly figure
fig = px.bar(df, x="category", y="dogs", facet_row="Source")
fig.show()
#fig = px.bar(df, x="category", y=["dogs", "cats", "birds"], facet_row="Source")
#fig.update_layout(barmode = 'group')