I want to create a graph where I want to add range to the secondary y-axis. The graph which I have right now is like this.
The code for this graph is like this:
import plotly.offline as pyo
import plotly.graph_objs as go
from plotly import tools
from plotly.subplots import make_subplots
import pandas as pd
import xlwings as xw
import logging
fileName = 'solar data.xlsx'
app = xw.App(visible=False)
try:
wb = app.books.open(fileName)
sheet = wb.sheets[4]
lastCell = sheet.range('A1').end('down').last_cell.row
solarOne = sheet.range('B2:B'+ str(lastCell)).value
bessOne = sheet.range('D2:D'+ str(lastCell)).value
socOne = sheet.range('E2:E'+ str(lastCell)).value
solarOne_Plus_bessOne = [i+j for i,j in zip(solarOne,bessOne)]
# solarTwo = sheet.range('F2:F' + str(lastCell)).value
# bessTwo = sheet.range('H2:H' + str(lastCell)).value
# socTwo = sheet.range('I2:I' + str(lastCell)).value
# solarTwo_Plus_bessTwo = [i + j for i, j in zip(solarTwo, bessTwo)]
except Exception as e:
logging.exception("Something awful happened!")
print(e)
finally:
app.quit()
app.kill()
fig = go.Figure()
projectTime = pd.date_range("2020-10-01 00:00:00", "2020-10-01 23:59:00", freq="1T")
fig = make_subplots(specs=[[{"secondary_y": True}]])
fig.add_trace(go.Scatter(x = projectTime, y = solarOne, name = 'Solar', fill='tozeroy', line=dict(width=0.5, color='rgb(255,167,0)')), secondary_y=False)
fig.add_trace(go.Scatter(x = projectTime, y = bessOne, name = 'Storage', fill='tozeroy', line=dict(width=0.5, color='rgb(43, 201, 34)')), secondary_y=False)
fig.add_trace(go.Scatter(x = projectTime, y = socOne, name = 'SoC', fill='tozeroy', line=dict(width=0.5, color='rgb(250, 67, 67)')), secondary_y=True)
fig.add_trace(go.Scatter(x = projectTime, y = solarOne_Plus_bessOne, name = 'Solar + BESS', fill='tozeroy',), secondary_y=False)
# Add figure title
fig.update_layout(
title_text="Solar with 0.5MW 0.5Hour storage"
)
# Set x-axis title
fig.update_xaxes(title_text="Time")
# Set y-axes titles
fig.update_yaxes(title_text="Dispatch(MW) and SoC(MWh)")
pyo.plot(fig, filename='Solar with 0.5MW 0.5Hour storage example 1.html')
I have tried to add layout_yaxis_range=[-0.6, 0.7] in secondary y-axis but it throws an error
TypeError: add_trace() got an unexpected keyword argument 'layout_yaxis_range'
I want this secondary y-axis with the same x-axis. Can anyone please help?
This works for me in similar cases:
fig.update_yaxes(range=[-0.6, 0.7], secondary_y=True)
Related
I am creating a 3D scatter plot based off a pandas dataframe, and then I want to re-draw it with slightly updated data whenever the user presses a button in my program. I almost have this functionality working, except the updated figure is drawn via a new opened tab, when really I just want my origin existing figure to be updated.
Here is my code. First I initialize the plot with 'version 1' of the data, then I set up a simple while loop to wait for the user to request an update. Then ideally once they enter input to ask for the update, I just re-draw everything in the same tab that is open. But instead a new tab is opened (which redraws the data correctly at least).
fig = go.Figure(data=[go.Scatter3d(x=df['x'],y=df['y'],z=df['z'],mode='markers', marker=dict(
size=4,
color=df['y'], # set color to an array/list of desired values
colorscale='Viridis', # choose a colorscale
opacity=0.3
))])
# Column max and mins for plotting:
xmax = df_1.max(axis=0)['x']; xmin = df_1.min(axis=0)['x']
ymax = df_1.max(axis=0)['y']; ymin = df_1.min(axis=0)['y']
zmax = df_1.max(axis=0)['z']; zmin = df_1.min(axis=0)['z']
fig.update_layout(
scene = dict(xaxis = dict(nticks=4, range=[xmin,xmax],),
yaxis = dict(nticks=4, range=[ymin,ymax],),
zaxis = dict(nticks=4, range=[zmin,zmax],),))
f2 = go.FigureWidget(fig)
f2.show()
#fig.show()
while True:
choice = input("> ")
choice = choice.lower() #Convert input to "lowercase"
if choice == 'exit':
print("Good bye.")
break
if choice == 'w':
print("W, moving forward")
cube_origin = cube_origin + np.array([0.1,0,0])
df_cube = createCubeMesh(cube_size, cube_density, cube_origin)
new_df = df_scene_orig.copy()
new_df = new_df.append(df_cube)
fig = go.Figure(data=[go.Scatter3d(x=new_df['x'],y=new_df['y'],z=new_df['z'],mode='markers', marker=dict(
size=4,
color=new_df['y'], # set color to an array/list of desired values
colorscale='Viridis', # choose a colorscale
opacity=0.3
))])
f2 = go.FigureWidget(fig)
f2.show()
I based my code on another answer that said to use go.FigureWidget(fig), but it doesn't seem to work as intended.
Edit
Instead of me using f2.show() at the end, I just want a simple thing analogous to f2.update() that redraws.
This is the case you want.
Everywhere in this page that you see fig.show(), you can display the same figure in a Dash application by passing it to the figure argument of the Graph component from the built-in dash_core_components package like this:
import plotly.graph_objects as go
fig = go.Figure(
data=[go.Scatter(
mode="markers+text",
x=[10, 20],
y=[20, 25],
text=["Point A", "Point B"]
)],
layout=dict(height=400, width=400, template="none")
)
import dash
import dash_core_components as dcc
import dash_html_components as html
app = dash.Dash()
app.layout = html.Div([
dcc.Graph(figure=fig)
])
app.run_server(debug=True, use_reloader=False)
reference: https://plotly.com/python/figure-introspection/
Help you write a code that is closest to your needs:
import plotly as py
from dash import dcc
from dash import html
from dash.dependencies import Input, Output
import plotly.graph_objects as go
from jupyter_dash import JupyterDash
import pandas as pd
import numpy as np
py.offline.init_notebook_mode(connected=True)
app = JupyterDash('SimpleExample')
app.layout = html.Div([
dcc.Dropdown(id='dropdown', options=[
{'label': 'W', 'value': 'W'},
{'label': 'exit', 'value': 'exit'}],
value='exit'),
dcc.Graph(id='graph-court')
])
def random_data():
# sample dataframe of a wide format
np.random.seed(4)
cols = list('xyz')
X = np.random.randint(50, size=(3, len(cols)))
df = pd.DataFrame(X, columns=cols)
df.iloc[0] = 0
return df
df = random_data()
def create_figure(df):
fig = go.Figure(data=[go.Scatter3d(x=df['x'], y=df['y'], z=df['z'], mode='markers', marker=dict(
size=10,
color=df['y'],
colorscale='Viridis',
opacity=0.3
))])
# Column max and mins for plotting:
xmax = df.max(axis=0)['x']
xmin = df.min(axis=0)['x']
ymax = df.max(axis=0)['y']
ymin = df.min(axis=0)['y']
zmax = df.max(axis=0)['z']
zmin = df.min(axis=0)['z']
fig.update_layout(
scene=dict(xaxis=dict(nticks=4, range=[xmin, xmax], ),
yaxis=dict(nticks=4, range=[ymin, ymax], ),
zaxis=dict(nticks=4, range=[zmin, zmax], ), ))
fig = go.FigureWidget(fig)
return fig
#app.callback(Output('graph-court', 'figure'),
[Input('dropdown', 'value')])
def update_figure(selected_value):
selected_value = selected_value.lower() # Convert input to "lowercase"
if selected_value == 'exit':
print("Good bye.")
new_x, new_y, new_z = [], [], []
else:
print("W, moving forward")
# new data
new_x, new_y, new_z = np.random.randint(10, size=(3, 1))
# ploy
fig = create_figure(df) # Set as global variable or local variable as required
fig.add_trace(go.Scatter3d(x=new_x, y=new_y, z=new_z, marker=dict(size=10, color='green'), mode='markers'))
return fig
app.run_server(debug=False, use_reloader=False)
Estimated that your "tab" is referring to "browser tab" it is basically not possible with the standard renderer.
With the renderer browser it serves a one-shot server on a random port, which is shutting down immediately after the rendering is done. You can check that by reloading the graph in browser.
You can:
generate a static image and serve that yourself in a webapp (e.g. with flask) with f2.write_image("test.svg")
generate a dynamic html content by f2.show(renderer = "iframe") and serve that with e.g. flask
simply use plotly dash, look here for impressions
Try using Plotly for plotting, it has a functionality (Visibility), using that you can update your plot on button click or drop down.
The below example is for dropdown.
import pandas as pd
import numpy as np
import plotly.offline as py_offline
import plotly.graph_objs as go
from plotly import tools
py_offline.init_notebook_mode()
trace = go.Scatter(
x=[1, 2, 3],
y=[4, 5, 6]
)
fig = tools.make_subplots(rows=10, cols=1)
for k in range(10):
fig.append_trace(trace, k+1, 1)
updatemenus=list([
dict(
buttons=[],
direction = 'down',
pad = {'r': 10, 't': 10},
showactive = True,
x = 0,
xanchor = 'left',
y = 1.2,
yanchor = 'top'
),
])
lister = []
for k in range(11):
lister.append(dict(
args=['visible', [True for k in range(10)] if k == 0 else [True if (i+1) == k else False for i in range(10)]],
label='Show Trace ' + str( 'All' if k == 0 else k),
method='restyle'
))
updatemenus[0]['buttons'] = lister
fig['layout']['updatemenus'] = updatemenus
fig['layout'].update(title='subplots')
py_offline.iplot(fig, filename='simple-subplot')
I've developed a software that shows plotted data from csv file.
Now I've created something that allows to the user to choose which plot to see.
I was looking how to do switch-case and I try it but something is wrong because actually my program opens wrong charts.
How can I solve it?
My code:
from Signals_Plotter import Plot_data
FILE_NAME = 'Signals_informations.csv'
plot_csv_obj = Plot_data()
user_choice = input("Which chart do you want?:\n"
"1: Line plot (all signals in same chart)\n"
"2: Bar subplots (signals in sublotted charts)\n"
"3: Markers plot (all signals in same chart)\n"
"4: Line subplots (signals in sublotted chart)\n"
"5: Stacked plot (all signals in same chart with stacked Y axes)\n"
)
def switch_demo(user_choice):
switcher = {
1: plot_csv_obj.line_plot_from_csv(FILE_NAME),
2: plot_csv_obj.bar_plot_from_csv(FILE_NAME),
3: plot_csv_obj.scatter_plot_from_csv(FILE_NAME),
4: plot_csv_obj.subplots_from_csv(FILE_NAME),
5: plot_csv_obj.stacked_plot_from_csv(FILE_NAME)
}
return switcher.get(user_choice, "Invalid choice")
switch_demo(user_choice)
Plot_Data class:
from plotly.offline import plot
import pandas as pd
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import random
class Plot_data:
def line_plot_from_csv(self, file_name):
df = pd.read_csv(file_name, delimiter = ';')
fig = go.Figure()
for i in range(1, len(df.columns)):
fig.add_trace(go.Scatter(x=df.iloc[:,0], y=df.iloc[:,i], mode='lines', name=df.columns[i]))
fig.update_layout(title_text="Line plots", yaxis={'title':'Values [unit]'}, xaxis={'title':'DateTime'})
plot(fig)
def bar_plot_from_csv(self, file_name):
df = pd.read_csv(file_name, delimiter = ';')
fig = make_subplots(rows=1, cols=df.shape[1]-1)
for i in range(1, len(df.columns)):
fig.add_trace(go.Bar(x=df.iloc[:,0], y=df.iloc[:,i], name=df.columns[i]),row=1, col=i)
fig.update_layout(height=600, width=1000, title_text="Bar Subplots", yaxis={'title':'Values [unit]'}, xaxis={'title':'DateTime'})
plot(fig)
def scatter_plot_from_csv(self, file_name):
df = pd.read_csv(file_name, delimiter = ';')
fig = go.Figure()
for i in range(1, len(df.columns)):
fig.add_trace(go.Scatter(x=df.iloc[:,0], y=df.iloc[:,i], mode='markers', name=df.columns[i]))
fig.update_layout(title_text="Markers plot", yaxis={'title':'Values [unit]'}, xaxis={'title':'DateTime'})
plot(fig)
def subplots_from_csv(self, file_name):
df = pd.read_csv(file_name, delimiter = ';')
fig = make_subplots(rows=1, cols=df.shape[1]-1)
for i in range(1, len(df.columns)):
fig.add_trace(go.Scatter(x=df.iloc[:,0], y=df.iloc[:,i], name=df.columns[i]),row=1, col=i)
fig.update_layout(height=600, width=1000, title_text="Scatter line Subplots", yaxis={'title':'Values [unit]'}, xaxis={'title':'DateTime'})
plot(fig)
def stacked_plot_from_csv(self, file_name):
df = pd.read_csv(file_name, delimiter = ';')
fig = go.Figure()
colors=[]
axes = {
'xaxis': dict(domain=[0.3, 0.7])
}
for i in range(1, len(df.columns)):
fig.add_trace(go.Scatter(x=df.iloc[:,0], y=df.iloc[:,i], name=df.columns[i], yaxis='y'+str(i)))
s = 'yaxis'
colors.append("#{:06x}".format(random.randint(0, 0xFFFFFF)))
if i > 1:
s = s + str(i)
axes[s] = dict(
title=f"S{i}",
titlefont=dict(color=colors[i-1]),
tickfont=dict(color=colors[i-1])
)
if i > 1:
axes[s]['anchor'] = 'free'
axes[s]['overlaying'] = 'y'
if i > len(df.columns) / 2:
axes[s]['side'] = 'right'
axes[s]['position'] = 0.3 + 0.1*i
else:
axes[s]['side'] = 'left'
axes[s]['position'] = 0.1*i
fig.update_layout(**axes)
fig.update_layout(
title_text="Stacked y-axes",
yaxis={'title':'Values [unit]'},
xaxis={'title':'DateTime'},
height=600,
width=1500
)
plot(fig)
Either cast your input to an integer or cast your dict keys to strings:
def switch_demo(user_choice):
switcher = {
"1": plot_csv_obj.line_plot_from_csv(FILE_NAME),
"2": plot_csv_obj.bar_plot_from_csv(FILE_NAME),
"3": plot_csv_obj.scatter_plot_from_csv(FILE_NAME),
"4": plot_csv_obj.subplots_from_csv(FILE_NAME),
"5": plot_csv_obj.stacked_plot_from_csv(FILE_NAME)
}
return switcher.get(user_choice, "Invalid choice")
With Bokeh, how do I get a handle to the Renderer (or GlyphRenderer) for an Annotation? Is this possible?
I would like to be able to toggle a Band (which is an Annotation) on and off with an interactive legend, so I need to be able to pass a list of Renderers to the LegendItem constructor.
This code:
maxline = fig.line(x='Date', y=stn_max, line_width=0.5, legend=stn_max, name="{}_line".format(stn_max), color=stn_color, alpha=0.75, source=source)
minline = fig.line(x='Date', y=stn_min, line_width=0.5, legend=stn_min, name="{}_line".format(stn_min), color=stn_color, alpha=0.75, source=source)
band = bkm.Band(base='Date', lower=stn_min, upper=stn_max, fill_alpha=0.50, line_width=0.5, fill_color=stn_color, source=source)
bkm.LegendItem(label=stn, renderers=[maxline, minline, band])
Produces this error
...
ValueError: expected an element of List(Instance(GlyphRenderer)), got seq with invalid items [Band(id='1091', ...)]
For LegendItem only instances of GlyphRenderer can be passed to its renderers attribute and Band is not based on GlyphRenderer so it gives error. In the code below the Band visibility is being toggled by means of a callback:
from bokeh.plotting import figure, show
from bokeh.models import Band, ColumnDataSource, Legend, LegendItem, CustomJS
import pandas as pd
import numpy as np
x = np.random.random(2500) * 140 - 20
y = np.random.normal(size = 2500) * 2 + 5
df = pd.DataFrame(data = dict(x = x, y = y)).sort_values(by = "x")
sem = lambda x: x.std() / np.sqrt(x.size)
df2 = df.y.rolling(window = 100).agg({"y_mean": np.mean, "y_std": np.std, "y_sem": sem})
df2 = df2.fillna(method = 'bfill')
df = pd.concat([df, df2], axis = 1)
df['lower'] = df.y_mean - df.y_std
df['upper'] = df.y_mean + df.y_std
source = ColumnDataSource(df.reset_index())
p = figure(tools = "pan,wheel_zoom,box_zoom,reset,save")
scatter = p.scatter(x = 'x', y = 'y', line_color = None, fill_alpha = 0.3, size = 5, source = source)
band = Band(base = 'x', lower = 'lower', upper = 'upper', source = source)
p.add_layout(band)
p.title.text = "Rolling Standard Deviation"
p.xaxis.axis_label = 'X'
p.yaxis.axis_label = 'Y'
callback = CustomJS(args = dict(band = band), code = """
if (band.visible == false)
band.visible = true;
else
band.visible = false; """)
legend = Legend(items = [ LegendItem(label = "x", renderers = [scatter, band.source.selection_policy]) ])
legend.click_policy = 'hide'
scatter.js_on_change('visible', callback)
p.add_layout(legend)
show(p)
Result:
Plotly.py is having issues with the y axis. Data is not ordered. Even in the csv file the data is sorted in ascending order.
https://i.stack.imgur.com/SUOL3.png
import plotly
import plotly.plotly as py
import plotly.graph_objs as go
import pandas as pd
import numpy as np
import math
#What is the filename
filename = 'output.csv'
#What is the X Value?
xvalue = 'total_students'
#What is the Y Value?
yvalue = 'realcount'
#What is the plot title?
PlotTitle = 'total_students'
filename = input("What is the filename? (WITH .CSV) ")
xvalue = input("What is the X value? ")
yvalue = input("What is the y Value? ")
PlotTitle = input("What is the title of this chart? ")
esc1 = pd.read_csv('output.csv', encoding='cp1252')
def random_color():
rgbl=[255,0,0]
random.shuffle(rgbl)
return tuple(rgbl)
esc1 = go.Scatter(
x = esc1[xvalue],
y = esc1[yvalue],
name = 'School',
mode = 'markers',
marker = dict(
size = 10,
sizemode='area',
sizeref=1,
color = 'rgba(66, 134, 244, .8)'
)
)
data = [esc1]
layout = dict(title = 'Total Student Scatter',
yaxis = dict(zeroline = True,
title=yvalue),
xaxis = dict(zeroline = True,
title=xvalue)
)
#fig = dict(data=data, layout=layout)
#py.iplot(fig, filename='styled-scatter')
plotly.offline.plot({
"data": data,
"layout": layout
},filename=PlotTitle+'.html', auto_open=False)
print("Finished")
Jeeze stack-overflow has a ton of quality control. I have to keep adding details so i hope this helps.
Hmm, also worked fine. My code:
#import all the necessary libraries
import plotly
import plotly.plotly as py
import plotly.graph_objs as go
import pandas as pd
import numpy as np
import math
import random
#What is the filename
filename = 'output.csv'
#What is the X Value?
xvalue = 'total_students'
#What is the Y Value?
yvalue = 'realcount'
#What is the plot title?
PlotTitle = 'total_students'
filename = input("What is the filename? (WITH .CSV) ")
xvalue = input("What is the X value? ")
yvalue = input("What is the y Value? ")
PlotTitle = input("What is the title of this chart? ")
esc1 = pd.read_csv(filename)
#I don`t have your `output.csv` so I am created own DataFrame
#esc1 = pd.DataFrame({"total_students":["10","20","30","40","50"],\
# "realcount":["8","16","28","39","41"]})
def random_color():
rgbl=[255,0,0]
random.shuffle(rgbl)
return tuple(rgbl)
#That`s your scatter trace
trace = go.Scatter(
x = esc1[xvalue],
y = esc1[yvalue],
name = 'School',
mode = 'markers',
marker = dict(
size = 10,
sizemode='area',
sizeref=1,
color = 'rgba(66, 134, 244, .8)'
)
)
#Give trace to data
data = [trace]
#Create layout
layout = dict(title = 'Total Student Scatter',
yaxis = dict(zeroline = True,
title=yvalue),
xaxis = dict(zeroline = True,
title=xvalue)
)
fig = dict(data=data, layout=layout)
plotly.offline.plot(fig, filename=PlotTitle+'.html', auto_open=False)
print("Finished")
And plot looks nice (yaxis and xaxis order as expected):
Why plotly package of python can not display figure in RMarkdown but matplotlib can? For example:
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE, message = FALSE, warning = FALSE)
```
```{r}
library(plotly)
subplot(
plot_ly(mpg, x = ~cty, y = ~hwy, name = 'default'),
plot_ly(mpg, x = ~cty, y = ~hwy) %>%
add_markers(alpha = 0.2, name = 'alpha'),
plot_ly(mpg, x = ~cty, y = ~hwy) %>%
add_markers(symbols = I(1), name = 'hollow')
)
```
```{python}
import plotly
import plotly.plotly as py
import plotly.graph_objs as go
import numpy as np
plotly.tools.set_credentials_file(username='xxx', api_key='xxx')
N = 500
trace0 = go.Scatter(x = np.random.randn(N), y = np.random.randn(N) + 2, name = "Above", mode = "markers",
marker = dict(size = 10, color = "rgba(152, 0, 0, .8)", line = dict(width = 2, color = "rgb(0,0,0)")))
trace1 = go.Scatter(x = np.random.randn(N), y = np.random.randn(N) - 2, name = "below", mode = "markers",
marker = dict(size = 10, color = "rgba(255, 182, 193, .9)", line = dict(width = 2, color = "rgb(0,0,0)")))
data = [trace0, trace1]
layout = dict(title = "Styled Scatter", yaxis = dict(zeroline = False), xaxis = dict(zeroline=False))
fig = dict(data = data, layout = layout)
py.iplot(fig, filename = "styled-scatter")
```
The R code can work well, but the python code can not dispay the figure, what is wrong with the code?
Here is what I did:
used plotly offline:
replace import plotly.plotly as py by import plotly.offline as py
no need to set username and api key in offline mode.
used py.plot(fig, filename = "styled-scatter.html", auto_open=False):
py.iplot() is for Jupyter notebooks (it embeds the plot directly into the Notebook)
auto_open = False argument is to avoid that the plot pops up.
embedded the html plot into the Rmarkdown by using the following:
```{r, echo=FALSE}
htmltools::includeHTML("styled-scatter.html")
```
and here is the result: