Plotting 3 pie charts side-by-side using the domain property - python

I am trying to plot 3 pie charts side by side. I don't understand why the following code is making the pie charts go across the page diagonally left to write rather than horizontally left to write in one line.
Here's my code:
app.layout = html.Div([
html.Div([
dcc.Graph(id='TPiePlot',
figure={
'data': [go.Pie(labels=labels1,
values=values1,
marker=dict(colors=colors, line=dict(color='#fff', width=1)),
hoverinfo='label+value+percent', textinfo='value',
domain={'x': [0, .25], 'y': [0, 1]}
)
],
'layout': go.Layout(title='T',
autosize=True
)
}
),
dcc.Graph(id='RPiePlot',
figure={
'data': [go.Pie(labels=labels2,
values=values2,
marker=dict(colors=colors, line=dict(color='#fff', width=1)),
hoverinfo='label+value+percent', textinfo='value',
domain={'x': [0.30, .55], 'y': [0, 1]}
)
],
'layout': go.Layout(title='R',
autosize=True
)
}
),
dcc.Graph(id='RoPiePlot',
figure={
'data': [go.Pie(labels=labels3,
values=values3,
marker=dict(colors=colors, line=dict(color='#fff', width=1)),
hoverinfo='label+value+percent', textinfo='value',
domain={'x': [0.60, 0.85], 'y': [0, 1]}
)
],
'layout': go.Layout(title='Ro',
autosize=True
)
}
)
])
])
Here is what's happening with option 1 from accepted answer (which is the one I need to go with). I'm getting three different sizes plus legend covering some of the pie chart:
I'm struggling to understand how to re-size dash graphs using CSS because the whole container increases in size rather than the actual graph and I don't know how to target just the graphs themself to make size bigger. Is there a way around this?

Plotly's domain is used for subplots. In your case you are plotting three individual plots one after the other and for each you are setting the domain separately.
You have at least two options:
Use the approach you are using now, i.e. 3 individual plots, and use CSS to define their position
Create one plot with three figures and use domain to adjust their position.
Option 1
import dash
import flask
import dash_html_components as html
import plotly.graph_objs as go
import dash_core_components as dcc
server = flask.Flask('app')
app = dash.Dash('app', server=server,
external_stylesheets=['https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css'])
labels = [['monkeys', 'elephants'],
['birds', 'dinosaurs'],
['unicorns', 'giraffes']]
values = [[50, 40],
[100, 10],
[100, 20]]
data = []
for label, value in zip(labels, values):
data.append(html.Div([dcc.Graph(figure={'data': [go.Pie(labels=label,
values=value,
hoverinfo='label+value+percent', textinfo='value'
)]})
], className='col-sm-4'))
app.layout = html.Div(data, className='row')
app.run_server()
Option 2
import dash
import flask
import dash_html_components as html
import plotly.graph_objs as go
import dash_core_components as dcc
server = flask.Flask('app')
app = dash.Dash('app', server=server)
labels = [['monkeys', 'elephants'],
['birds', 'dinosaurs'],
['unicorns', 'giraffes']]
values = [[50, 40],
[100, 10],
[100, 20]]
data = []
x1 = 0
x2 = 0.25
for label, value in zip(labels, values):
data.append(go.Pie(labels=label,
values=value,
hoverinfo='label+value+percent', textinfo='value',
domain={'x': [x1, x2], 'y': [0, 1]}
)
)
x1 = x1 + 0.30
x2 = x1 + 0.25
app.layout = html.Div([
html.Div([dcc.Graph(figure={'data': data})])
])
app.run_server()

Related

Error with Multi Dropdown List in Python Dash

