I'm currently trying to create a graph with plotly,
My goal would be to create a combined Barplot / Data table both controled with a range slider in order to controle the values with the date. I've succeded to create the barplot controled with the range slider.
I can't manage to control the table :/
Here is a combined plot but where the range slider is attached to the table, as you can see it does not control the date but the table view
https://plotly.com/~tristan1551/31/
Here is an exemple of a barplot i've done with a range slider https://plotly.com/~tristan1551/23/
Another idea would be to only to control the table with the ranger slider, i can't manager to do that too.
Is there a way to achive what i want to do ?
Thank you for your herlp :)
to synchronise a table with a range slider on a figure you can use a dash callback
below code creates a bar chart with a rangeslider
attaches a callback to changes in figure to get position of rangeslider
constructs table based on these inputs
from jupyter_dash import JupyterDash
import dash_core_components as dcc
import dash_html_components as html
import dash_table
from dash.dependencies import Input, Output, State
import pandas as pd
import numpy as np
import plotly.express as px
df = pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/2014_apple_stock.csv")
df["AAPL_x"] = pd.to_datetime(df["AAPL_x"])
fig = px.bar(df, x="AAPL_x", y="AAPL_y").update_layout(
xaxis={
"range": [df["AAPL_x"].quantile(0.9), df["AAPL_x"].max()],
"rangeslider": {"visible": True},
}
)
# Build App
app = JupyterDash(__name__)
app.layout = html.Div(
[dcc.Graph(id="bargraph", figure=fig), html.Div(id="bartable", children=[])],
)
#app.callback(
Output("bartable", "children"),
Input("bargraph", "relayoutData"),
)
def updateTable(graphData):
global df
if graphData and "xaxis.range" in graphData.keys():
d1 = pd.to_datetime(graphData["xaxis.range"][0])
d2 = pd.to_datetime(graphData["xaxis.range"][1])
else:
d1 = df["AAPL_x"].quantile(0.9)
d2 = df["AAPL_x"].max()
dft = df.loc[df["AAPL_x"].between(d1, d2)]
return dash_table.DataTable(
columns=[{"name": c, "id": c} for c in dft.columns],
data=dft.to_dict("records"),
)
# Run app and display result inline in the notebook
app.run_server(mode="inline")
Related
I have a plotly generated plot in python.
It can be zoomed or a specific region selected by window selection.
Is there any solution to calculate current number of points on current view of scatterplot?
E.g. initial screen gives us 1000 points, but when I zoom or using a window to choose any specific area - I want to see that this area includes only 100 points from initial scatterplot. Is it possible? Or maybe to get bounds from x-axis of a plot to use it in further dashboard - e.g. to calculate max/min/mean values for the points on the screen..
you clearly state dashboard hence assuming dash
zoom and pan result in relayoutDatacallback being triggered
this passes a dict which can be parsed for min/max x and y
code below shows this, filtering dataframe used to create scatter to get number of points
import dash
import plotly.express as px
from dash.dependencies import Input, Output, State
from jupyter_dash import JupyterDash
import numpy as np
import pandas as pd
r = np.random.RandomState(42)
# some data to plot
df = pd.DataFrame(
{"x-val": np.linspace(1, 100, 1000), "y-val": r.uniform(1, 100, 1000)}
)
fig = px.scatter(df, x="x-val", y="y-val")
app = JupyterDash(__name__)
app.layout = dash.html.Div(
[dash.dcc.Graph(id="graph", figure=fig), dash.html.Div(id="debug")]
)
# simple callback capture zoom and pan
#app.callback(Output("debug", "children"), Input("graph", "relayoutData"))
def figEvent(relayoutData):
r = relayoutData
# parse out min & max values displayed
rng = {
ax: [df[c].min(), df[c].max()]
if f"{ax}axis.range[0]" not in r.keys()
else [r[f"{ax}axis.range[0]"], r[f"{ax}axis.range[1]"]]
for ax, c in zip("xy", ["x-val", "y-val"])
}
# filter dataframe and get number of rows
n = df.loc[df["x-val"].between(*rng["x"]) & df["y-val"].between(*rng["y"])].shape[0]
return n
app.run_server(mode="inline", debug=True)
I've tried navigating around the web for a solution to this problem, but have had no luck. The closest solution I found was this, however, it's in R and I've been trying to look for a solution in Python for this these past twos days.
I've already messed with Plotly Dash's documentation here on Interactive Graphing and the clickData and hoverData seems to only output coordinate data on actual data points on the graph that are clicked/hovered over on. My goal is obtain a pair of x,y coordinate through two mouse clicks on the graph, so that I am able to draw a line on the graph using that pair of coordinates. However, it seems Plotly's Dash Interactive Graphing is limited in its ability to provide mouse coordinate data that are not on actual data points. Is there any work around to this or an obvious solution / part of the documentation that I missed?
you can create an additional trace of transparent points that are scattered uniformly across the figure
then it's a simple case of using clickData callback
full code below
import numpy as np
import pandas as pd
import plotly.express as px
import math, json
import dash
from dash.dependencies import Input, Output, State
from jupyter_dash import JupyterDash
GS = 100
fig = px.line(
x=np.linspace(0, 1, 300), y=(np.sin(np.linspace(0, math.pi * 3, 300)) / 2) + 0.5
).add_traces(
px.scatter(
x=np.repeat(np.linspace(0, 1, GS), GS), y=np.tile(np.linspace(0, 1, GS), GS)
)
.update_traces(marker_color="rgba(0,0,0,0)")
.data
)
# Build App
app = JupyterDash(__name__)
app.layout = dash.html.Div(
[dash.dcc.Graph(id="graph", figure=fig), dash.html.Div(id="where")]
)
#app.callback(
Output("where", "children"),
Input("graph", "clickData"),
)
def click(clickData):
if not clickData:
raise dash.exceptions.PreventUpdate
return json.dumps({k: clickData["points"][0][k] for k in ["x", "y"]})
# Run app and display result inline in the notebook
app.run_server(mode="inline")
I've been trying to create a candlestick graph that shows the prices of NASDAQ and moving average on it, which has been a partial success:
import dash
from dash.dependencies import Output, Input
import dash_core_components as dcc
import dash_html_components as html
import plotly
import random
import plotly.graph_objs as go
import yfinance as yf
import plotly.express as px
import datetime as dt
from datetime import datetime
from metody import metody
import time
import pandas as pd
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
NASDAQ = pd.read_excel(r'file.xlsx')
app = dash.Dash(external_stylesheets=external_stylesheets)
fig = go.Figure(data=go.Candlestick(
open=NASDAQ['Open'],
close=NASDAQ['Close'],
low=NASDAQ['Low'],
high=NASDAQ['High'],
))
close = NASDAQ['Close']
open = NASDAQ['Open']
srednia = metody.generateMovingAverage(NASDAQ['Close'], 3)
fig.add_trace(
go.Scatter(
y=srednia
)
)
app.layout = html.Div([
html.H1(
children="This is a chart of {}".format("NASDAQ"),
style={
'text-align': 'center'
}
),
dcc.Graph(
id='candles',
animate=True,
figure=fig,
),
dcc.Interval(
id='update',
interval=1000
)
])
app.run_server(debug=True)
unfortunately however when I'm trying to zoom the results, the candles do not upscale so that it's readable:
My question is: how do I deal with that? I'd love my chart to be nicely interactive (meaning the user can adjust the period and the candles are as big as it fits to the size of the chart).
PS: I'm really new to Dash, so if you've got any comments on my code or you know something I've done the wrong way round, please tell me :)
You need to get this into your code somewhere (upon zoom trigger):
fig.update_yaxes(range=[minY, maxY])
with minY and maxY being chosen from a downselection of your results (and rounded down and up respectively to look a bit better)
But I don't see where your zoom is being done - I assume you aren't using the plotly default but instead closing in using the lower summary bar?
You might have to dive in to the .css I'm afraid - or maybe you can insert additional lines into it before passing it to dash.Dash()
I am creating a dashboard in dash for a course at university. I created 3 histograms however, there are many unique values which give a long range of x values. In my plots I would like to show only the 10 or 20 values that have the highest count (top 10 values). Can someone help me out?
import plotly.express as px
from jupyter_dash import JupyterDash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
# Build App
app = JupyterDash(__name__)
app.layout = html.Div([
html.H1("forensics "),
dcc.Graph(id='graph'),
dcc.Graph(id='graph1'),
dcc.Graph(id='graph2'),
html.Label([
"select market",
dcc.Dropdown(
id='market', clearable=False,
value='whitehousemarket', options=[
{'label': c, 'value': c}
for c in posts['marketextract'].unique()
])
]),
])
# Define callback to update graph
#app.callback(
Output('graph', 'figure'),
Output('graph1', 'figure'),
Output('graph2', 'figure'),
[Input("market", "value")]
)
def update_figure(market):
fig=px.histogram(x=posts['datetime'].loc[posts['marketextract']==market])
fig1=px.histogram(x=posts['username'].loc[posts['marketextract']==market])
fig2=px.histogram(x=posts['drugs'].loc[posts['marketextract']==market])
return [fig, fig1, fig2]
# Run app and display result inline in the notebook
app.run_server(mode='inline')
To my knowledge, px.histogram() does not have a method to exclude certain observations of bins. But judging by the look of your data (please consider sharing a proper sample), what you're doing here is just showing the different counts of some user names. And you can easily do that through a combination of df.groupby() and px.histogram. Or px.bar() or go.Bar() for that matter, but we'll stick with px.histogram since that is what you're seeking help with. Anyway, using random selections of country names from px.gapminder you can use:
dfg = df.groupby(['name']).size().to_frame().sort_values([0], ascending = False).head(10).reset_index()
fig = px.histogram(dfg, x='name', y = 'count')
And get:
If you drop .head(10) you'll get this instead:
And I hope this is the sort of functionality you were looking for. And don't be intimidated by the long df.groupby(['name']).size().to_frame().sort_values([0], ascending = False).reset_index(). I'm not a pandas expert, so you could quite possibly find a more efficient approach. But it does the job. Here's the complete code with some sample data:
# imports
import pandas as pd
import plotly.express as px
import random
# data sample
gapminder = list(set(px.data.gapminder()['country']))[1:20]
names = random.choices(gapminder, k=100)
# data munging
df = pd.DataFrame({'name':names})
dfg = df.groupby(['name']).size().to_frame().sort_values([0], ascending = False).reset_index()
dfg.columns = ['name', 'count']
# plotly
fig = px.histogram(dfg, x='name', y = 'count')
fig.layout.yaxis.title.text = 'count'
fig.show()
I would like to create a vertical scroll for a line chart in Plotly. For visualisation, the vertical scroll is something depicted in the figure below.
Assume, we have 6 line chart as below, then how can we create a vertical scroll bar on the canvas
import plotly.graph_objects as go
import plotly.io as pio
from plotly.subplots import make_subplots
import pandas as pd
# data
pio.templates.default = "plotly_white"
df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv')
df = df.set_index('Date')
df.tail()
cols = df.columns[:-4]
ncols = len(cols)
# subplot setup
fig = make_subplots(rows=ncols, cols=1, shared_xaxes=True)
for i, col in enumerate(cols, start=1):
fig.add_trace(go.Scatter(x=df[col].index, y=df[col].values), row=i, col=1)
fig.show()
Thanks for any tips or good reading material.
I made a single page web app using plotly-dash. In this dashboard I wanted to create a vertical bar chart that also had a sroller on the side.
I imported the following dependencies:
from dash.dependencies import Input, Output, State
import dash_html_components as html
import dash_core_components as dcc
import dash_bootstrap_components as dbc
import dash
import dash_table
import plotly.graph_objs as go
import pandas as pd
In the app.layout I gave the css style parameters in the html.Div that contained my dcc.graph component:-
dcc.Graph(
id='doctors',
figure={}
),style={"maxHeight": "400px", "overflow": "scroll"})
], width={'size': 6})
Later in the #app callback I gave height to my vertical bar graph:-
fig.update_layout(height = (30*len(all_by_doctor)), title_text='Total bookings
by {} doctors'.format(len(all_by_doctor)),plot_bgcolor='#ffffff')