Return a graph based on a value from the dropdown - matplotlib

I am trying to plot a matplotlib graph after based on the value chosen from the dropdown. I have made the dropdown and the plots are also ready for the values but i dont know how to connect both of them together.
Following is the code of the dropdown:
app.layout = html.Div([
dcc.Dropdown(
id='first-dropdown',
options = [
{'label': 'Chest Pain', 'value': 'cp'},
{'label': 'Resting Blood Pressure', 'value': 'trestbps'},
{'label': 'Serum Cholestrol in mg/dl', 'value': 'chol'},
{'label': 'Fasting Blood Pressure', 'value': 'fbs'},
{'label': 'Resting electrocardiographic results', 'value': 'restecg'},
{'label': 'Maximum heart rate achieved', 'value': 'thalach'},
{'label': 'Exercise induced angina', 'value': 'exang'},
{'label': 'Old Peak', 'value': 'oldpeak'},
{'label': 'Slope of the peak exercise ST segment', 'value': 'slope'},
{'label': 'Number of major vessels (0-3) colored by flourosopy', 'value': 'ca'},
{'label': 'Thalassemia', 'value': 'thal'}
],
value= 'thalach'
)
])
and for each value in the dropdown i have a separate function which returns a plot. For eg:
What i am trying to do is that if the Label 'Max Heart Rate Achieved' is selected from the dropdown whose value is 'thalach'. I have a function called plotThalach which returns a plot like this:
def plotThalach(df):
df_men = df[df['sex'] == 1.0]
df_women = df[df['sex'] == 0.0]
plt.figure(figsize=(20, 8))
plt.bar(df_men['age'] + 0.00, df_men['thalach'], color='b', width=0.25, label='Men')
plt.bar(df_women['age'] + 0.25, df_women['thalach'], color='r', width=0.25, label='Women')
plt.legend(loc='upper right')
plt.xlabel("Age")
plt.ylabel("Max Heart Rate")
plt.title("Age vs Max Heart Rate")
return plt
Now how do i connect both of these in such a way that when a value is selected from the dropdown my function gets called and plot gets displayed on the screen.

It's not so clear why you want to mix plotly-dash and matplotlib, you can easily do it using just plotly-dash
Here is a sample code,
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import pandas as pd
import plotly.graph_objs as go
df = pd.read_csv(
'https://raw.githubusercontent.com/plotly/'
'datasets/master/gapminderDataFiveYear.csv')
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
#main div
app.layout = html.Div([
#drop down with a default value set
dcc.Dropdown(
id='xaxis-column',
options=[{'label': str(year), 'value': year} for year in df['year'].unique()],
value=df['year'].min(),
),
#graph that is to be updated
dcc.Graph(id='graph-with-slider')
])
#callback which will be spawned when the input changes, in this case the input is the dropdown value
#app.callback(
Output('graph-with-slider', 'figure'),
[Input('xaxis-column', 'value')])
def update_figure(selected_year):
filtered_df = df[df.year == selected_year]
traces = []
for i in filtered_df.continent.unique():
df_by_continent = filtered_df[filtered_df['continent'] == i]
traces.append(go.Scatter(
x=df_by_continent['gdpPercap'],
y=df_by_continent['lifeExp'],
text=df_by_continent['country'],
mode='markers',
opacity=0.7,
marker={
'size': 15,
'line': {'width': 0.5, 'color': 'white'}
},
name=i
))
return {
'data': traces,
'layout': go.Layout(
xaxis={'type': 'log', 'title': 'GDP Per Capita'},
yaxis={'title': 'Life Expectancy', 'range': [20, 90]},
margin={'l': 40, 'b': 40, 't': 10, 'r': 10},
legend={'x': 0, 'y': 1},
hovermode='closest'
)
}
if __name__ == '__main__':
app.run_server(debug=True)
But if you want to show the matplotlib graph instead of plotly-dash graph, you can refer the "Incorporating Matplotlib Plots" section here

Related

Default display of annotations in Plotly/Python using a button