I'm trying to visualize the price development of different financial indices (A, B, C) in an interactive line chart embedded in Python Dash. I want to allow users to select multiple indices and compare them accordingly in the same plot over a specific period of time. At the same time, the plot should also change accordingly when unselecting indices. So far, I was able to plot only one index. The issue I'm having now is that the the plot does not change at all when adding additional indices. I've tried to solve this issue myself for the last couple of hours, but without success, unfortunately.
I'm using Jupyter Notebook. Here's my code with a data sample:
import pandas as pd
import dash
import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Input, Output
import plotly.express as px
data = [['2020-01-31', 100, 100, 100], ['2020-02-28', 101, 107, 99], ['2020-03-31', 104, 109, 193], ['2020-04-30', 112, 115, 94], ['2020-05-31', 112, 120, 189]]
df = pd.DataFrame(data, columns = ['DATE', 'A', 'B', 'C'])
df = df.set_index('DATE')
df
# create the Dash app
app = dash.Dash()
# set up app layout
app.layout = html.Div(children=[
html.H1(children='Index Dashboard'),
dcc.Dropdown(id='index-dropdown',
options=[{'label': x, 'value': x}
for x in df.columns],
value='A',
multi=True, clearable=True),
dcc.Graph(id='price-graph')
])
# set up the callback function
#app.callback(
Output(component_id='price-graph', component_property='figure'),
[Input(component_id='index-dropdown', component_property='value')]
)
def display_time_series(selected_index):
filtered_index = [df.columns == selected_index]
fig = px.line(df, x=df.index, y=selected_index,
labels={'x', 'x axis label'})
fig.update_layout(
title="Price Index Development",
xaxis_title="Month",
yaxis_title="Price",
font=dict(size=13))
return fig
# Run local server
if __name__ == '__main__':
app.run_server(debug=True, use_reloader=False)
As I'm relatively new to Python Dash, any help or advice would be extremely appreciated!
You're not applying your filter inside your callback to your data and the filter itself doesn't work.
Instead you can do something like this:
#app.callback(
Output(component_id="price-graph", component_property="figure"),
[Input(component_id="index-dropdown", component_property="value")],
)
def display_time_series(selected_index):
dff = df[selected_index] # Only use columns selected in dropdown
fig = px.line(dff, x=df.index, y=selected_index, labels={"x", "x axis label"})
fig.update_layout(
title="Price Index Development",
xaxis_title="Month",
yaxis_title="Price",
font=dict(size=13),
)
return fig

Python Dash graph legend covering x-axis labels

My Python web app has a Plotly Dash "Graph" whose legend covers the x-axis labels. I've tried adjusting the following elements, with no success and no visible changes at all:
legend style 'margin-top'
margin 'b'
padding 'b'
Here's the code:
import dash
import dash_core_components as dcc
import dash_html_components as html
graph = dcc.Graph(
figure = {
'data': data,
'layout': dict(
hovermode = "closest",
height = 400, # 500 is a bit too big on a smartphone
legend = dict(
font=dict(color='#7f7f7f'),
orientation="h", # Looks much better horizontal than vertical
style={'margin-top': 100},
),
font = {
'family': 'Segoe UI',
'color': "#7f7f7f"
},
# Added more margin on the left side to fix the cutoff True/False labels on the booleans
margin = dict(l=40, r=25, b=10, t=10),
padding = dict(l=0, r=0, b=10, t=0),
)
}
)
Here's what it looks like, showing the legend overlapping the x-axis labels:
I found the solution here in the documentation.
y
Parent: layout.legend
Type: number between or equal to -2 and 3
Sets the y position (in normalized coordinates) of the legend. Defaults to "1" for
vertical legends, defaults to "-0.1" for horizontal legends on graphs w/o range sliders and defaults to "1.1" for horizontal legends on graph with one or multiple range sliders.
It defaults to -0.1 so I set it to -0.15, which is a little bit lower, to give the x-axis labels some more room.
import dash
import dash_core_components as dcc
import dash_html_components as html
graph = dcc.Graph(
figure = {
'data': data,
'layout': dict(
hovermode = "closest",
height = 400, # 500 is a bit too big on a smartphone
legend = dict(
font=dict(color='#7f7f7f'),
orientation="h", # Looks much better horizontal than vertical
y=-0.15
),
)
}
)
Result:

Accessing state of traces in Plotly Dash

I'm using Plotly Dash to build a stacked bar chart with 3 trace values.
I'm trying to access the state of the trace values so that I can filter a dataframe and pass the resulting DF back to the plot, as opposed to simply hiding the traces on de-select.
for example, I have a dataframe :
Item Status Value
1 First 2000
1 Second 3490
1 Third 542
2 First 641
2 Second 564
3 First 10
My traces are 3 values (first, Second, Third) pertaining to a linear process where each value is a status marking the advancement of an item.
My intention is to be able to select statuses from further down the progression so only those items that have advanced to a certain step are plotted.
As I select more advanced statuses in the trace legend, my plotted x-values should drop off since fewer advance that far, even though they all share the majority of the statuses
The only solution I can think of is to make checkboxes for each trace value and use those inputs in a callback, but that seems redundant to the select/de-select traces functionality built in.
You looking for something like that?
Code:
import dash
from dash.dependencies import Output, Input
import dash_core_components as dcc
import dash_html_components as html
import plotly
import plotly.graph_objs as go
import pandas as pd
app = dash.Dash(__name__)
df = pd.DataFrame({'Item': [1, 1, 1, 2, 2, 3],
'Status': ["First", "Second", "Third",
"First", "Second", "First"],
'Value': [2000, 3490, 542, 641, 564, 10]})
colors = {
'background': '#111111',
'background2': '#FF0',
'text': '#7FDBFF'
}
df1 = df.loc[df["Status"] == "First"]
df2 = df.loc[df["Status"] == "Second"]
df3 = df.loc[df["Status"] == "Third"]
trace1 = go.Bar(
x=df1["Item"],
y=df1["Value"],
name='First',
)
trace2 = go.Bar(
x=df2["Item"],
y=df2["Value"],
name='Second',
)
trace3 = go.Bar(
x=df3["Item"],
y=df3["Value"],
name='Third',
)
app.layout = html.Div(children=[
html.Div([
html.H5('Your Plot'),
dcc.Graph(
id='cx1',
figure=go.Figure(data=[trace1, trace2, trace3],
layout=go.Layout(barmode='stack')))],)])
if __name__ == '__main__':
app.run_server(debug=True)
Output:

Remove point outlines in scatter3d plot points

I am working on a python dash app. I have created a 3d scatter plot based on a dataframe df. The points on the plot all have white outlines, and when they are clustered tightly, the outlines make it look messy. Is there a way to remove the outlines?
import plotly.plotly as py
import plotly.graph_objs as go
import pandas as pd
df = pd.read_csv("./data.csv")
data = [
go.Scatter3d(
x=df[x_axis],
y=df[y_axis],
z=df[z_axis],
mode='markers',
marker=dict(size=df['size_col']),
)
]
layout = go.Layout(
scene=dict(xaxis={'title': 'x'},
yaxis={'title': 'y'},
zaxis={'title': 'z'}),
margin={'l': 60, 'b': 40, 't': 10, 'r': 10},
legend={'x': 0, 'y': 1},
hovermode='closest'
)
fig = go.Figure(data=data, layout=layout)
py.iplot(fig, filename='simple-3d-scatter')
This is what it currently looks like for me: 3d scatter plot
It should be possible because when looking at https://plot.ly/python/3d-scatter-plots/#3d-scatter-plot-with-colorscaling, the plot does not have these white outlines.
Marker objects have their own line attributes.
data = [
go.Scatter3d(
x=df[x_axis],
y=df[y_axis],
z=df[z_axis],
mode='markers',
marker=dict(
size=df['size_col'],
line=dict(width=0)
),
)
]

Plotly: How to select graph source using dropdown?

