I have been trying to create a plotly figure (scatter plot) with a date slider and then exporting the figure to an HTML file.
To do so I have used the plotly px library: px.scatter(animation_frame...), just as in the second example here: https://plotly.com/python/sliders/.
Once I have the figure I save it to a HTML file with fig.to_html(full_html=False, include_plotlyjs='cdn').
This does work, but the problem I face is that the slider starts animating the frames by default whenever I open the html file. Is there a way to make the slider start static by default? I need it to start static because the figure has many frames and the slider automatically updating the frames makes the file really slow.
My code is:
figDVTO = px.scatter(dfPrueba, x="DíasVencimiento", y="Inflación", labels=dict(DíasVencimiento="Días al Vencimiento", Inflación="Inflación Implícita (%)"),
animation_frame="Fecha", title="Curva Inflación Implícita Diaria", range_y=[1, 8],
range_x=[0,7000], color = "Implícita", color_discrete_map = dicColores)
figDVTO.update_traces(marker=dict(size=12, line=dict(width=2,
color='DarkSlateGrey')),
selector=dict(mode='markers'))
I tried to set the "stop" animation button as default, but even when I do so, the slider animates the frames.
I also tried to construct the figure with plotly.graph_objects Figure, by constructing the dictionary that contains the frames.
I am able to recreate the figure I create with plotly express. However, after looking in plotly´s documentation I´m still no sure how to make the slider initially static. Have tried changing the method in updatemenus, as well as changing the method in sliders, but nothing seems to work.
I would really appreciate any sort of help, been scratching my head for weeks now...
Here is my complete code to construct the figure with plotly.graph_objects:
# make figure
fig_dict = {
"data": [],
"frames": [],
"layout": {'legend': {'title': {'text': 'Implícita'}, 'tracegroupgap': 0},
'sliders': [{
'active': 0,
'currentvalue': {'prefix': 'Fecha='},
'len': 0.9,
'pad': {'b': 10, 't': 60},
'steps':[],
'x': 0.1,
'xanchor': 'left',
'y': 0,
'yanchor': 'top'
}],
'title': {'text': 'Curva Inflación Implícita Diaria',
'font':dict(
family="Arial",
size=18,
)
},
'updatemenus': [{'active': 0,
'bgcolor': '#B0BEC5',
'buttons': [{'args': [None, {'frame': {'duration':
500, 'redraw': False},
'mode': 'immediate',
'fromcurrent': True,
'transition': {'duration':
500, 'easing': 'linear'}}],
'label': '▶',
'method': 'animate'},
{'args': [[None], {'frame':
{'duration': 0, 'redraw':
False}, 'mode': 'immediate',
'fromcurrent': True,
'transition': {'duration': 0,
'easing': 'linear'}}],
'label': '◼',
'method': 'animate'}],
'direction': 'left',
'pad': {'r': 10, 't': 70},
'showactive': True,
'type': 'buttons',
'x': 0.1,
'xanchor': 'right',
'y': 0,
'yanchor': 'top'}],
'xaxis': {'anchor': 'y',
'domain': [0.0, 1.0],
'range': [0, 7000],
'title': {'text': 'Días al Vencimiento'}},
'yaxis': {'anchor': 'x',
'domain': [0.0, 1.0],
'range': [1, 8],
'title': {'text': 'Inflación Implícita (%)'}}
}
}
#Creating starting frame
listFechas = list(dfPrueba['Fecha'].unique())
listImplicitas = list(dfPrueba['Implícita'].unique())
fecha=listFechas[0]
for implicita in listImplicitas:
data_dict = {
"x": np.array(dfPrueba.loc[(dfPrueba['Fecha']==fecha)&(dfPrueba['Implícita']==implicita), 'DíasVencimiento']),
"y": np.array(dfPrueba.loc[(dfPrueba['Fecha']==fecha)&(dfPrueba['Implícita']==implicita), 'Inflación']),
'legendgroup': str(implicita),
'hovertemplate': ('Implícita='+ str(implicita)+'<br>Fecha='+str(fecha)+'<br>Días al Vencimiento=%{x}<br>Inflación Implícita (%)=%{y}<extra></extra>'),
'marker': {'color': dicColores[implicita], 'line': {'color': 'DarkSlateGrey', 'width': 2}, 'size': 12, 'symbol': 'circle'},
"mode": "markers",
'marker': {'color': dicColores[implicita], 'line': {'color': 'DarkSlateGrey', 'width': 2}, 'size': 12, 'symbol': 'circle'},
"name": str(implicita),
'orientation': 'v',
'showlegend': True,
'type': 'scatter',
'xaxis': 'x',
'yaxis': 'y',
}
fig_dict["data"].append(data_dict)
# make frames
for fecha in listFechas:
frame = {"data": [], "name": str(fecha)}
for implicita in listImplicitas:
data_dict = {
"x": np.array(dfPrueba.loc[(dfPrueba['Fecha']==fecha)&(dfPrueba['Implícita']==implicita), 'DíasVencimiento']),
"y": np.array(dfPrueba.loc[(dfPrueba['Fecha']==fecha)&(dfPrueba['Implícita']==implicita), 'Inflación']),
'legendgroup': str(implicita),
'hovertemplate': ('Implícita='+ str(implicita)+'<br>Fecha='+str(fecha)+'<br>Días al Vencimiento=%{x}<br>Inflación Implícita (%)=%{y}<extra></extra>'),
'marker': {'color': dicColores[implicita], 'line': {'color': 'DarkSlateGrey', 'width': 2}, 'size': 12, 'symbol': 'circle'},
"mode": "markers",
'marker': {'color': dicColores[implicita], 'line': {'color': 'DarkSlateGrey', 'width': 2}, 'size': 12, 'symbol': 'circle'},
"name": str(implicita),
'orientation': 'v',
'legendgroup': '23',
'showlegend': True,
'type': 'scatter',
'xaxis': 'x',
'yaxis': 'y'
}
frame["data"].append(data_dict)
fig_dict["frames"].append(frame)
#Updating sliders steps
for fecha in listFechas:
loop_dic={'args': [[str(fecha)], {'frame':
{'duration': 0, 'redraw': False},
'mode': 'immediate', 'fromcurrent':
True, 'transition': {'duration': 0,
'easing': 'linear'}}],
'label': str(fecha),
'method': 'animate'}
fig_dict["layout"]["sliders"][0]["steps"].append(loop_dic)
#Creating figure
figB = go.Figure(fig_dict)
figB.update_layout(
title="Curva Inflación Implícita Diaria",
xaxis_title="Días al Vencimiento",
yaxis_title="Inflación Implícita (%)",
legend_title="Serie",
font=dict(
family="Arial",
size=18,
),
hovermode="x",
yaxis=dict(tickformat=".2f")
)
Related
I am new to plotly dash. I am trying to create an interactive dashboard where I can filter the colorbar to see the upper values for example if the value is 3000 it was red, so if I type 3000 as input, it is still red but the graph will not show values less than 3000. I am able to add the filtering option but when I filter(I used zmin in go heatmap) the colorscale also changes. Can I keep the previous colorscale so that if I choose zmin, it refreshes the graph with the original colorscale but filters values greater than zmin? Here is the code I have written so far -
app.layout = html.Div(children=[
html.H1(children='Title'),
dcc.Graph(
id='graph',
figure=fig
),
dcc.Input(
id="input", type="number", value=0
)
])
#app.callback(
Output('graph', 'figure'),
Input('input', 'value')
)
def update_figure(input):
frames = []
for d, i in enumerate(sorted(timestamp_list)):
frames.append(
go.Frame(
name=time.strftime("%a, %d %b %Y %H:%M:%S", time.localtime(int(i) / 1000)),
data=[
go.Heatmap(z=df_dict[i],
x=df_dict[i].columns,
y=df_dict[i].index,
zmin=input,
zmax=max(value_list))
]
)
)
yaxis_name = kind.split("_")[0]
xaxis_name = kind.split("_")[1]
fig = go.Figure(
data=frames[0].data,
frames=frames,
layout=go.Layout(
autosize=True,
height=800,
yaxis={"title": yaxis_name, "dtick": 1},
xaxis={"title": xaxis_name, "tickangle": 45, "side": 'top'},
),
)
# finally, create the slider
fig.update_layout(
updatemenus=[{
'buttons': [
{
'args': [None, {'frame': {'duration': 500, 'redraw': True},
'transition': {'duration': 500, 'easing': 'quadratic-in-out'}}],
'label': 'Play',
'method': 'animate'
},
{
'args': [[None], {'frame': {'duration': 0, 'redraw': False},
'mode': 'immediate',
'transition': {'duration': 0}}],
'label': 'Pause',
'method': 'animate'
}
],
'direction': 'left',
'pad': {'r': 10, 't': 100},
'showactive': False,
'type': 'buttons',
'x': 0.1,
'xanchor': 'right',
'y': 0,
'yanchor': 'top'
}],
sliders=[{"steps": [{"args": [[f.name], {"frame": {"duration": 0, "redraw": True},
"mode": "immediate", }, ],
"label": f.name, "method": "animate", }
for f in frames],
}]
)
return fig
Here is the sample output I get-[![enter image description here][1]][1]
After filtering- [![enter image description here][2]][2]
I am not completely sure I understood what you mean, but isn't it enough to just filter your data? I also don't have an example of how you data look like, but why don't you try filtering your data frame before you plot?
data_to_plot = frames[frames['your_column'] > zmin]
I am trying to create a spreadsheet plot with a line and two scatter charts. I am trying to have different symbols for each scatter chart:
# create the chart and add it to the workbook:
value_line_chart = workbook.add_chart({'type': 'line'})
value_line_chart.set_y_axis({'name': 'Values'})
value_line_chart.set_x_axis({'name': 'Time'})
value_line_chart.set_title({'name': 'Chart of {}'.format(historical_data.symbol)})
value_line_chart.add_series({
'line': {
'color': 'cyan',
'width': .5
},
'values': [worksheet.name, data_start_row, value_col, last_col, value_col],
'categories': [worksheet.name, data_start_row, date_col, last_col, date_col],
'name': "data",
})
scatter_buy_chart = workbook.add_chart({'type': 'scatter'})
scatter_buy_chart.add_series({
'marker': {
'type': 'long_dash',
'size': 5,
'border': {'color': 'red'},
'fill': {'color': 'red'},
},
'values': [worksheet.name, data_start_row, buy_action_col, last_col, buy_action_col],
'categories': [worksheet.name, data_start_row, date_col, last_col, date_col],
'name': "buy",
})
value_line_chart.combine(scatter_buy_chart)
scatter_sell_chart = workbook.add_chart({'type': 'scatter'})
scatter_sell_chart.add_series({
'marker': {
'type': 'plus',
'size': 5,
'border': {'color': 'green'},
'fill': {'color': 'green'},
},
'values': [worksheet.name, data_start_row, sell_action_col, last_col, sell_action_col],
'categories': [worksheet.name, data_start_row, date_col, last_col, date_col],
'name': "buy",
})
value_line_chart.combine(scatter_sell_chart)
value_line_chart.set_size({'width': 720, 'height': 576})
value_line_chart.set_x_axis({
'date_axis': True,
'min': date_data[0],
'max': date_data[len(date_data)-1]
})
value_line_chart.set_legend({'none': True})
worksheet.insert_chart('B1', value_line_chart)
workbook.close()
The problems that I am having are:
I am unable to get the second scatter chart to show up
I am unable to get the colors of the symbols to change
I have tried rendering the line and scatter charts individually and the the data and symbol shapes show up correctly.
I am able to change the color of the line chart.
I am able to change the shape of the symbols.
I am able to render the line chart and only one of the two scatter charts.
I was able to get the results I was looking for by adding all of the series into the single chart:
# create the chart and add it to the workbook:
chart = workbook.add_chart({'type': 'line'})
chart.set_y_axis({'name': 'Values'})
chart.set_x_axis({'name': 'Time'})
chart.set_title({'name': 'Chart of {}'.format(historical_data.symbol)})
chart.add_series({
'line': {
'color': 'cyan',
'width': .5
},
'values': [worksheet.name, data_start_row, value_col, last_col, value_col],
'categories': [worksheet.name, data_start_row, date_col, last_col, date_col],
'name': "data",
})
chart.add_series({
'marker': {
'type': 'long_dash',
'size': 8,
'border': {'color': 'red'},
'fill': {'color': 'red'},
},
'values': [worksheet.name, data_start_row, buy_action_col, last_col, buy_action_col],
'categories': [worksheet.name, data_start_row, date_col, last_col, date_col],
'name': "buy",
})
chart.add_series({
'marker': {
'type': 'plus',
'size': 8,
'border': {'color': 'green'},
'fill': {'color': 'green'},
},
'values': [worksheet.name, data_start_row, sell_action_col, last_col, sell_action_col],
'categories': [worksheet.name, data_start_row, date_col, last_col, date_col],
'name': "buy",
})
chart.set_size({'width': 720, 'height': 576})
chart.set_x_axis({
'date_axis': True,
'min': date_data[0],
'max': date_data[len(date_data)-1]
})
chart.set_legend({'none': True})
worksheet.insert_chart('B1', chart)
workbook.close()
It isn’t possible to combine more than 2 charts with XlsxWriter. That is a limitation of the library.
I am going through the the slider animation plot tutorial from plotly (https://plot.ly/python/animations/), the one at the bottom, with my own data. My scenario is basically is data gathered from users from an application. I have data for one month (May), which the frequency of users are recorded hourly for each day. I want to use a slider to have a range of values from day 1 to 31 and the plot to show the unique values of each hour for each specific day.
My problem: I only get day one, but the value of the slider is updating correctly. Fixed old problem, now I have another one: Now instead of 1 step of the data, the graph is showing every single step.
My code:
# dMay to DataFrame
dfMay = pd.DataFrame({key :dMay[key] for key in list(dMay.keys())})
for i, df in enumerate([dfMay], 1):
df.columns = [str(col_name)[6:].format(i) for col_name in df.columns]
keys = list(map(lambda x: str(x), dfMay.keys())) # Slider values - days
from plotly.grid_objs import Grid, Column
listOfCols = []
for col in keys:
listOfCols.append(Column(dfMay[col], col))
grid = Grid(listOfCols)
py.grid_ops.upload(grid, 'Testing'+str(time.time()), auto_open=False)
# Animated Plot
figure = {
'data': [],
'layout': {},
'frames': []
}
# fill in most of layout
figure['layout']['xaxis'] = {'range': [0, 23], 'title': 'Zaman (saat)'}
figure['layout']['yaxis'] = {'title': 'Kullanıcı Sayısı', 'type': 'linear'}
figure['layout']['hovermode'] = 'closest'
figure['layout']['sliders'] = {
'args': [
'transition', {
'duration': 400,
'easing': 'cubic-in-out'
}
],
'initialValue': '0',
'plotlycommand': 'animate',
'values': list(range(24)),
'visible': True
}
figure['layout']['updatemenus'] = [
{
'buttons': [
{
'args': [None, {'frame': {'duration': 500, 'redraw': True},
'fromcurrent': True, 'transition': {'duration': 300, 'easing': 'quadratic-in-out'}}],
'label': 'Play',
'method': 'animate'
},
{
'args': [[None], {'frame': {'duration': 0, 'redraw': True}, 'mode': 'immediate',
'transition': {'duration': 0}}],
'label': 'Pause',
'method': 'animate'
}
],
'direction': 'left',
'pad': {'r': 10, 't': 87},
'showactive': False,
'type': 'buttons',
'x': 0.1,
'xanchor': 'right',
'y': 0,
'yanchor': 'top'
}
]
sliders_dict = {
'active': 0,
'yanchor': 'top',
'xanchor': 'left',
'currentvalue': {
'font': {'size': 20},
'prefix': 'Zaman:',
'visible': True,
'xanchor': 'right'
},
'transition': {'duration': 300, 'easing': 'cubic-in-out'},
'pad': {'b': 10, 't': 50},
'len': 0.9,
'x': 0.1,
'y': 0,
'steps': []
}
# make data
start = 0
for day in keys:
data_dict = {
'x': list(range(24)),
'y': list(dfMay[day]),
'mode': 'markers',
'marker': {
'sizemode': 'area',
'sizeref': 200000,
'size': 20
},
'name': day
}
figure['data'].append(data_dict)
# make frames
for day in keys:
frame = {'data': [], 'name': str(day)}
data_dict = {
'x': list(range(24)),
'y': list(dfMay[day]),
'mode': 'markers',
'text': list(dfMay[day]),
'marker': {
'sizemode': 'area',
'sizeref': 200000,
'size': 20
},
'name': day,
}
frame['data'].append(data_dict)
figure['frames'].append(frame)
slider_step = {'args': [
[day],
{'frame': {'duration': 1000, 'redraw': True},
'mode': 'immediate',
'transition': {'duration': 1000}}
],
'label': day,
'method': 'animate'}
sliders_dict['steps'].append(slider_step)
figure['layout']['sliders'] = [sliders_dict]
print('Done')
plot(figure)
I also can,t get rid of the colored markers on the right!
EDIT 1: Added dfMay Table
EDIT 2: Changed problem, added a new plot
Images to Supplement:
Fixes slider related issue. I followed another plotly tutorial. https://plot.ly/~empet/14896
plotData=[dict(type='scatter',
x=list(range(24)),
y=test_data[:0],
mode='markers',
marker=dict(size=10, color='red')
)
]
frames=[dict(data=[dict(y=test_data[:,k])],
traces=[0],
name=f'{k+1}',
layout=dict(yaxis=dict(range=[-1, test_data[:, k].max()+100]))) for k in range(31)]
sliders=[dict(steps= [dict(method= 'animate',
args= [[ f'{k+1}'],
dict(mode= 'e',
frame= dict( duration=1000, redraw= False ),
transition=dict( duration= 0)
)
],
label=f' {k+1}'
) for k in range(31)],
transition= dict(duration= 30 ),
x=0,#slider starting position
y=0,
currentvalue=dict(font=dict(size=12),
prefix='Day: ',
visible=True,
xanchor= 'center'
),
len=1.0,
active=1) #slider length)
]
axis_style=dict(showline=True,
mirror=True,
zeroline=False,
ticklen=4)
layout=dict(title='Mayıs-Günlük Kullanıcı Sayıları',
width=900,
height=600,
autosize=False,
xaxis=dict(axis_style, dtick=1, tit='s' title='Zaman (saat)', **dict(range=[0,24])),
yaxis=dict(axis_style, title='Kullanıcı Sayısı',autorange=False),
#plot_bgcolor="rgba(66,134,244, 0.2)",
shapes= [dict(
# Sabah
type= 'rect',
xref= 'x',
yref= 'paper',
x0= '0',
y0= 0,
x1= '8',
y1= 1,
fillcolor= 'rgba(66, 134, 244, 0.5)',
opacity= 0.2,
line= dict(width= 0)
),
# Oglen
dict(
type= 'rect',
xref= 'x',
yref= 'paper',
x0= '8',
y0= 0,
x1= '16',
y1= 1,
fillcolor= '#rgba(255, 252, 117,1)',
opacity= 0.2,
line= dict(width=0)
),
# Aksam
dict(
type= 'rect',
xref= 'x',
yref= 'paper',
x0= '16',
y0= 0,
x1= '24',
y1= 1,
fillcolor= 'rgba(2, 0, 168, 1)',
opacity= 0.2,
line= dict(width=0)
)
],
hovermode='closest',
updatemenus=[dict(type='buttons', showactive=True,
y=0,
x=1.15,
xanchor='right',
yanchor='top',
pad=dict(t=0, r=10),
buttons=[dict(label='Play',
method='animate',
args=[None,
dict(frame=dict(duration=4000,
redraw=True),
transition=dict(duration=4000),
fromcurrent=True,
mode='immediadate'
)
]
),
dict(label='Pause',
method='animate',
args=[[None],
dict(frame=dict(duration=0,
redraw=False),
transition=dict(duration=30),
fromcurrent=True,
mode='immediate'
)
]
)
]
)
],
sliders=sliders
)
# Animated Plot
figure = {
'data': plotData,
'layout': layout,
'frames': frames
}
fig=dict(data=plotData, frames=frames, layout=layout)
fig['data'][0].update(mode='markers+lines',
line=dict(width=1.5, color='blue'))
plot(fig, auto_open=False)
Displaying one slice of a numpy 3D array in Plotly is easy, just use a Heatmap:
import plotly.offline as offline
import plotly.graph_objs as go
import numpy as np
trace = go.Heatmap(z=3D_array[10,:,:]) # just one slice (10) along x axis
fig = dict(data=[trace])
offline.plot(fig, filename='heatmap.html')
What I want is to have a slider to see any slice. Using a few examples over the web I came up with this:
figure = {
'data': [],
'layout': {},
'frames': [],
}
sliders_dict = {
'active': 0,
'yanchor': 'top',
'xanchor': 'left',
'currentvalue': {
'font': {'size': 20},
'prefix': 'Year:',
'visible': True,
'xanchor': 'right'
},
'transition': {'duration': 300, 'easing': 'cubic-in-out'},
'pad': {'b': 10, 't': 50},
'len': 0.9,
'x': 0.1,
'y': 0,
'steps': []
}
frame = {'data': []}
for i in range(A.shape[0]):
frame['data'].append(A[i, :, :])
figure['frames'].append(frame)
slider_step = {'args': [
[i],
{'frame': {'duration': 300, 'redraw': False},
'mode': 'immediate',
'transition': {'duration': 300}}
],
'label': i,
'method': 'animate'}
sliders_dict['steps'].append(slider_step)
figure['layout']['sliders'] = [sliders_dict]
figure['data'] = [go.Heatmap(z=A[10,:,:])]
print(figure.keys())
offline.plot(figure, filename='heatmap.html')
I can't get it to work. I feel like there is a problem with passing data for consecutive frames.
Any tips on how to proceed?
I have this chart, created using python package xlsxwriter and I wanna remove all the points in the middle and only keep the first one and last one.
before :
Final results wanted.:
I tried the attribute points but unfortunate, it didn't work for me.
line_chart.add_series(
{
'values': '='+worksheet_name+'!$C$'+str(row_range+1)+':$I'+str(row_range+1),
'marker': {'type': 'diamond'},
'data_labels': {'value': True, 'category': True, 'position': 'center', 'leader_lines': True},
'points': [
{'fill': {'color': 'green'}},
None,
None,
None,
None,
None,
{'fill': {'color': 'red'}}
],
'trendline': {
'type': 'polynomial',
'name': 'My trend name',
'order': 2,
'forward': 0.5,
'backward': 0.5,
'line': {
'color': 'red',
'width': 1,
'dash_type': 'long_dash'
}
}
}
)
I also tried:
line_chart.set_x_axis({
'major_gridlines': {'visible': False},
'minor_gridlines': {'visible': False}
'delete_series': [1, 6]
})
no luck.
Anobody can help me please?
Thanks in advance!