I managed the possibility to switch on and off the annotations in a plotly chart. After the executing the code i would like to see the chart without annotations and if required, the annotations could be activated (Label: OFF).
The following code displays per default the annotations and i am not able to set it up, that the first display of chart will be show without annotations.
import plotly.express as px
import pandas as pd
# assign data of lists.
data = {'x': ["2022-05-06", "2022-05-08", "2022-05-09", "2022-05-12", "2022-05-15", "2022-05-16", "2022-05-22", "2022-05-24", "2022-05-26"],
'y': [0, 1, 8, 2, 4, 3, 4, 6, 5],
'text':["","","Annotation1","","Annotation2","","","","Annotation3"]}
# Create DataFrame
df = pd.DataFrame(data)
# assign data of lists.
data1 = {'x': ["2022-05-07", "2022-05-14", "2022-05-23"],
'text':["Annotation1", "Annotation2", "Annotation3"]}
df1 = pd.DataFrame(data1)
fig = px.line(df, x='x', y='y', title='Annotations ONN / OFF')
arrow_list=[]
counter=0
for i in df1['text'].tolist():
if i != "":
arrow=dict(x=df1['x'].values[counter],y=9,xref="x",yref="y",text=i,arrowhead = 2,ax=0,
arrowwidth=1.5,
bordercolor="#c7c7c7",
borderwidth=2,
borderpad=4,
bgcolor="#ff7f0e",
opacity=0.8,
font=dict(
family="Courier New, monospace",
size=16,
color="#ffffff"
),
arrowcolor='rgb(255,51,0)',)
arrow_list.append(arrow)
counter+=1
else:
counter+=1
fig.update_layout(
updatemenus=[
dict(
type="buttons",
# direction="right",
active=0,
showactive=True,
buttons=list([
dict(label="Label:Off",
method="update",
args=[{"visible": [True, False, True, False]},
{"annotations": []}]),
dict(label="Label:On",
method="update",
args=[{"visible": [True, True, True, True]},
{"annotations": arrow_list}]),
]),
)
])
fig.update_layout(annotations=arrow_list)
fig.show()
I have tried to modify args and active, but without any success.
The first display of the charts (annotations should be off):
I found the solution:
import plotly.graph_objects as go
import pandas as pd
# Load dataset
# assign data of lists.
data = {'Date': ["2022-05-06", "2022-05-08", "2022-05-09", "2022-05-12", "2022-05-15", "2022-05-16", "2022-05-22", "2022-05-24", "2022-05-26"],
'High': [0, 1, 8, 2, 4, 3, 4, 6, 5],
'text':["","","Annotation1","","Annotation2","","","","Annotation3"]}
# Create DataFrame
df = pd.DataFrame(data)
# Initialize figure
fig = go.Figure()
# Add Traces
fig.add_trace(
go.Scatter(x=list(df.Date),
y=list(df.High),
name="High",
line=dict(color="#33CFA5")))
arrow_list=[]
counter=0
for i in df1['text'].tolist():
if i != "":
arrow=dict(x=df1['x'].values[counter],y=9,xref="x",yref="y",text=i,arrowhead = 2,ax=0,
arrowwidth=1.5,
bordercolor="#c7c7c7",
borderwidth=2,
borderpad=4,
bgcolor="#ff7f0e",
opacity=0.8,
font=dict(
family="Courier New, monospace",
size=16,
color="#ffffff"
),
arrowcolor='rgb(255,51,0)',)
arrow_list.append(arrow)
counter+=1
else:
counter+=1
fig.update_layout(
updatemenus=[
dict(
active=0,
buttons=list([
dict(label="Label: Off",
method="update",
args=[{"visible": [True, False, True, False]},
{"title": "Labels Off",
"annotations": []}]),
dict(label="Label: On",
method="update",
args=[{"visible": [True, True, False, False]},
{"title": "Labels On",
"annotations": arrow_list}]),
]),
)
])
fig.show()

Connect points based on same value in matplotlib

Given this example:
df = pd.DataFrame({'a': ['foo', 'foo', 'bar', 'baz', 'baz', 'baz', 'foobar'], 'x': [3, 4, 1, 5, 5.5, 5.2, 8]})
How can I draw a line plot connecting the data points that have the same 'a', e.g. connect points 3 and 4 because 'foo' is the same, whereas the last data point, 8 is plotted as just a dot, by itself.
One way:
df.reset_index().pivot_table(index= 'index', columns= 'a', values = 'x').plot(marker = '*')
Alternative via seaborn:
import seaborn as sns
sns.lineplot(x = 'index', y = 'x' , hue = 'a', data = df.reset_index(), marker = '*')
OUTPUT:

bi-directional bar chart with annotation in python plotly