I'm trying to embed multiple, selectable graphs in a single figure using Plotly, using a dropdown figure. I followed the dropdown example from Plotly, but they only show how to change graph characteristics (like visible, or type), not the underlying data. In my situation, I have a static X-axis and want to change the Y-values. Here's a minimal working example that can be run in a jupyter notebook:
import plotly
from plotly import graph_objs as go, offline as po, tools
po.init_notebook_mode()
import numpy as np
import json
x = list(np.linspace(-np.pi, np.pi, 100))
values_1 = list(np.sin(x))
values_2 = list(np.tan(x))
line = go.Scatter(
x=x,
y=values_1
)
updatemenus = [
{
'buttons': [
{
'method': 'restyle',
'label': 'Val 1',
'args': [
{'y': json.dumps(values_1)},
]
},
{
'method': 'restyle',
'label': 'Val 2',
'args': [
{'y': json.dumps(values_2)},
]
}
],
'direction': 'down',
'showactive': True,
}
]
layout = go.Layout(
updatemenus=updatemenus,
)
figure = go.Figure(data=[line], layout=layout)
po.iplot(figure)
However, while the approach seems to work like advertised for general graph attributes (like 'visible'), when I use 'y', it produces a straight line, where y goes from 0 to len(y), instead of the actual data I gave it. Here are images of the initial render, and then what happens when I select the dropdown item for the Tan(X) graph, then go back to the Sin(X):
How do I embed the data for multiple graphs into a single figure so that the user can select which one they want to view?
Updated answer using graph_objects:
As of version 4, you don't have to worry about offline versus online functionality. So drop the from plotly import graph_objs as go, offline as po and po.init_notebook_mode(), and just use import plotly.graph_objects as go. I've updated my original answer with a complete code snippet that shows the whole approach with multiple traces using plotly.graph_objects at the end. The solution to the question as it still stands will still be the same, namely:
'y' in updatemenus does not take a single list as an argument, but rather a list of lists like in 'y' = [values_1] where values_1 is a list in itself. So just replace your lines
{'y': json.dumps(values_1)}, and {'y': json.dumps(values_2)},
with
{'y': [values_1]}, and {'y': [values_2]},
to get these plots for the different options Val 1 and Val 2:
Some Details:
Values_1 is, unsurprisingly, a list of length 100 where each element is of type numpy.float. Replacing json.dumps(values_1) with values_1, and json.dumps(values_2) with values_2 will render the same plots as in your question. The reason why these plots are just straight lines, seems to be that it's the length of your lists that are being plotted, and not the values contained in that list. Or something to that effect.
Setting 'y' = values_1 is the same thing as assigning a single list to 'y'. But 'y' in updatemenus does not take a single list as an argument, but rather a list of lists like in 'y' = [values_1]. Why? Because you might want to plot multiple lists in the same figure like 'y' = [values_1, values_1b]. Have a look:
Plot for dropdown option Var 1:
Plot for dropdown option Var 2
Complete original code:
import plotly
from plotly import graph_objs as go, offline as po, tools
po.init_notebook_mode()
import numpy as np
import json
x = list(np.linspace(-np.pi, np.pi, 100))
values_1 = list(np.sin(x))
values_1b = [elem*-1 for elem in values_1]
values_2 = list(np.tan(x))
values_2b = [elem*-1 for elem in values_2]
line = go.Scatter(
x=x,
y=values_1
)
line2 = go.Scatter(
x=x,
y=values_1b
)
updatemenus = [
{
'buttons': [
{
'method': 'restyle',
'label': 'Val 1',
'args': [
{'y': [values_1, values_1b]},
]
},
{
'method': 'restyle',
'label': 'Val 2',
'args': [
{'y': [values_2, values_2b]},
]
}
],
'direction': 'down',
'showactive': True,
}
]
layout = go.Layout(
updatemenus=updatemenus,
)
figure = go.Figure(data=[line, line2], layout=layout)
po.iplot(figure)
Complete updated code:
# imports
import plotly.graph_objects as go
import numpy as np
# data
x = list(np.linspace(-np.pi, np.pi, 100))
values_1 = list(np.sin(x))
values_1b = [elem*-1 for elem in values_1]
values_2 = list(np.tan(x))
values_2b = [elem*-1 for elem in values_2]
# plotly setup]
fig = go.Figure()
# Add one ore more traces
fig.add_traces(go.Scatter(x=x, y=values_1))
fig.add_traces(go.Scatter(x=x, y=values_1b))
# construct menus
updatemenus = [{'buttons': [{'method': 'update',
'label': 'Val 1',
'args': [{'y': [values_1, values_1b]},]
},
{'method': 'update',
'label': 'Val 2',
'args': [{'y': [values_2, values_2b]},]}],
'direction': 'down',
'showactive': True,}]
# update layout with buttons, and show the figure
fig.update_layout(updatemenus=updatemenus)
fig.show()
Plot with version 4 default layout:

Categories

Resources