Related
I am trying to generate a chart with a secondary x-axis, but I can't get the secondary x-axis to be added to the chart.
Below is the code I'm using. If I change "x2_axis" to "y2_axis" and "set_x2_axis" to "set_y2_axis", then I am able to create a secondary y axis successfully -- but it does not work for a secondary x axis. Am I doing something wrong?
import xlsxwriter
workbook = xlsxwriter.Workbook('test.xlsx')
worksheet = workbook.add_worksheet()
data = [
[1, 2, 3, 4, 5],
[10, 40, 50, 20, 10],
[1,1,2,2,3,3,4,4,5,5],
[200,200,100,100,300,300,250,250,350,350]
]
worksheet.write_column('A2', data[0])
worksheet.write_column('B2', data[1])
worksheet.write_column('C2', data[2])
worksheet.write_column('D2', data[3])
chart= workbook.add_chart({'type': 'line'})
chart.add_series ({
'name': 'Primary',
'categories': '=Sheet1!$A$2:$A$6',
'values': '=Sheet1!$B$2:$B$6',
})
chart.add_series ({
'name': 'Secondary',
'categories': '=Sheet1!$C$2:$C$11',
'values': '=Sheet1!$D$2:$D$11',
'x2_axis': True
})
chart.set_x_axis({
'name': 'Primary Axis',
'interval_unit': 1,
'interval_tick': 1,
'major_tick_mark': 'none',
})
chart.set_y_axis({
'name': 'Value',
})
chart.set_x2_axis({
'label_position': 'low',
'name': 'Secondary Axis',
'visible': True
})
worksheet.insert_chart('B20', chart)
workbook.close()
Setting a secondary X axis in Excel (or XlsxWriter) isn't obvious, in comparison to setting a secondary Y axis. Generally, you need to add a secondary Y and X axis pair before you can set a secondary X axis. Something like this:
import xlsxwriter
workbook = xlsxwriter.Workbook('test.xlsx')
worksheet = workbook.add_worksheet()
data = [
[1, 2, 3, 4, 5],
[10, 40, 50, 20, 10],
[1, 1, 2, 2, 3, 3, 4, 4, 5, 5],
[200, 200, 100, 100, 300, 300, 250, 250, 350, 350]
]
worksheet.write_column('A2', data[0])
worksheet.write_column('B2', data[1])
worksheet.write_column('C2', data[2])
worksheet.write_column('D2', data[3])
chart = workbook.add_chart({'type': 'line'})
chart.add_series({
'name': 'Primary',
'categories': '=Sheet1!$A$2:$A$6',
'values': '=Sheet1!$B$2:$B$6',
})
chart.add_series({
'name': 'Secondary',
'categories': '=Sheet1!$C$2:$C$11',
'values': '=Sheet1!$D$2:$D$11',
'x2_axis': True,
'y2_axis': True,
})
chart.set_x_axis({
'name': 'Primary Axis',
'interval_unit': 1,
'interval_tick': 1,
'major_tick_mark': 'none',
})
chart.set_y_axis({
'name': 'Y Values 1',
})
chart.set_y2_axis({
'name': 'Y Values 2',
'crossing': 'max',
})
chart.set_x2_axis({
'label_position': 'high',
'name': 'Secondary Axis',
'visible': True,
})
worksheet.insert_chart('B20', chart)
workbook.close()
Output:
I have 3 bar charts with separated data-frames and x,y labels. I can not use make_subplot tool since it is compatible with graph_object instance, not with express.bar. In this case, I've read documentations about facet_row(facet_col) properties which plots bars in one figure but it does not fit to my case. I literally want 3 different figures in one page/window.
I create bar charts as below:
import plotly.express as px
x = ['one', 'two', 'three']
y = [1, 2, 3]
dataframe1 = {
"x_axis_1": x,
"y_axis_1": y
}
fig1 = px.bar(dataframe1, x="x_axis_1", y="y_axis_1")
fig1.update_xaxes(type='category')
Thank you for any idea in advance!
As you mentioned the add_traces expects us to input instances of trace classes from the plotly.graph_objects package (e.g plotly.graph_objects.Scatter, plotly.graph_objects.Bar) (see here)
However since you do not want to use graph_objects we have to find a workaround
Each fig that you create using plotly express has 2 parts : data and layout
For example for your bar chart, if I do:
print (fig1)
>>>
Figure({
'data': [{'alignmentgroup': 'True',
'hovertemplate': 'x_axis_1=%{x}<br>y_axis_1=%{y}<extra></extra>',
'legendgroup': '',
'marker': {'color': '#636efa'},
'name': '',
'offsetgroup': '',
'orientation': 'v',
'showlegend': False,
'textposition': 'auto',
'type': 'bar',
'x': array(['one', 'two', 'three'], dtype=object),
'xaxis': 'x',
'y': array([1, 2, 3], dtype=int64),
'yaxis': 'y'}],
'layout': {'barmode': 'relative',
'legend': {'tracegroupgap': 0},
'margin': {'t': 60},
'template': '...',
'xaxis': {'anchor': 'y', 'domain': [0.0, 1.0], 'title': {'text': 'x_axis_1'}},
'yaxis': {'anchor': 'x', 'domain': [0.0, 1.0], 'title': {'text': 'y_axis_1'}}}
})
If we check the data parameter its a list of plotly graph_object classes:
print (fig1['data'][0])
>>>
Bar({
'alignmentgroup': 'True',
'hovertemplate': 'x_axis_1=%{x}<br>y_axis_1=%{y}<extra></extra>',
'legendgroup': '',
'marker': {'color': '#636efa'},
'name': '',
'offsetgroup': '',
'orientation': 'v',
'showlegend': False,
'textposition': 'auto',
'x': array(['one', 'two', 'three'], dtype=object),
'xaxis': 'x',
'y': array([1, 2, 3], dtype=int64),
'yaxis': 'y'
})
print(type(fig1['data'][0]))
>>>
<class 'plotly.graph_objs._bar.Bar'>
So basically we have to extract this out from the plotly express figure and pass it to add_traces for it to work
The complete solution
Generate some data:
x1 = ['one', 'two', 'three']
y1 = [1, 2, 3]
x2 = ['five', 'six', 'seven']
y2 = [5, 6, 7]
x3 = ['eight', 'nine', 'ten']
y3 = [8, 9, 10]
dataframe1 = {
"x_axis_1": x,
"y_axis_1": y
}
dataframe2 = {
"x_axis_2": x2,
"y_axis_2": y2
}
dataframe3 = {
"x_axis_3": x3,
"y_axis_3": y3
}
Generate the plot:
from plotly.subplots import make_subplots
fig = make_subplots(rows=3, cols=1)
fig1 = px.bar(dataframe1, x="x_axis_1", y="y_axis_1")
fig2 = px.bar(dataframe2, x="x_axis_2", y="y_axis_2")
fig3 = px.bar(dataframe3, x="x_axis_3", y="y_axis_3")
fig.add_trace(fig1['data'][0], row=1, col=1)
fig.add_trace(fig2['data'][0], row=2, col=1)
fig.add_trace(fig3['data'][0], row=3, col=1)
fig.show()
Output:
As you can see by querying the data key from the plotly express figure, we get the required format we need to pass to the add_traces method.
I created a bullet chart with a negative and positive dimension in plotly.go. However, when plotting my bar it always starts from -1. Is there a way to set the starting point at zero, so it can align in both dimensions from there?
Reproducable example:
act = 0.123
avg = 0.13
before = 0.15
fig = go.Figure(go.Indicator(
mode="number+gauge+delta", value=act,
domain={'x': [0.1, 1], 'y': [0, 1]},
title={'text': "<b>S-Score</b>"},
delta={'reference': before},
gauge={
'shape': "bullet",
'tick0':0,
'axis': {'range': [-1, 1]},
'threshold': {
'line': {'color': "white", 'width': 2},
'thickness': 0.75, 'value': avg},
'steps': [
{'range': [-1, 0], 'color': "#ff6666"},
{'range': [0, 1], 'color': "#89ac76"}
],
'bar': {'color': "grey"}}))
Actual Output:
Output I want:
I've done a lot of research and haven't found a solution. I propose a trick approach and a proposal to change the x-axis. This is a bit far from the answer you expect.
import plotly.graph_objects as go
act = 0.123
avg = 0.13
before = 0.15
fig = go.Figure(go.Indicator(
mode = "number+gauge+delta", value = act,
domain = {'x': [0.1, 1], 'y': [0, 1]},
title = {'text' :"<b>S-Score</b>"},
delta = {'reference': before},
gauge = {
'shape': "bullet",
'axis': {'range': [-1, 1]},
'threshold': {
'line': {'color': "white", 'width': 2},
'thickness': 0.75,
'value': avg},
'steps': [
{'range': [-1, 0], 'color': "#ff6666"},
{'range': [0, 1], 'color': "#89ac76"}],
'bar': {'color':'#ff6666'}
}))
fig.update_layout(height = 250)
fig.show()
import plotly.graph_objects as go
act = 0.123
avg = 0.13
before = 0.15
fig = go.Figure(go.Indicator(
mode = "number+gauge+delta", value = act,
domain = {'x': [0.1, 1], 'y': [0, 1]},
title = {'text' :"<b>S-Score</b>"},
delta = {'reference': before},
gauge = {
'shape': "bullet",
'axis': {'range': [0, 1]},
'threshold': {
'line': {'color': "white", 'width': 2},
'thickness': 0.75,
'value': avg},
'steps': [
{'range': [-1, 0], 'color': "#ff6666"},
{'range': [0, 1], 'color': "#89ac76"}],
'bar': {'color':'grey',
'line': {'color':'#444', 'width':2},
}}))
fig.update_layout(height = 250)
fig.show()
How do I increase the opacity or alpha of the 'filled' area of my plot? I tried:
import pandas as pd
import plotly.offline as py
import plotly.graph_objs as go
import cufflinks as cf
from plotly import tools
plotly.offline.init_notebook_mode()
cf.go_offline()
df = pd.DataFrame(np.random.rand(10, 4), columns=['a', 'b', 'c', 'd'])
df.iplot(kind='area', fill=True, filename='cuflinks/stacked-area', opacity=.1)
but it doesn't seem to work.
There doesn't seem to be an easy built-in way of achieving this. However, a work-around is to first get the figure object of the plot, modify it to change the opacity, and then plot it.
You can get the figure object using the asFigure attribute like this:
figure = df.iplot(asFigure=True, kind='area', fill=True, filename='cuflinks/stacked-area')
The figure object in this case looks like:
Figure({
'data': [{'fill': 'tonexty',
'fillcolor': 'rgba(255, 153, 51, 0.3)',
'line': {'color': 'rgba(255, 153, 51, 1.0)', 'dash': 'solid', 'shape': 'linear', 'width': 1.3},
'mode': 'lines',
'name': 'a',
'text': '',
'type': 'scatter',
'uid': '4dcc1a3e-fba3-4a32-bb2a-40925b4fae5b',
'x': array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=int64),
'y': array([0.91229144, 0.63049138, 0.22855077, 0.13470399, 0.9114691 , 0.39640368,
0.46534334, 0.20508211, 0.00203548, 0.41343938])},
{'fill': 'tonexty',
'fillcolor': 'rgba(55, 128, 191, 0.3)',
'line': {'color': 'rgba(55, 128, 191, 1.0)', 'dash': 'solid', 'shape': 'linear', 'width': 1.3},
'mode': 'lines',
'name': 'b',
'text': '',
'type': 'scatter',
'uid': '1015b30d-7c09-456c-875c-8a211a6ebdeb',
'x': array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=int64),
'y': array([1.81115175, 1.57534372, 0.41288126, 0.38068805, 1.72268856, 0.87778503,
1.32714727, 0.848242 , 0.51605283, 0.58190402])},
{'fill': 'tonexty',
'fillcolor': 'rgba(50, 171, 96, 0.3)',
'line': {'color': 'rgba(50, 171, 96, 1.0)', 'dash': 'solid', 'shape': 'linear', 'width': 1.3},
'mode': 'lines',
'name': 'c',
'text': '',
'type': 'scatter',
'uid': '7d1852ac-b8e7-44e6-ae69-54229d7e2c83',
'x': array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=int64),
'y': array([2.79222081, 1.58812634, 1.1439478 , 1.30453731, 2.50881795, 1.67681961,
1.85609861, 1.36657712, 0.89024486, 0.82749039])},
{'fill': 'tonexty',
'fillcolor': 'rgba(128, 0, 128, 0.3)',
'line': {'color': 'rgba(128, 0, 128, 1.0)', 'dash': 'solid', 'shape': 'linear', 'width': 1.3},
'mode': 'lines',
'name': 'd',
'text': '',
'type': 'scatter',
'uid': '89b85012-fc95-487c-b7ba-9cb6c249b768',
'x': array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=int64),
'y': array([3.54740551, 1.79856232, 2.1326556 , 2.10560567, 2.64867039, 2.55519564,
2.73888819, 2.23274393, 1.16987343, 1.42794202])}],
'layout': {'legend': {'bgcolor': '#F5F6F9', 'font': {'color': '#4D5663'}},
'paper_bgcolor': '#F5F6F9',
'plot_bgcolor': '#F5F6F9',
'title': {'font': {'color': '#4D5663'}},
'xaxis': {'gridcolor': '#E1E5ED',
'showgrid': True,
'tickfont': {'color': '#4D5663'},
'title': {'font': {'color': '#4D5663'}, 'text': ''},
'zerolinecolor': '#E1E5ED'},
'yaxis': {'gridcolor': '#E1E5ED',
'showgrid': True,
'tickfont': {'color': '#4D5663'},
'title': {'font': {'color': '#4D5663'}, 'text': ''},
'zerolinecolor': '#E1E5ED'}}
})
You'll note that each trace in the data has a fillcolor attribute: 'fillcolor': 'rgba(255, 153, 51, 0.3)'. The last number is the alpha value, which you want to modify. I've made a hacky little function to update the fillcolor attribute of all traces in a figure object:
def update_opacity(figure,opacity):
for trace in range(len(figure['data'])):
# print(figure['data'][trace]['fillcolor'],'-> ',end='')
rgba_split = figure['data'][trace]['fillcolor'].split(',')
figure['data'][trace]['fillcolor'] = ','.join(rgba_split[:-1] + [' {})'.format(opacity)])
# print(figure['data'][trace]['fillcolor'])
return figure
For full opacity, you can do:
figure = update_opacity(figure,1)
Then, simply plot the result with
py.iplot(figure)
Output:
I am attempting to adapt the Python Plotly example on 'Adding Sliders to Animations in Python' to a barchart but am getting a 'Figure field is invalid' message.
I am trying to adapt the input data to reflect that of a bar chart rather than a scatter chart (used in the example). I have created a grid:
Which I am using with the following code:
years = ['2007','2008','2009']
items = ['Name_1','Name_2']
col_name_template = '{column}'
for year in years:
frame = {'data': [], 'name': str(year)}
x_list = []
y_list = []
for item in items:
x_list.append(grid.get_column_reference(col_name_template.format(column='name')))
y_list.append(grid.get_column_reference(col_name_template.format(column=year)))
frame['data'].append(go.Bar(
x=x_list,
y=y_list
))
figure['frames'].append(frame)
slider_step = {'args': [
[year],
{'frame': {'duration': 300, 'redraw': False},
'mode': 'immediate',
'transition': {'duration': 300}}
],
'label': year,
'method': 'animate'}
sliders_dict['steps'].append(slider_step)
figure['layout']['sliders'] = [sliders_dict]
py.icreate_animations(figure, 'barchart example')
When trying to plot I get the following error:
Figure field is invalid. Reason: Raw data arrays are not allowed at this endpoint. Use grid references instead. Raw data found at the following paths in the figure...
How do I use only grid references but also ensure that a bar chart is plotted rather than a scatter chart?
I used the offline method of plotting plotly.offline.iplot which doesn't require grid references. The only downside of animations with bar charts is that transitions aren't currently supported.
Code below (including buttons and slider):
from plotly.offline import init_notebook_mode, iplot
from IPython.display import display, HTML
init_notebook_mode(connected = True)
years = ['2010', '2011', '2012']
items = ['A', 'B', 'C', 'D']
count = [
[1, 2, 3, 4],
[2, 3, 4, 1],
[3, 4, 1, 2]
]
figure = {
'data': [{
'type': 'bar',
'x': items,
'y': count[0]
}],
'layout': {
'xaxis': {
'title': 'X',
'gridcolor': '#FFFFFF',
'linecolor': '#000',
'linewidth': 1,
'zeroline': False,
'autorange': False
},
'yaxis': {
'title': 'Y',
'gridcolor': '#FFFFFF',
'linecolor': '#000',
'linewidth': 1,
'range': [0, 5],
'autorange': False
},
'title': 'Example Title',
'hovermode': 'closest',
'updatemenus': [{
'type': 'buttons',
'buttons': [{
'label': 'Play',
'method': 'animate',
'args': [None, {
'frame': {
'duration': 500,
'redraw': True
},
'fromcurrent': True,
'transition': {
'duration': 300,
'easing': 'quadratic-in-out'
}
}]
},
{
'label': 'End',
'method': 'animate',
'args': [None, {
'frame': {
'duration': 0,
'redraw': True
},
'fromcurrent': True,
'mode': 'immediate',
'transition': {
'duration': 0
}
}]
}
],
'direction': 'left',
'pad': {
'r': 10,
't': 87
},
'showactive': False,
'type': 'buttons',
'x': 0.1,
'xanchor': 'right',
'y': 0,
'yanchor': 'top'
}]
},
'frames': []
}
sliders_dict = {
'active': 0,
'yanchor': 'top',
'xanchor': 'left',
'currentvalue': {
'font': {
'size': 20
},
'prefix': 'Year:',
'visible': True,
'xanchor': 'right'
},
'transition': {
'duration': 300,
'easing': 'cubic-in-out'
},
'pad': {
'b': 10,
't': 50
},
'len': 0.9,
'x': 0.1,
'y': 0,
'steps': []
}
for index, year in enumerate(years):
frame = {
'data': [{
'type': 'bar',
'x': items,
'y': count[index]
}],
'name': str(year)
}
figure['frames'].append(frame)
slider_step = {
'args': [
[year],
{
'frame': {
'duration': 300,
'redraw': True
},
'mode': 'immediate',
'transition': {
'duration': 300
}
}
],
'label': year,
'method': 'animate'
}
sliders_dict['steps'].append(slider_step)
figure['layout']['sliders'] = [sliders_dict]
iplot(figure)