I have a pandas dataset with a toy version that can be created with this
#creating a toy pandas dataframe
s1 = pd.Series(['dont have a mortgage',-31.8,'have mortgage',15.65])
s2 = pd.Series(['have utility bill arrears',-21.45,'',0])
s3 = pd.Series(['have interest only mortgage',-19.59,'',0])
s4 = pd.Series(['bank with challenger bank',-19.24,'bank with a traditional bank',32.71])
df = pd.DataFrame([list(s1),list(s2),list(s3),list(s4)], columns = ['label1','value1','label2','value2'])
I want to create a bar chart that looks like this version I hacked together in excel
I want to be able to supply RGB values to customise the two colours for the left and right bars (currently blue and orange)
I tried different versions using “fig.add_trace(go.Bar” but am brand new to plotly and cant get anything to work with different coloured bars on one row with annotation under each bar.
All help greatly appreciated!
thanks
To create a double-sided bar chart, you can create two subplots with shared x- and y-axis. Each subplot is a horizontal bar chart with a specified marker color
import pandas as pd
import plotly.graph_objects as go
from plotly.subplots import make_subplots
# define data set
s1 = pd.Series(['dont have a mortgage',-31.8,'have mortgage',15.65])
s2 = pd.Series(['have utility bill arrears',-21.45,'',0])
s3 = pd.Series(['have interest only mortgage',-19.59,'',0])
s4 = pd.Series(['bank with challenger bank',-19.24,'bank with a traditional bank',32.71])
df = pd.DataFrame([list(s1),list(s2),list(s3),list(s4)], columns = ['label1','value1','label2','value2'])
# create subplots
fig = make_subplots(rows=1, cols=2, specs=[[{}, {}]], shared_xaxes=True,
shared_yaxes=True, horizontal_spacing=0)
fig.append_trace(go.Bar(y=df.index, x=df.value1, orientation='h', width=0.4, showlegend=False, marker_color='#4472c4'), 1, 1)
fig.append_trace(go.Bar(y=df.index, x=df.value2, orientation='h', width=0.4, showlegend=False, marker_color='#ed7d31'), 1, 2)
fig.update_yaxes(showticklabels=False) # hide all yticks
The annotations need to be added separately:
annotations = []
for i, row in df.iterrows():
if row.label1 != '':
annotations.append({
'xref': 'x1',
'yref': 'y1',
'y': i,
'x': row.value1,
'text': row.value1,
'xanchor': 'right',
'showarrow': False})
annotations.append({
'xref': 'x1',
'yref': 'y1',
'y': i-0.3,
'x': -1,
'text': row.label1,
'xanchor': 'right',
'showarrow': False})
if row.label2 != '':
annotations.append({
'xref': 'x2',
'yref': 'y2',
'y': i,
'x': row.value2,
'text': row.value2,
'xanchor': 'left',
'showarrow': False})
annotations.append({
'xref': 'x2',
'yref': 'y2',
'y': i-0.3,
'x': 1,
'text': row.label2,
'xanchor': 'left',
'showarrow': False})
fig.update_layout(annotations=annotations)
fig.show()

Python 3 matplotlit figure saved broken

I use the python 3 to make a figure, it displays very well, but when I save it, it is broken for the right half, as figures appended below. I am not sure what is wrong with it. The code I have is the following:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.ticker import rcParams, AutoMinorLocator
params = {'backend': 'ps',
'font.size': 30,
'font.style': 'normal',
'axes.labelsize': 30,
#'text.fontsize': 30,
'axes.linewidth': 2,
'legend.fontsize': 12,
'xtick.labelsize': 30,
'ytick.labelsize': 30,
'xtick.top': True,
'ytick.right': True,
#'xtick.major.top': True,
#'xtick.minor.top': True,
#'ytick.major.right': True,
#'ytick.minor.right': True,
'text.usetex': True,
'ps.usedistiller': 'xpdf'}
rcParams.update(params)
ion = [-2.0, -2.5, -3.0, -3.25, -3.5, -4.0, -4.5, -5.0, -5.5, -6.0]
cooling_mass = [0.036409, 0.035329, 0.042622, 0.069795, 0.090708, 0.107212, 0.109671, 0.110513, 0.107213, 0.109558]
fig, ax = plt.subplots(1, figsize=(8,6))
minor_locator1 = AutoMinorLocator(5)
ax.xaxis.set_minor_locator(minor_locator1)
minor_locator2 = AutoMinorLocator(5)
ax.yaxis.set_minor_locator(minor_locator2)
ax.tick_params('both', length=10, width=2, direction='in',which='major',pad=8)
ax.tick_params('both', length=5, width=2, direction='in',which='minor',pad=8)
ax.axhspan(0.036, 0.107, facecolor='lightskyblue', alpha=0.5)
ax.scatter(ion, cooling_mass, color='b', marker = 'o', s=50, zorder=2)
ax.set_ylim([0.008,0.14])
ax.set_yticks([0.03,0.06,0.09,0.12])
ax.set_xlim([-6.5,-1.5])
ax.set_xticks([-6.0,-4.0,-2.0])
ax.set_ylabel(r'$\rm Cooling ~Mass ~Rate ~[\rm M_\odot/yr]$', size=20, labelpad=5)
ax.set_xlabel(r'$\log {\rm U}$')
plt.gca().invert_xaxis()
plt.savefig('ion_cooling.eps',bbox_inches='tight')
plt.show()

Plotly not loading chart correctly where matplotlib does

When using plotly I do get this picture with some straight lines on the graph. I do not have the same when using matplotlib.
import pandas as pd
import numpy as np
import cufflinks as cf
from plotly.offline import plot
from datetime import datetime
import io
import requests
df = cf.datagen.lines()
src = "https://iss.moex.com/iss/engines/stock/markets/index/securities/RTSI/candles.csv?iss.only=history&interval=31&iss.reverse=true&from=1995-09-01&till=2019-12-28&iss.json=extended&callback=JSON_CALLBACK&lang=en&limit=100&start=0&sort_order=TRADEDATE&sort_order_desc=desc&_=1563185736134'"
r = requests.get(src)
df = pd.read_csv(io.StringIO(r.content.decode('utf-8')),
sep=';',
names=[
'Open', 'Close', 'High', 'Low', 'Value',
'Volume', 'Date', 'End'
]).iloc[2:]
frame = {
'Date': df['Date'].astype(np.datetime64),
'Open': df['Open'].astype('float64'),
'Close': df['Close'].astype('float64'),
'High': df['High'].astype('float64'),
'Low': df['Low'].astype('float64'),
'Value': df['Value'].astype('float64'),
'Volume': df['Volume'].astype('float64'),
}
df = pd.DataFrame(frame)
plot([{
'x': df['Date'],
'y': df[col],
'name': col
} for col in df.columns[1:]])
df.iplot()
Is this a bug with plotly or am I doinf something wrong?
The principal problem is that the date values don't appear in sorted order. It is necessary to sort them explicitly.
Another problem is that the numbers in the 'Value' column have a complete different range than the others. To display them in the same plot, one could add a secondary y-axis.
As the 'Volume' column isn't filled in (containing only zeros), it can be left out.
Here is some sample code, skipping conversion steps which probably are unnecessary for the latest plotly versions:
import plotly.graph_objects as go
import pandas as pd
src = "https://...."
df = pd.read_csv(src,
sep=';',
names=[
'Open', 'Close', 'High', 'Low', 'Value',
'Volume', 'Date', 'End'
]).iloc[2:]
df = df.sort_values(by='Date')
for col in df.columns:
print(col, df[col].min(), df[col].max())
fig = go.Figure()
for col in ['Open', 'Close', 'High', 'Low', 'Value']:
fig.add_trace(
go.Scatter(
x=df['Date'],
y=df[col],
name=col,
yaxis='y1' if col == 'Value' else 'y2'
))
fig.update_layout(
yaxis=dict(
title="Price",
),
yaxis2=dict(
title="Volume",
anchor="x",
overlaying="y",
side="right"
))
fig.show()
I see several small problems plus data is not sorted as stated by #JohanC. Then you should really use 2 yaxis as suggested by #JohanC Here is my full code with comments
import pandas as pd
import io
import requests
import plotly.graph_objects as go
# get Data
src = "https://iss.moex.com/iss/engines/stock/markets/index/securities/RTSI/candles.csv?iss.only=history&interval=31&iss.reverse=true&from=1995-09-01&till=2019-12-28&iss.json=extended&callback=JSON_CALLBACK&lang=en&limit=100&start=0&sort_order=TRADEDATE&sort_order_desc=desc&_=1563185736134'"
r = requests.get(src)
df = pd.read_csv(io.StringIO(r.content.decode('utf-8')),
sep=';',
names=[
'Open', 'Close', 'High', 'Low', 'Value',
'Volume', 'Date', 'End'
]).iloc[2:]
# set Date as first column and drop End
df = df.set_index('Date')\
.drop("End", axis=1)\
.reset_index()
# change dtypes
df["Date"] = df["Date"].astype("M8[us]")
for col in df.columns[1:]:
df[col] = df[col].astype(float)
# sort Date
df = df.sort_values("Date")\
.reset_index(drop=True)
fig = go.Figure()
for col in df.columns[1:]:
fig.add_trace(
go.Scatter(x=df["Date"],
y=df[col],
name=col))
fig.show()