i am currently working with plotly i have a function called plotChart that takes a dataframe as input and plots a candlestick chart. I am trying to figure out a way to pass a list of dataframes to the function plotChart and use a plotly dropdown menu to show the options on the input list by the stock name. The drop down menu will have the list of dataframe and when an option is clicked on it will update the figure in plotly is there away to do this. below is the code i have to plot a single dataframe
def make_multi_plot(df):
fig = make_subplots(rows=2, cols=2,
shared_xaxes=True,
vertical_spacing=0.03,
subplot_titles=('OHLC', 'Volume Profile'),
row_width=[0.2, 0.7])
for s in df.name.unique():
trace1 = go.Candlestick(
x=df.loc[df.name.isin([s])].time,
open=df.loc[df.name.isin([s])].open,
high=df.loc[df.name.isin([s])].high,
low=df.loc[df.name.isin([s])].low,
close=df.loc[df.name.isin([s])].close,
name = s)
fig.append_trace(trace1,1,1)
fig.append_trace(go.Scatter(x=df.loc[df.name.isin([s])].time, y=df.loc[df.name.isin([s])].BbandsMid, mode='lines',name='MidBollinger'),1,1)
fig.append_trace(go.Scatter(x=df.loc[df.name.isin([s])].time, y=df.loc[df.name.isin([s])].BbandsUpp, mode='lines',name='UpperBollinger'),1,1)
fig.append_trace(go.Scatter(x=df.loc[df.name.isin([s])].time, y=df.loc[df.name.isin([s])].BbandsLow, mode='lines',name='LowerBollinger'),1,1)
fig.append_trace(go.Scatter(x=df.loc[df.name.isin([s])].time, y=df.loc[df.name.isin([s])].vwap, mode='lines',name='VWAP'),1,1)
fig.append_trace(go.Scatter(x=df.loc[df.name.isin([s])].time, y=df.loc[df.name.isin([s])].STDEV_1, mode='lines',name='UPPERVWAP'),1,1)
fig.append_trace(go.Scatter(x=df.loc[df.name.isin([s])].time, y=df.loc[df.name.isin([s])].STDEV_N1, mode='lines',name='LOWERVWAP'),1,1)
fig.append_trace(go.Scatter(x=df.loc[df.name.isin([s])].time, y=df.loc[df.name.isin([s])].KcMid, mode='lines',name='KcMid'),1,1)
fig.append_trace(go.Scatter(x=df.loc[df.name.isin([s])].time, y=df.loc[df.name.isin([s])].KcUpper, mode='lines',name='KcUpper'),1,1)
fig.append_trace(go.Scatter(x=df.loc[df.name.isin([s])].time, y=df.loc[df.name.isin([s])].KcLow, mode='lines',name='KcLow'),1,1)
trace2 = go.Bar(
x=df.loc[df.name.isin([s])].time,
y=df.loc[df.name.isin([s])].volume,
name = s)
fig.append_trace(trace2,2,1)
# fig.update_layout(title_text=s)
graph_cnt=len(fig.data)
tr = 11
symbol_cnt =len(df.name.unique())
for g in range(tr, graph_cnt):
fig.update_traces(visible=False, selector=g)
#print(g)
def create_layout_button(k, symbol):
start, end = tr*k, tr*k+2
visibility = [False]*tr*symbol_cnt
visibility[start:end] = [True,True,True,True,True,True,True,True,True,True,True]
return dict(label = symbol,
method = 'restyle',
args = [{'visible': visibility[:-1],
'title': symbol,
'showlegend': False}])
fig.update(layout_xaxis_rangeslider_visible=False)
fig.update_layout(
updatemenus=[go.layout.Updatemenu(
active = 0,
buttons = [create_layout_button(k, s) for k, s in enumerate(df.name.unique())]
)
])
fig.show()
i am trying to add annotations to the figure it will be different for each chart below is how i had it setup for the single chart df['superTrend'] is a Boolean column
for i in range(df.first_valid_index()+1,len(df.index)):
prev = i - 1
if df['superTrend'][i] != df['superTrend'][prev] and not np.isnan(df['superTrend'][i]) :
#print(i,df['inUptrend'][i])
fig.add_annotation(x=df['time'][i], y=df['open'][i],
text= 'Buy' if df['superTrend'][i] else 'Sell',
showarrow=True,
arrowhead=6,
font=dict(
#family="Courier New, monospace",
size=20,
#color="#ffffff"
),)
I adapted an example from the plotly community to your example and created the code. The point of creation is to create the data for each subplot and then switch between them by means of buttons. The sample data is created using representative companies of US stocks. one issue is that the title is set but not displayed. We are currently investigating this issue.
import yfinance as yf
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import pandas as pd
symbols = ['AAPL','GOOG','TSLA']
stocks = pd.DataFrame()
for s in symbols:
data = yf.download(s, start="2021-01-01", end="2021-12-31")
data['mean'] = data['Close'].rolling(20).mean()
data['std'] = data['Close'].rolling(20).std()
data['upperBand'] = data['mean'] + (data['std'] * 2)
data.reset_index(inplace=True)
data['symbol'] = s
stocks = stocks.append(data, ignore_index=True)
def make_multi_plot(df):
fig = make_subplots(rows=2, cols=1,
shared_xaxes=True,
vertical_spacing=0.03,
subplot_titles=('OHLC', 'Volume Profile'),
row_width=[0.2, 0.7])
for s in df.symbol.unique():
trace1 = go.Candlestick(
x=df.loc[df.symbol.isin([s])].Date,
open=df.loc[df.symbol.isin([s])].Open,
high=df.loc[df.symbol.isin([s])].High,
low=df.loc[df.symbol.isin([s])].Low,
close=df.loc[df.symbol.isin([s])].Close,
name=s)
fig.append_trace(trace1,1,1)
trace2 = go.Scatter(
x=df.loc[df.symbol.isin([s])].Date,
y=df.loc[df.symbol.isin([s])].upperBand,
name=s)
fig.append_trace(trace2,1,1)
trace3 = go.Bar(
x=df.loc[df.symbol.isin([s])].Date,
y=df.loc[df.symbol.isin([s])].Volume,
name=s)
fig.append_trace(trace3,2,1)
# fig.update_layout(title_text=s)
# Calculate the total number of graphs
graph_cnt=len(fig.data)
# Number of Symbols
symbol_cnt =len(df.symbol.unique())
# Number of graphs per symbol
tr = 3
# Hide setting for initial display
for g in range(tr, graph_cnt):
fig.update_traces(visible=False, selector=g)
def create_layout_button(k, symbol):
start, end = tr*k, tr*k+2
visibility = [False]*tr*symbol_cnt
# Number of graphs per symbol, so if you add a graph, add True.
visibility[start:end] = [True,True,True]
return dict(label = symbol,
method = 'restyle',
args = [{'visible': visibility[:-1],
'title': symbol,
'showlegend': True}])
fig.update(layout_xaxis_rangeslider_visible=False)
fig.update_layout(
updatemenus=[go.layout.Updatemenu(
active = 0,
buttons = [create_layout_button(k, s) for k, s in enumerate(df.symbol.unique())]
)
])
fig.show()
return fig.layout
make_multi_plot(stocks)
I am very new to python coding. With Dash - Plotly, I have plotted sensor data onto a GEO map, below the map is the histogram, which shows the frequency of sensor-observations per hour. There are three drop-down entries to filter the data based on date-picker from a calendar, a sensor picker and an hour picker.
The sample code of Dash-Plotly takes initially its own example CSV file for the image above (location: NY). I took my own CSV and made sure to alter it according to the format of the example CSV's (location: Africa). Which resulted into the following data format (two row sample):
**Date/Time Lat Lon**
2019-03-25 04:00:00 -10,80948998827914 20,19160777427344
2019-03-25 04:05:00 -10,798684405083584 20,16288145431259
My problem: Everything seems to work. Except when I select any date past (say) 7th of the month. Then I get three errors, which for the life of me I don't understand why, because nothing has changed except for the CSV:
EDIT 1:
As an example use-case: in my CSV I have sensor observations for the date '2019-03-23'. So on the webpage when I select the date: March 23, 2019. I get the following errors:
- Callback error updating total-rides.children - IndexError: list index out of range
File "/Frontend/app.py", line 262, in update_total_rides
len(totalList[date_picked.month - 4][date_picked.day - 1])
- Callback error updating histogram.figure - IndexError: list index out of range
File "/Frontend/app.py", line 322, in update_histogram
[xVal, yVal, colorVal] = get_selection(monthPicked,dayPicked, selection)
File "/Users/Mieer/Desktop/DSP_Frontend/app.py", line 231, in **get_selection**
yVal.append(len(totalList[month][day][totalList[month][day].index.hour== i]))
- Callback error updating map-graph.figure - IndexError: list index out of range
File "/Frontend/app.py", line 419, in update_graph
listCoords = getLatLonColor(selectedData, monthPicked,dayPicked)
File "/Users/Mieer/Desktop/DSP_Frontend/app.py", line 382, in **getLatLonColor**
listCoords = totalList[month][day]
My Question: How can one solve the range issue of the list? As for all I know, all that was altered in the code was the datafile which is full of enough data of the right format as I benchmarked the example CSV for which everything worked.
EDIT 2: the code hasn't changed, only the CSV has been replaced with one that considers the exact same format, but with way less records. I have added the callback-graph:
Below my code:
import dash
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
import numpy as np
from dash.dependencies import Input, Output
from plotly import graph_objs as go
from plotly.graph_objs import *
from datetime import datetime as dt
app = dash.Dash(
__name__, meta_tags=[{"name": "viewport", "content": "width=device-width"}]
)
server = app.server
# Plotly mapbox public token
mapbox_access_token = "pk.eyJ1IjoicGxvdGx5bWFwYm94IiwiYSI6ImNqdnBvNDMyaTAxYzkzeW5ubWdpZ2VjbmMifQ.TXcBE-xg9BFdV2ocecc_7g"
list_of_fixed_sensors = {
"sensor_1_2": {"lat": -10.736196, "lon": 20.060188},
"sensor_1_3": {"lat": -10.736196, "lon": 20.106700},
"sensor_1_6": {"lat": -10.736196, "lon": 20.246292},
# Initialize data frame
df1 = pd.read_csv(
"/Users/ME/Desktop/Frontend/sensor_points.csv",
dtype=object,
)
df = pd.concat([df1], axis=0)
df["Date/Time"] = pd.to_datetime(df["Date/Time"], format="%Y-%m-%d %H:%M")
df.index = df["Date/Time"]
df.drop("Date/Time", 1, inplace=True)
totalList = []
for month in df.groupby(df.index.month):
dailyList = []
for day in month[1].groupby(month[1].index.day):
dailyList.append(day[1])
totalList.append(dailyList)
totalList = np.array(totalList)
# Layout of Dash App HTML
app.layout = html.Div(
children=[
html.Div(
className="row",
children=[
# Column for user controls
html.Div(
className="four columns div-user-controls",
children=[
html.Img(
className="logo", src=app.get_asset_url("dash-logo-new-.png")
),
html.H2("DASHBOARD - Park Monitoring"),
html.Div(
className="div-for-dropdown",
children=[
dcc.DatePickerSingle(
id="date-picker",
min_date_allowed=dt(2019, 3, 1),
max_date_allowed=dt(2019, 12, 31),
initial_visible_month=dt(2019, 3, 1),
date=dt(2019, 3, 1).date(),
display_format="MMMM DD, YYYY",
style={"border": "0px solid white"}
)
],
),
# Change to side-by-side for mobile layout
html.Div(
className="row",
children=[
html.Div(
className="div-for-dropdown",
children=[
# Dropdown for locations on map
dcc.Dropdown(
id="location-dropdown",
options=[
{"label": i, "value": i}
for i in list_of_fixed_sensors
],
placeholder="Select a location",
)
],
),
html.Div(
className="div-for-dropdown",
children=[
# Dropdown to select times
dcc.Dropdown(
id="bar-selector",
options=[
{
"label": str(n) + ":00",
"value": str(n),
}
for n in range(24)
],
multi=True,
placeholder="Select certain hours",
)
],
),
],
),
html.H1(id="total-rides"),
html.H1(id="total-rides-selection"),
html.H1(id="date-value"),
],
),
# Column for app graphs and plots
html.Div(
className="eight columns div-for-charts bg-grey",
children=[
dcc.Graph(id="map-graph"),
html.Div(
className="text-padding",
children=[
"Select any of the bars on the histogram to section data by time."
],
),
dcc.Graph(id="histogram"),
],
),
],
)
]
)
# Get the amount of rides per hour based on the time selected
# This also higlights the color of the histogram bars based on
# if the hours are selected
def get_selection(month, day, selection):
xVal = []
yVal = []
xSelected = []
colorVal = [
"#F4EC15",
"#DAF017",
"#BBEC19",
"#9DE81B",
"#80E41D",
"#66E01F",
"#4CDC20",
"#34D822",
"#24D249",
"#25D042",
"#26CC58",
"#28C86D",
"#29C481",
"#2AC093",
"#2BBCA4",
"#2BB5B8",
"#2C99B4",
"#2D7EB0",
"#2D65AC",
"#2E4EA4",
"#2E38A4",
"#3B2FA0",
"#4E2F9C",
"#603099",
]
# Put selected times into a list of numbers xSelected
xSelected.extend([int(x) for x in selection])
for i in range(24):
# If bar is selected then color it white
if i in xSelected and len(xSelected) < 24:
colorVal[i] = "#FFFFFF"
xVal.append(i)
# Get the number of rides at a particular time
yVal.append(len(totalList[month][day][totalList[month][day].index.hour == i]))
return [np.array(xVal), np.array(yVal), np.array(colorVal)]
# Selected Data in the Histogram updates the Values in the DatePicker
#app.callback(
Output("bar-selector", "value"),
[Input("histogram", "selectedData"), Input("histogram", "clickData")],
)
def update_bar_selector(value, clickData):
holder = []
if clickData:
holder.append(str(int(clickData["points"][0]["x"])))
if value:
for x in value["points"]:
holder.append(str(int(x["x"])))
return list(set(holder))
# Clear Selected Data if Click Data is used
#app.callback(Output("histogram", "selectedData"), [Input("histogram", "clickData")])
def update_selected_data(clickData):
if clickData:
return {"points": []}
# Update the total number of observations
#app.callback(Output("total-rides", "children"), [Input("date-picker", "date")])
def update_total_rides(datePicked):
date_picked = dt.strptime(datePicked, "%Y-%m-%d")
return "Total number of observations: {:,d}".format(
len(totalList[date_picked.month - 4][date_picked.day - 1])
)
# Update the total number of observations from selected bar in histogram
#app.callback(
[Output("total-rides-selection", "children"), Output("date-value", "children")],
[Input("date-picker", "date"), Input("bar-selector", "value")],
)
def update_total_rides_selection(datePicked, selection):
firstOutput = ""
if selection is not None or len(selection) is not 0:
date_picked = dt.strptime(datePicked, "%Y-%m-%d")
totalInSelection = 0
for x in selection:
totalInSelection += len(
totalList[date_picked.month - 4][date_picked.day - 1][
totalList[date_picked.month - 4][date_picked.day - 1].index.hour
== int(x)
]
)
firstOutput = "Total observations for selected time: {:,d}".format(totalInSelection)
if (
datePicked is None
or selection is None
or len(selection) is 24
or len(selection) is 0
):
return firstOutput, (datePicked, " - showing hour(s): All")
holder = sorted([int(x) for x in selection])
if holder == list(range(min(holder), max(holder) + 1)):
return (
firstOutput,
(
datePicked,
" - showing hour(s): ",
holder[0],
"-",
holder[len(holder) - 1],
),
)
holder_to_string = ", ".join(str(x) for x in holder)
return firstOutput, (datePicked, " - showing hour(s): ", holder_to_string)
# Update Histogram Figure based on Month, Day and Times Chosen
#app.callback(
Output("histogram", "figure"),
[Input("date-picker", "date"), Input("bar-selector", "value")],
)
def update_histogram(datePicked, selection):
date_picked = dt.strptime(datePicked, "%Y-%m-%d")
monthPicked = date_picked.month - 4
dayPicked = date_picked.day - 1
[xVal, yVal, colorVal] = get_selection(monthPicked, dayPicked, selection)
layout = go.Layout(
bargap=0.01,
bargroupgap=0,
barmode="group",
margin=go.layout.Margin(l=10, r=0, t=0, b=50),
showlegend=False,
plot_bgcolor="#323130",
paper_bgcolor="#323130",
dragmode="select",
font=dict(color="white"),
xaxis=dict(
range=[-0.5, 23.5],
showgrid=False,
nticks=25,
fixedrange=True,
ticksuffix=":00",
),
yaxis=dict(
range=[0, max(yVal) + max(yVal) / 4],
showticklabels=False,
showgrid=False,
fixedrange=True,
rangemode="nonnegative",
zeroline=False,
),
annotations=[
dict(
x=xi,
y=yi,
text=str(yi),
xanchor="center",
yanchor="bottom",
showarrow=False,
font=dict(color="white"),
)
for xi, yi in zip(xVal, yVal)
],
)
return go.Figure(
data=[
go.Bar(x=xVal, y=yVal, marker=dict(color=colorVal), hoverinfo="x"),
go.Scatter(
opacity=0,
x=xVal,
y=yVal / 2,
hoverinfo="none",
mode="markers",
marker=dict(color="rgb(66, 134, 244, 0)", symbol="square", size=40),
visible=True,
),
],
layout=layout,
)
# Get the Coordinates of the chosen months, dates and times
def getLatLonColor(selectedData, month, day):
listCoords = totalList[month][day]
# No times selected, output all times for chosen month and date
if selectedData is None or len(selectedData) is 0:
return listCoords
listStr = "listCoords["
for time in selectedData:
if selectedData.index(time) is not len(selectedData) - 1:
listStr += "(totalList[month][day].index.hour==" + str(int(time)) + ") | "
else:
listStr += "(totalList[month][day].index.hour==" + str(int(time)) + ")]"
return eval(listStr)
# Update Map Graph based on date-picker, selected data on histogram and location dropdown
#app.callback(
Output("map-graph", "figure"),
[
Input("date-picker", "date"),
Input("bar-selector", "value"),
Input("location-dropdown", "value"),
],
)
def update_graph(datePicked, selectedData, selectedLocation):
zoom = 10.5
latInitial = -10.736196
lonInitial = 20.060188
bearing = 0
if selectedLocation:
zoom = 13.0
latInitial = list_of_fixed_sensors[selectedLocation]["lat"]
lonInitial = list_of_fixed_sensors[selectedLocation]["lon"]
date_picked = dt.strptime(datePicked, "%Y-%m-%d")
monthPicked = date_picked.month - 4
dayPicked = date_picked.day - 1
listCoords = getLatLonColor(selectedData, monthPicked, dayPicked)
return go.Figure(
data=[
# Data for all rides based on date and time
Scattermapbox(
lat=listCoords["Lat"],
lon=listCoords["Lon"],
mode="markers",
hoverinfo="lat+lon+text",
text=listCoords.index.hour,
marker=dict(
showscale=True,
color=np.append(np.insert(listCoords.index.hour, 0, 0), 23),
opacity=0.5,
size=5,
colorscale=[
[0, "#F4EC15"],
[0.04167, "#DAF017"],
[0.0833, "#BBEC19"],
[0.125, "#9DE81B"],
[0.1667, "#80E41D"],
[0.2083, "#66E01F"],
[0.25, "#4CDC20"],
[0.292, "#34D822"],
[0.333, "#24D249"],
[0.375, "#25D042"],
[0.4167, "#26CC58"],
[0.4583, "#28C86D"],
[0.50, "#29C481"],
[0.54167, "#2AC093"],
[0.5833, "#2BBCA4"],
[1.0, "#613099"],
],
colorbar=dict(
title="Time of<br>Day",
x=0.93,
xpad=0,
nticks=24,
tickfont=dict(color="#d8d8d8"),
titlefont=dict(color="#d8d8d8"),
thicknessmode="pixels",
),
),
),
# Plot of fixed sensors on the map
Scattermapbox(
lat=[list_of_fixed_sensors[i]["lat"] for i in list_of_fixed_sensors],
lon=[list_of_fixed_sensors[i]["lon"] for i in list_of_fixed_sensors],
mode="markers",
marker=dict(size=8, color='white', symbol='square', opacity=0.2),
hoverinfo="text",
text=[i for i in list_of_fixed_sensors],
),
],
layout=Layout(
autosize=True,
margin=go.layout.Margin(l=0, r=35, t=0, b=0),
showlegend=False,
mapbox=dict(
accesstoken=mapbox_access_token,
center=dict(lat=latInitial, lon=lonInitial),
style="dark",
bearing=bearing,
zoom=zoom,
),
updatemenus=[
dict(
buttons=(
[
dict(
args=[
{
"mapbox.zoom": 10.5,
"mapbox.center.lon": "24.060188",
"mapbox.center.lat": "-10.736196",
"mapbox.bearing": 0,
"mapbox.style": "dark",
}
],
label="Reset Zoom",
method="relayout",
)
]
),
direction="left",
pad={"r": 0, "t": 0, "b": 0, "l": 0},
showactive=False,
type="buttons",
x=0.45,
y=0.02,
xanchor="left",
yanchor="bottom",
bgcolor="#323130",
borderwidth=1,
bordercolor="#6d6d6d",
font=dict(color="#FFFFFF"),
)
],
),
)
if __name__ == "__main__":
app.run_server(debug=True)
As the error message suggests, all errors are caused by the index-out-of-range for the array totalList. The reason is quite obvious: totalList contains less elements (smaller shape) than you expect. See this section of your code:
totalList = []
for month in df.groupby(df.index.month):
dailyList = []
for day in month[1].groupby(month[1].index.day):
dailyList.append(day[1])
totalList.append(dailyList)
totalList = np.array(totalList)
It seems that you believe the value of month in the first loop will always iterate through 1, 2, ..., 12 and the day through 1,2,...,31. But those are not guaranteed. The shape of totalList strongly depends on the content of your input data (the CSV file). Let's say the file only contains records for 3 months (e.g. Jan. May and Dec.), then len(totalList)==3. More importantly, totalList[2] will contain the data for May instead of Feb.! So your code totalList[month][...] will give you the wrong data!! This is a more critical issue than those index-out-of-range errors.
You can get the data for a specific month and day by a single line:
df[(df.index.month==month) & (df.index.day==day)] # equivalent to totalList[month][day]
So it is not necessary to make use of the totalList array. I'd suggest you to refactor your code to get rid of this redundant data structure.
SOLUTION
I made the following alterations to the date and day to solve two issues:
List-out-of-Range issue.
The fact that totalList[month][...] outputs wrong data as there was a mismatch between totalList and the date/time of the actual CSV.
I have advanced (refactored) on the following code-snippets to obtain the solution significant to the graph, the histogram and the string that outputs total observations. Basically, the date and day have been corrected. One can compare these new snippet advancements with my original code in the post above.
With these advancements the calendar shows empty results for the
list-items that don't contain observations and shows the actual
correlating results of those list-items that do possess the
observations.
First advancement: added csv to consider the day/times of year.
df2 = pd.read_csv(
"2019daytimes.csv",
dtype=object,
)
df = df.append(df2, ignore_index=True, sort=True)
Second advancement: made the calendar start from first day of observations (static approach not dynamic (I know, later date= should be dynamic and dependent on the first date/time of observations captured in any assigned CSV))
dcc.DatePickerSingle(
id="date-picker",
min_date_allowed=dt(2019, 1, 1),
max_date_allowed=dt(2019, 12, 31),
date=dt(2019, 3, 23).date(),
display_format="MMMM DD, YYYY",
style={"border": "0px solid white"})
Third advancement: added totalList[date_picked.month-1][date_picked.day-1]) - 24
# Update the total number of observations
#app.callback(Output("total-observations", "children"), [Input("date-picker", "date")])
def update_total_rides(datePicked):
date_picked = dt.strptime(datePicked, "%Y-%m-%d")
return "Total number of observations: {:,d}".format(
len(totalList[date_picked.month-1][date_picked.day-1]) - 24
)
Fourth advancement: added [date_picked.month-1][date_picked.day-1] and -1 at end of totalInSelection += len() and if(totalInSelection < 0): totalInSelection = 0
def update_total_rides_selection(datePicked, selection):
firstOutput = ""
if selection is not None or len(selection) is not 0:
date_picked = dt.strptime(datePicked, "%Y-%m-%d")
totalInSelection = 0
for x in selection:
totalInSelection += len(
totalList[date_picked.month-1][date_picked.day-1][
totalList[date_picked.month-1][date_picked.day-1].index.hour
== int(x)
]
)-1
if(totalInSelection < 0):
totalInSelection = 0
firstOutput = "Total observations for selected time: {:,d}".format(totalInSelection)
Fifth advancement: added -1 for month and day of date_picked. And yVal -1
def update_histogram(datePicked, selection):
date_picked = dt.strptime(datePicked, "%Y-%m-%d")
# print(update_histogram)
monthPicked = date_picked.month-1
dayPicked = date_picked.day-1
[xVal, yVal, colorVal] = get_selection(monthPicked, dayPicked, selection)
#print(xVal)
#print(yVal)
yVal = yVal - 1
Sixed advancement: added -1 at month and day of date_picked.
def update_graph(datePicked, selectedData, selectedLocation):
zoom = 10.5
latInitial = -10.8736
lonInitial = 20.1067
bearing = 0
if selectedLocation:
zoom = 13.0
latInitial = list_of_fixed_sensors[selectedLocation]["lat"]
lonInitial = list_of_fixed_sensors[selectedLocation]["lon"]
date_picked = dt.strptime(datePicked, "%Y-%m-%d")
monthPicked = date_picked.month-1
dayPicked = date_picked.day-1
listCoords = getLatLonColor(selectedData, monthPicked, dayPicked)
I'm prototyping some code to then bring in some more complex time series data (and a lot of it) but can't for the life of me figure out how to get the vector components to animate in the below code. The blue path looks good to start with then disappears on play. And secondly, only the x component displays on play. I've been working mostly off the tutorials on the main plotly site so far, but, as the project builds complexity, my lack of expertise in plotly has let me down. I'm developing in an online Jupyter notebook if someone has any suggestions on how to make my code better. Thanks.
N = 50
vec_x, vec_y, vec_z = [0,0,0]
list_of_lists = []
choice = [-0.2, 0.2]
for i in range(N):
vec_x = vec_x + np.random.choice(choice)
vec_y = vec_y + np.random.choice(choice)
vec_z = vec_z + np.random.choice(choice)
list_of_lists.append([vec_x, vec_y, vec_z])
points = np.array(list_of_lists)
source = points.T
def frameMaker(i):
"""
returns x,y,z dict of currently indexed frame by vector component key
"""
scale = 10
list_of_lists = dict({
"x": [[source[0][i],scale * source[0][i+1]], [source[1][i],source[1][i]], [source[2][i],source[2][i]]],
"y": [[source[0][i],source[0][i]], [source[1][i],scale * source[1][i+1]], [source[2][i], source[2][i]]],
"z": [[source[0][i],source[0][i]], [source[1][i],source[1][i]], [source[2][i], scale * source[2][i+1]]]
})
return list_of_lists
#graphics
plt = go.Figure(
data=[go.Scatter3d(
x=source[0],
y=source[1],
z=source[2],
mode="lines",
line=dict(
color="darkblue",
width=2)),
go.Scatter3d(
x=source[0],
y=source[1],
z=source[2],
mode="lines",
line=dict(
color="darkblue",
width=2))
],
layout =
go.Layout(
title = go.layout.Title(text="Title | Total Frames: "+ str(N)),
scene_aspectmode="cube",
scene = dict(
xaxis = dict(range=[-2,2], nticks=10, autorange=False),
yaxis = dict(range=[-2,2], nticks=10, autorange=False),
zaxis = dict(range=[-2,2], nticks=10, autorange=False)),
updatemenus=[dict(type="buttons",
buttons=[dict(label="Play",
method="animate",
args=[None])])]
),
frames=[go.Frame(
data=[go.Scatter3d(
x = [source[0][k]],
y = [source[1][k]],
z = [source[2][k]],
mode="markers",
marker=dict(color="red",size=10,opacity=0.5)),
go.Scatter3d(
x=frameMaker(k)["x"][0],
y=frameMaker(k)["x"][1],
z=frameMaker(k)["x"][2],
line=dict(color='darkblue',width=2)),
go.Scatter3d(
x=frameMaker(k)["y"][0],
y=frameMaker(k)["y"][1],
z=frameMaker(k)["y"][2],
line=dict(color='#bcbd22',width=2)),
go.Scatter3d(
x=frameMaker(k)["z"][0],
y=frameMaker(k)["z"][1],
z=frameMaker(k)["z"][2],
line=dict(color='#d62728',width=2))],
layout=go.Layout(
title = go.layout.Title(text=str([k+1,list(map(lambda x: round(x,3), source.T[k]))]))
)
) for k in range(N-1)
]
)
plt.show()
I am new to using plotly and I am attempting to build a dynamic visualisation using python and plotly. I hope to be able to switch between a world choropleth map and a scatter plot using a drop-down menu.
So far I have been able to successfully get a dropdown menu to appear and show the required labels and even show a single plot by removing either the choropleth map or scatter plot trace from the data variable. The problem is that I when I try to have both plots implemented the choropleth map is drawn over the top of the scatterplot regardless of the menu option I choose.
A screenshot of the output.
Areas I Have Looked For A Solution
The plotly reference and looked through the updatemenus and layout sections among many others.
Reviewed the ploty python tutorial page for dropdowns and implementing parts of the suggestion in my code with a focus on the update method.
I have found a StackOverflow page that seemed to be very close to the answer I needed however not quite.
Finally, I also searched the plotly community forum.
The Code
Note I have removed a portion of the code such as imports and data at the beginning.
scatterplot = go.Scatter(
y = df2['Renewable energy consumption (% of total final energy consumption) 2015'],
x = df2['GDP per capita, PPP (constant 2011 international $) 2015'],
mode='markers',
ids=df2['Country Name'],
showlegend = False,
marker = dict(
size = 8,
color = np.random.randn(500),
),
textfont = dict(
size = 14,
color = 'black')
)
choropleth_map = dict(
type = 'choropleth',
locations = df['ISO3166_alpha3'],
z = df['renewables_mtoe'],
text = df['Country'],
colorscale = [[0,"rgb(106, 240, 255)"],[0.10,"rgb(106, 199, 255)"],[0.70,"rgb(50, 100, 255)"],[0.93,"rgb(0, 43, 198)"],\
[0.99999,"rgb(0, 24, 109)"],[1,"rgb(220, 220, 220)"]],
autocolorscale = False,
reversescale = True,
marker = dict(
line = dict (
color = 'rgb(180,180,180)',
width = 0.5
) ),
colorbar = dict(
title = 'mtoe<br>',
tickfont = dict(
size = 16),
titlefont = dict(
size = 16)),
)
data = [choropleth_map, scatterplot]
updatemenus = list([
dict(active=0,
buttons=list([
dict(label = 'choropleth_map',
method = 'update',
args = [{'visible': [True,False]},
{'title': 'The Map'}]),
dict(label = 'scatterplot',
method = 'update',
args = [{'visible': [False,True]},
{'title': 'Scatterplot'}]),
]),
)
])
layout = dict(title='default', showlegend=False,
updatemenus=updatemenus,
geo = dict(showframe = True,
showcoastlines = False,
showland = True,
landcolor = '#dcdcdc',
projection = dict(type = 'natural earth'))
)
fig = dict( data=data, layout=layout )
plotly.offline.iplot(fig, validate=True)
A big thank you in advance to anyone who can help. I have spent days trying to solve this problem, it has even driven me to make my first post on StackOverflow.