This code produces a bar plot:
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import plotly.graph_objects as go
classes= ['class1', 'class2', 'class3', 'class4', 'class5', 'class6', 'class7']
lens = [199, 30, 89, 59, 109, 115, 89]
nums = [145, 457, 123, 67, 35, 31, 134]
fig = go.Figure(data=[
go.Bar(name='Length', x=classes, y=lens),
go.Bar(name='Number', x=classes, y=nums),
])
# Change the bar mode
fig.update_layout(barmode='group')
fig.update_layout(title_text='Length and Number',
title_x=0.1,
plot_bgcolor='rgba(0,0,0,0)',
paper_bgcolor='rgba(0,0,0,0)',
bargap=0.30,
bargroupgap=0.0,
margin=dict(l=50, r=50, t=50, b=50),
xaxis_title="Score Class",
yaxis_title="Length and Number",
yaxis = dict(
tickfont = dict(size=13)),
xaxis = dict(
tickfont = dict(size=13)),)
fig.update_xaxes(showline=True, linewidth=2, linecolor='black')
fig.update_yaxes(showline=True, linewidth=2, linecolor='black')
fig.show()
The output is:
I want to click on any of the red bars, and it will bring me to a scatterplot of values in that class.
I can produce a scatterplot with this:
dict2 = {}
dict2['class1'] = [(2,2),(1,1),(2,3),(3,4),(5,1)]
dict2['class2'] = [(3,1),(4,4),(5,5),(6,2),(7,1)]
dict2['class3'] = [(3,2),(4,1),(5,4),(6,4),(7,1)]
dict2['class4'] = [(3,1),(4,5),(6,3),(4,3),(5,3)]
dict2['class5'] = [(1,1),(1,1),(1,2),(3,1),(4,3)]
dict2['class6'] = [(2,2),(2,1),(2,3),(5,3),(6,4)]
class1_dict = {}
class1_dict['xs'] = [i[0] for i in dict2['class1']]
class1_dict['ys'] = [i[1] for i in dict2['class1']]
plt.scatter(class1_dict['xs'],class1_dict['ys'])
plt.show()
And I know how to click on a bar generally to return a dataframe that I could put into the scatterplot like this:
dict_name = {}
dict_name['classes'] = classes
dict_name['lens'] = lens
dict_name['nums'] = nums
df = pd.DataFrame.from_dict(dict_name, orient='columns')
print(df)
axs = df.hist(bins=4, picker=True)
ax = axs[0, 0]
def onpick(event):
bar = event.artist
left = bar.get_x()
right = left bar.get_width()
col_df = df[(df.lens >= left) & (df.lens <= right)]
ax.figure.canvas.mpl_connect('pick_event', onpick)
#plt.show()
I'm trying to change that last piece of code, so instead of axs = df.hist(bins=4, picker=True)
, I can read in my bar plot, and upon clicking, return a dataframe that I can read into a scatterplot.
So I thought I just needed to somehow add these two lines:
axs = df.hist(bins=4, picker=True)
ax = axs[0, 0]
To my bar plot code, to make it clickable.
So I thought since axs
is just a plot, which is what fig
, I could just add this line to the bar plot code and it would work:
fig = go.Figure(data=[
go.Bar(name='Length', x=classes, y=lens),
go.Bar(name='Number', x=classes, y=nums),
])
ax = fig[0,0]
The error I get is:
Traceback (most recent call last):
File "/Users/slowatkela/anaconda/lib/python3.7/site-packages/plotly/basedatatypes.py", line 188, in _check_path_in_prop_tree
obj = obj[p]
File "/Users/slowatkela/anaconda/lib/python3.7/site-packages/plotly/basedatatypes.py", line 732, in __getitem__
prop = BaseFigure._str_to_dict_path(prop)
File "/Users/slowatkela/anaconda/lib/python3.7/site-packages/plotly/basedatatypes.py", line 1839, in _str_to_dict_path
ret = _str_to_dict_path_full(key_path_str)[0]
File "/Users/slowatkela/anaconda/lib/python3.7/site-packages/plotly/basedatatypes.py", line 71, in _str_to_dict_path_full
if len(key_path_str):
TypeError: object of type 'int' has no len()
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "test3.py", line 17, in <module>
ax=axs[0,0]
File "/Users/slowatkela/anaconda/lib/python3.7/site-packages/plotly/basedatatypes.py", line 754, in __getitem__
err = _check_path_in_prop_tree(self, orig_prop, error_cast=PlotlyKeyError)
File "/Users/slowatkela/anaconda/lib/python3.7/site-packages/plotly/basedatatypes.py", line 212, in _check_path_in_prop_tree
if prop[i][0] == "_":
TypeError: 'int' object is not subscriptable
I guess it's because the first plot makes a grouped bar plot makes one figure whereas the histogram example makes two plots? Could someone show me where I'm going wrong?
CodePudding user response:
As mentioned by @JohanC in the comments, plotly
and matplotlib
are very different libraries. This means that their objects are not related by any kind of class hierarchy, and don't share the same properties.
For that reason, you cannot set a matplotlib axes
object equal to a plotly
figure object. A plotly figure object is not the same as a matplotlib figure object. You will probably need to stay within one library to achieve what you want. If the matplotlib onpick
functionality is important to you, then you should probably stay within matplotlib. I believe that in matplotlib you can construct hoverevents
but it's more effort than in plotly which has hoverevents
as the default for almost if not all of the figures.
Also a plotly figure isn't an array so fig[0,0]
doesn't make sense. Perhaps you meant to access fig.data
which is a tuple meaning you can access fig.data[0], fig.data[1], ... fig.data[N]