I'd like to concatenate two charts and then beautify the resulting combined chart (add some nice background). One important thing here is try to preserve titles for both charts.
When I try to do that, I either get the beautified combined chart with only one title or an error: ValueError: Objects with "background" attribute cannot be used within HConcatChart. Consider defining the background attribute in the HConcatChart object instead.
Here are some dummy code snippets of what I've tried.
Try #1 which yields only one title:
import altair as alt
from vega_datasets import data
source = data.cars()
line = alt.Chart(source).mark_line().encode(
x='Year',
y='mean(Miles_per_Gallon)'
)
band = alt.Chart(source).mark_errorband(extent='ci').encode(
x='Year',
y=alt.Y('Miles_per_Gallon', title='Miles/Gallon'),
)
combined = band | line
combined
combined.properties(background = '#f9f9f9',
title = alt.TitleParams(text = 'General title',
subtitle = ['Subtitle'],
font = 'Ubuntu Mono',
fontSize = 22,
color = '#3E454F',
subtitleFont = 'Ubuntu Mono',
subtitleFontSize = 16,
subtitleColor = '#3E454F')
)
Try #2 which yields a value error:
line2 = line.properties(background = '#f9f9f9',
title = alt.TitleParams(text = 'General title 1',
subtitle = ['Subtitle'],
font = 'Ubuntu Mono',
fontSize = 22,
color = '#3E454F',
subtitleFont = 'Ubuntu Mono',
subtitleFontSize = 16,
subtitleColor = '#3E454F')
)
band2 = band.properties(background = '#f9f9f9',
title = alt.TitleParams(text = 'General title 2',
subtitle = ['Subtitle'],
font = 'Ubuntu Mono',
fontSize = 22,
color = '#3E454F',
subtitleFont = 'Ubuntu Mono',
subtitleFontSize = 16,
subtitleColor = '#3E454F')
)
line2 | band2
Is there a way to achieve what I want? Or Altair doesn't allow this yet?
You can specify the titles on the individual charts, and the background on the combined chart:
line2 = line.properties(
title = alt.TitleParams(text = 'General title 1',
subtitle = ['Subtitle'],
font = 'Ubuntu Mono',
fontSize = 22,
color = '#3E454F',
subtitleFont = 'Ubuntu Mono',
subtitleFontSize = 16,
subtitleColor = '#3E454F')
)
band2 = band.properties(
title = alt.TitleParams(text = 'General title 2',
subtitle = ['Subtitle'],
font = 'Ubuntu Mono',
fontSize = 22,
color = '#3E454F',
subtitleFont = 'Ubuntu Mono',
subtitleFontSize = 16,
subtitleColor = '#3E454F')
)
combined = band2 | line2
combined.properties(background = '#f9f9f9')
Related
I am coding for 20+ tabs to plot similar parameters and have been writing the styling for each figure separately. Is there a way to set the styling all at once for all figures?
p = figure(tools=TOOLS, x_axis_type='datetime',plot_height=400, plot_width=700,
outline_line_color = 'gray',
y_axis_label = 'Volts',
y_range = DataRange1d()
)
# Setting the second y axis range name and range
#p.extra_y_ranges = {"foo": Range1d(start=0, end=0.000006)}
p.extra_y_ranges = {"foo": DataRange1d()}
# Adding the second axis to the plot.
p.add_layout(LinearAxis(y_range_name="foo"), 'right')
a1=p.line(x='Time', y='340', line_color="darkcyan", line_width=1, source=source)
a11 = p.line(x='Time',y='StdDev', line_color = 'red', line_width=1, y_range_name="foo", source=source)
p.y_range.renderers=[a1]
p.extra_y_ranges['foo'].renderers = [a11]
tooltips=[( "Time", "#Time{%H:%M:%S}"),
("Y-value", "$y")]
formatt ={'Time':'datetime'}
p.add_tools(HoverTool(tooltips=tooltips, formatters=formatt, mode = 'mouse'))
p.title.text = "Plot Title "
p.title.text_color = "gray"
p.title.text_font = "arial"
p.title.text_font_style = "bold"
p.xgrid[0].grid_line_color=None
p.ygrid[0].grid_line_alpha=0.5
p.xaxis.axis_label = 'TimeStamp'
Following my way, I would essentially need to repeat above code 20+ times for each tab.
I have tried to re-create the following example Towards Data Science Example shown on the web
I have written the following code which I modified to this:
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import pandas as pd
import plotly.graph_objs as go
# Step 1. Launch the application
app = dash.Dash()
# Step 2. Import the dataset
filepath = 'https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv'
st = pd.read_csv(filepath)
# range slider options
st['Date'] = pd.to_datetime(st.Date)
dates = ['2015-02-17', '2015-05-17', '2015-08-17', '2015-11-17',
'2016-02-17', '2016-05-17', '2016-08-17', '2016-11-17', '2017-02-17']
features = st.columns[1:-1]
opts = [{'label' : i, 'value' : i} for i in features]
# Step 3. Create a plotly figure
trace_1 = go.Scatter(x = st.Date, y = st['AAPL.High'],
name = 'AAPL HIGH',
line = dict(width = 2,
color = 'rgb(229, 151, 50)'))
layout = go.Layout(title = 'Time Series Plot',
hovermode = 'closest')
fig = go.Figure(data = [trace_1], layout = layout)
# Step 4. Create a Dash layout
app.layout = html.Div([
# a header and a paragraph
html.Div([
html.H1("This is my first dashboard"),
html.P("Dash is so interesting!!")
],
style = {'padding' : '50px' ,
'backgroundColor' : '#3aaab2'}),
# adding a plot
dcc.Graph(id = 'plot', figure = fig),
# dropdown
html.P([
html.Label("Choose a feature"),
dcc.Dropdown(
id='opt',
options=opts,
value=features[0],
multi=True
),
# range slider
html.P([
html.Label("Time Period"),
dcc.RangeSlider(id = 'slider',
marks = {i : dates[i] for i in range(0, 9)},
min = 0,
max = 8,
value = [1, 7])
], style = {'width' : '80%',
'fontSize' : '20px',
'padding-left' : '100px',
'display': 'inline-block'})
])
])
# Step 5. Add callback functions
#app.callback(Output('plot', 'figure'),
[Input('opt', 'value'),
Input('slider', 'value')])
def update_figure(input1, input2):
# filtering the data
st2 = st[(st.Date > dates[input2[0]]) & (st.Date < dates[input2[1]])]
# updating the plot
trace_1 = go.Scatter(x = st2.Date, y = st2['AAPL.High'],
name = 'AAPL HIGH',
line = dict(width = 2,
color = 'rgb(229, 151, 50)'))
trace_2 = go.Scatter(x = st2.Date, y = st2[input1],
name = str(input1),
line = dict(width = 2,
color = 'rgb(106, 181, 135)'))
fig = go.Figure(data = [trace_1, trace_2], layout = layout)
return fig
# Step 6. Add the server clause
if __name__ == '__main__':
app.run_server(debug = True)
When I change the feature input, it does not update the plot correctly and does not show the selected features in the plot.
Either there is something wrong with the callback function or the initialization of the graph with the second trace. But I cant figure out where the issue is.
As you are only providing two scatter traces within your callback. From both, one is static for 'AAPL.High'. So you need to limit the dropdown values to Multi=False.
Valid plots are only generated for choosing options like 'AAPL.LOW' and others like dic won't display a second trace. The callback wouldn't terminate if you would keepmulti=True the callback would stil work, if always only one option is selected. The moment you select two or more options the script will fail as it would try to find faulty data for the data return block here:
trace_2 = go.Scatter(x = st2.Date, y = st2[**MULTIINPUT**],
name = str(input1),
line = dict(width = 2,
color = 'rgb(106, 181, 135)'))
Only one column id is allowed to be passed at MULTIINPUT. If you want to introduce more traces please use a for loop.
Change the code to the following:
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import pandas as pd
import plotly.graph_objs as go
# Step 1. Launch the application
app = dash.Dash()
# Step 2. Import the dataset
filepath = 'https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv'
st = pd.read_csv(filepath)
# range slider options
st['Date'] = pd.to_datetime(st.Date)
dates = ['2015-02-17', '2015-05-17', '2015-08-17', '2015-11-17',
'2016-02-17', '2016-05-17', '2016-08-17', '2016-11-17', '2017-02-17']
features = st.columns
opts = [{'label' : i, 'value' : i} for i in features]
# Step 3. Create a plotly figure
trace_1 = go.Scatter(x = st.Date, y = st['AAPL.High'],
name = 'AAPL HIGH',
line = dict(width = 2,
color = 'rgb(229, 151, 50)'))
layout = go.Layout(title = 'Time Series Plot',
hovermode = 'closest')
fig = go.Figure(data = [trace_1], layout = layout)
# Step 4. Create a Dash layout
app.layout = html.Div([
# a header and a paragraph
html.Div([
html.H1("This is a Test Dashboard"),
html.P("Dash is great!!")
],
style = {'padding' : '50px' ,
'backgroundColor' : '#3aaab2'}),
# adding a plot
dcc.Graph(id = 'plot', figure = fig),
# dropdown
html.P([
html.Label("Choose a feature"),
dcc.Dropdown(
id='opt',
options=opts,
value=features[0],
multi=False
),
# range slider
html.P([
html.Label("Time Period"),
dcc.RangeSlider(id = 'slider',
marks = {i : dates[i] for i in range(0, 9)},
min = 0,
max = 8,
value = [1, 7])
], style = {'width' : '80%',
'fontSize' : '20px',
'padding-left' : '100px',
'display': 'inline-block'})
])
])
# Step 5. Add callback functions
#app.callback(Output('plot', 'figure'),
[Input('opt', 'value'),
Input('slider', 'value')])
def update_figure(input1, input2):
# filtering the data
st2 = st#[(st.Date > dates[input2[0]]) & (st.Date < dates[input2[1]])]
# updating the plot
trace_1 = go.Scatter(x = st2.Date, y = st2['AAPL.High'],
name = 'AAPL HIGH',
line = dict(width = 2,
color = 'rgb(229, 151, 50)'))
trace_2 = go.Scatter(x = st2.Date, y = st2[input1],
name = str(input1),
line = dict(width = 2,
color = 'rgb(106, 181, 135)'))
fig = go.Figure(data = [trace_1, trace_2], layout = layout)
return fig
# Step 6. Add the server clause
if __name__ == '__main__':
app.run_server(debug = True)
I hope this cleared things up and solved your issues. :)
I am trying to achieve what is done here: https://www.quantalys.com/Fonds/120955 with javascript in python plotly. I want to add the hover vertical line and the red annotation on the x axis. I have done some searching on goolgle but I couldn't find the the answer I'm looking for. My current chart looks like this:
trace1 = go.Scatter(
x = df1.x,
y = df1.y,
name = "M&G OPTIMAL INCOME FD EUR AH ACC",
hoverinfo= 'name',
opacity=0.7,
mode = 'lines',
line = dict(
color = ('rgb(2, 12, 245)'),
width = 1,
),
)
trace2 = go.Scatter(
x = df2.x,
y = df2.y,
opacity=0.7,
name = "Alloc Flexible Prudent Monde",
hoverinfo= 'name',
mode = 'lines',
line = dict(
color = ('rgb(67, 45, 24)'),
width = 1,
)
)
trace3 = go.Scatter(
x = df3.x,
y = df3.y,
name = "25% MSCI World + 75% ML Global",
hoverinfo= 'name',
mode = 'lines',
opacity=0.7,
line = dict(
color = ('rgb(205, 12, 24)'),
width = 1,
)
)
layout = go.Layout(
xaxis=dict(
showline=True,
showgrid=True,
showticklabels=True,
linecolor='rgb(204, 204, 204)',
linewidth=2,
mirror=True,
),
yaxis=dict(
showline=True,
showgrid=True,
showticklabels=True,
linecolor='rgb(204, 204, 204)',
linewidth=2,
mirror=True,
),
showlegend=True,
)
data= [trace1, trace2,trace3]
fig = dict(data=data, layout=layout)
iplot(fig, filename='line-mode')
Add this to your layout definition.
showlegend = True,
hovermode = 'x'
Add this to your xaxis definition.
showspikes = True,
spikemode = 'across',
spikesnap = 'cursor',
showline=True,
showgrid=True,
...
And add this to your layout definition:
spikedistance = -1,
xaxis=dict(...
Please refer to this post and the documentation by plotly. :)
EDIT
You ask for the x-axis lable. Please use
spikemode = 'across+toaxis'
Additionally I would suggest to use
spikedash = 'solid'
because it is better fitting your example.
I have three plots based on the same dataset. How can I link all three plots so that when I select a certain species in vbar plot, two scatter plot also change to plot points in that species only.
any help is appreciated~
from bokeh.sampledata.iris import flowers
from bokeh.plotting import figure, output_file, show
from bokeh.models import ColumnDataSource, CategoricalColorMapper
from bokeh.layouts import column, row
#color mapper to color data by species
mapper = CategoricalColorMapper(factors = ['setosa','versicolor', 'virginica'],\
palette = ['green', 'blue', 'red'])
output_file("plots.html")
#group by species and plot barplot for count
species = flowers.groupby('species')
source = ColumnDataSource(species)
p = figure(plot_width = 800, plot_height = 400, title = 'Count by Species', \
x_range = source.data['species'], y_range = (0,60),tools = 'box_select')
p.vbar(x = 'species', top = 'petal_length_count', width = 0.8, source = source,\
nonselection_fill_color = 'gray', nonselection_fill_alpha = 0.2,\
color = {'field': 'species', 'transform': mapper})
labels = LabelSet(x='species', y='petal_length_count', text='petal_length_count',
x_offset=5, y_offset=5, source=source)
p.add_layout(labels)
#scatter plot for sepal length and width
source1 = ColumnDataSource(flowers)
p1 = figure(plot_width = 800, plot_height = 400, tools = 'box_select', title = 'scatter plot for sepal')
p1.circle(x = 'sepal_length', y ='sepal_width', source = source1, \
nonselection_fill_color = 'gray', nonselection_fill_alpha = 0.2, \
color = {'field': 'species', 'transform': mapper})
#scatter plot for petal length and width
p2 = figure(plot_width = 800, plot_height = 400, tools = 'box_select', title = 'scatter plot for petal')
p2.circle(x = 'petal_length', y ='petal_width', source = source1, \
nonselection_fill_color = 'gray', nonselection_fill_alpha = 0.2, \
color = {'field': 'species', 'transform': mapper})
#show all three plots
show(column(p, row(p1, p2)))
I don't think there's some functionality existing for this at the moment. But you can explicitly link two ColumnDataSources with a CustomJS callback:
from bokeh.models import CusomJS
source = ColumnDataSource(species)
source1 = ColumnDataSource(flowers)
source.js_on_change('selected', CustomJS(args=dict(s1=source1), code="""
const indices = cb_obj.selected['1d'].indices;
const species = new Set(indices.map(i => cb_obj.data.species[i]));
s1.selected['1d'].indices = s1.data.species.reduce((acc, s, i) => {if (species.has(s)) acc.push(i); return acc}, []);
s1.select.emit();
"""))
Note that this callback only synchronizes selection from the bar plot to the scatter plots. To make selections on the scatter plots influence the bar plot, you'll have to write some additional code.
Currently written this code that produces a bar chart but would like to add a threshold line. Could anyone help me please?
def make_bar_chart(data):
"""Takes a list of dicts with a time and price"""
# Times
chart_x = []
# Prices
chart_y = []
# Create the relevant arrays
for item in data:
chart_x.append(item["time"])
chart_y.append(item["price"])
# Make the chart
the_graph = Bar(x = chart_x, y = chart_y , name = "Stocks")
graph_data = Data([the_graph])
the_layout = Layout(title = "Stocks", xaxis = dict(title = "Time"), yaxis = dict(title = "Price"))
the_figure = Figure(data = graph_data, layout = the_layout)
plotly.offline.plot(the_figure, filename = "stocks.html")
Try something like this. In plotly it seems that lines are provided via shapes.
the_layout = Layout(title = "Stocks",
xaxis = dict(title = "Time"),
yaxis = dict(title = "Price"),
shapes=[
{
'type': 'line',
'xref': 'paper',
'x0': 0,
'y0': 100, # use absolute value or variable here
'x1': 1,
'y1': 100, # ditto
'line': {
'color': 'rgb(50, 171, 96)',
'width': 1,
'dash': 'dash',
},
},
],
)
I haven't tested this as you haven't provided sample data. Well done for supplying code on your first question, but on Stack Overflow it's best to provide a completely self-contained example that people can copy and run 'as is.'