TypeError: unhashable type: ‘Scatter’ when trying to create scatter plot with multiple axes

Hi,

Just trying to build upon the example in the tutorial that creates a scatter plot from a pandas dataframe. Attempted to add a second y-axes using the code below:

import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objs as go
import pandas as pd

app = dash.Dash()

df = pd.read_csv(
    'https://gist.githubusercontent.com/chriddyp/' +
    '5d1ea79569ed194d432e56108a04d188/raw/' +
    'a9f9e8076b837d541398e999dcbac2b2826a81f8/'+
    'gdp-life-exp-2007.csv')


app.layout = html.Div([
    dcc.Graph(
        id='life-exp-vs-gdp',
        figure={
            'data': [
                {
                go.Scatter(
                    x=df[df['continent'] == i]['gdp per capita'],
                    y=df[df['continent'] == i]['life expectancy'],
                    text=df[df['continent'] == i]['country'],
                    mode='markers',
                    opacity=0.7,
                    marker={
                        'size': 15,
                        'line': {'width': 0.5, 'color': 'white'}
                    },
                    name=i
                ) for i in df.continent.unique()
                },
                {
                go.Scatter(
                    x=df[df['continent'] == i]['gdp per capita'],
                    y=df[df['continent'] == i]['population'],
                    text=df[df['continent'] == i]['country'],
                    mode='markers',
                    opacity=0.7,
                    marker={
                        'size': 15,
                        'line': {'width': 0.5, 'color': 'white'}
                    },
                    name=i
                ) for i in df.continent.unique()
                }
            ],
            'layout': go.Layout(
                xaxis={'type': 'log', 'title': 'GDP Per Capita'},
                yaxis={'title': 'Life Expectancy'},
                margin={'l': 40, 'b': 40, 't': 10, 'r': 10},
                legend={'x': 0, 'y': 1},
                hovermode='closest'
            )
        }
    )
])

if __name__ == '__main__':
    app.run_server()

However when I try to run app.py I get the error:

Traceback (most recent call last):
  File "graph_from_dataframe.py", line 33, in <module>
    ) for i in df.continent.unique()
  File "graph_from_dataframe.py", line 33, in <setcomp>
    ) for i in df.continent.unique()
TypeError: unhashable type: 'Scatter'

I’ve seen examples with multiple axes where a html file is generated but I’m trying to do something closer to a running application. Has anyone had success with multiple axes scatter plot?

It should just be go.Scatter not {go.Scatter.

Had that initially but I gives me a syntax error, so that’s why I added the curly braces ( { and } ) based upon the multi axes examples. I now have:

'data': [
                go.Scatter(
                    x=df[df['continent'] == i]['gdp per capita'],
                    y=df[df['continent'] == i]['life expectancy'],
                    text=df[df['continent'] == i]['country'],
                    mode='markers',
                    opacity=0.7,
                    marker={
                        'size': 15,
                        'line': {'width': 0.5, 'color': 'white'}
                    },
                    name=i
                ) for i in df.continent.unique()
                go.Scatter(
                    x=df[df['continent'] == i]['gdp per capita'],
                    y=df[df['continent'] == i]['population'],
                    text=df[df['continent'] == i]['country'],
                    mode='markers',
                    opacity=0.7,
                    marker={
                        'size': 15,
                        'line': {'width': 0.5, 'color': 'white'}
                    },
                    name=i
                ) for i in df.continent.unique()
            ],

The syntax error is:

 File "graph_from_dataframe.py", line 33
    go.Scatter(
     ^
SyntaxError: invalid syntax

I just can’t seem to get the syntax for second scatter set (population) correct…

Looks like an issue with python list conacentation. Try 'data': [ [go.Scatter(...) for i in ...] + [go.Scatter(...) for i in ...]]

The hash() is a built-in python method, used to return a unique number . This can be applied to any user-defined object which won’t get changed once initialized. This property is used mainly in dictionary keys .

TypeError: unhashable type: ‘list’ usually means that you are trying to use a list as an hash argument. This means that when you try to hash an unhashable object it will result an error. For ex. when you use a list as a key in the dictionary , this cannot be done because lists can’t be hashed. The standard way to solve this issue is to cast a list to a tuple .

Hi I have the same issue, this doesn’t work too

Can you provide a solution to the issue?

Were you able to resolve this issue?I’m facing the same thing.

Hey @mahima8. I have something working when I use yaxis2 inside the layout. It’s a completely different df but don’t think it should matter. Hope this helps

datasets = json.loads(jsonified_cleaned_data)
df = pd.read_json(datasets['df_3'], orient='split')

trace_vol = go.Bar(
        x=df.index,
        y=df.volume,
        #showlegend=False
        name = "Volume")

trace = go.Scatter(
            x=df.index,
            y=df.stdev,
            name = "StdDev",
            line = dict(color = '#FF9933'),
            opacity = 0.8,
            yaxis='y2')

layout = go.Layout(
#title='Double Y Axis Example',
legend=dict(x=1.1, y=1.0),
yaxis=dict(
    title='Volume'
),
yaxis2=dict(
    title='StdDev',
    titlefont=dict(
        color='#000000'
    ),
    tickfont=dict(
        color='#000000'
    ),
    overlaying='y',
    side='right',
    #position=0.96
)
)

return {
    'data':[trace,trace_vol], 'layout':dict(xaxis=dict(title='Volume')), 'layout':layout
}

you must delete the “{” between the “data”: [ and the go.Scatter and also the “}” at the end before name=i.

try this code:

import dash
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd

import plotly
import plotly.graph_objects as go
from plotly.subplots import make_subplots

app = dash.Dash(__name__)

df = pd.read_csv(
    'https://gist.githubusercontent.com/chriddyp/' +
    '5d1ea79569ed194d432e56108a04d188/raw/' +
    'a9f9e8076b837d541398e999dcbac2b2826a81f8/'+
    'gdp-life-exp-2007.csv')

def main_graph(df):

    fig = make_subplots(rows=1, cols=1,shared_xaxes=True, shared_yaxes=False)

    for i in df.continent.unique():
        # Trace 1
        fig.add_trace(go.Scatter(x=df[df['continent'] == i]['gdp per capita'],y=df[df['continent'] == i]['life expectancy'],text=df[df['continent'] == i]['country'],mode='markers',opacity=0.7,marker={'size': 15,'line': {'width': 0.5, 'color': 'white'}},name=i))
        fig['data'][-1].update(yaxis='y')

        # Trace 2
        fig.add_trace(go.Scatter(x=df[df['continent'] == i]['gdp per capita'],y=df[df['continent'] == i]['population'],text=df[df['continent'] == i]['country'],mode='markers',opacity=0.7,marker={'size': 15,'line': {'width': 0.5, 'color': 'white'}},name=i))
        fig['data'][-1].update(yaxis='y2')


    #====================== Layout parameters
    fig.update_layout(
        xaxis=dict(type='log',domain=[0.0, 0.92], #spikemode = 'across',spikethickness = 2,spikedash='solid',
        title = 'GDP Per Capita',
        autorange=True,
        showline = False,
        showgrid=False, gridwidth=1, gridcolor='rgba(128,128,128,0.3)',
        zeroline=False
        ),

        yaxis=dict(zeroline=False,showgrid=False, gridwidth=1, gridcolor='rgba(128,128,128,0.3)',autorange=True,title='Life Expectancy',titlefont=dict(color='green'),tickfont=dict(color='green'),side="right",anchor='x'),
        yaxis2=dict(zeroline=False,showgrid=False, gridwidth=1, gridcolor='rgba(128,128,128,0.3)',autorange=True,title='title 2',titlefont=dict(color='red'),tickfont=dict(color='red'),side="right",anchor='free',position=0.98,overlaying="y"),

    )

    # Update layout properties
    fig.update_layout(
        title={
        'text': "Graph",
        'y':0.95,
        'x':0.41,
        'xanchor': 'center',
        'yanchor': 'top'},
        hovermode="closest",
        margin=dict(l=5,t=40,r=80),
    )

    return fig


app.layout = html.Div([
    dcc.Graph(
        id='life-exp-vs-gdp',
        figure = main_graph(df)
        # figure={
        #     'data': [
        #         {
        #         go.Scatter(
        #             x=df[df['continent'] == i]['gdp per capita'],
        #             y=df[df['continent'] == i]['life expectancy'],
        #             text=df[df['continent'] == i]['country'],
        #             mode='markers',
        #             opacity=0.7,
        #             marker={
        #                 'size': 15,
        #                 'line': {'width': 0.5, 'color': 'white'}
        #             },
        #             name=i
        #         ) for i in df.continent.unique()
        #         },
        #         {
        #         go.Scatter(
        #             x=df[df['continent'] == i]['gdp per capita'],
        #             y=df[df['continent'] == i]['population'],
        #             text=df[df['continent'] == i]['country'],
        #             mode='markers',
        #             opacity=0.7,
        #             marker={
        #                 'size': 15,
        #                 'line': {'width': 0.5, 'color': 'white'}
        #             },
        #             name=i
        #         ) for i in df.continent.unique()
        #         }
        #     ],
        #     'layout': go.Layout(
        #         xaxis={'type': 'log', 'title': 'GDP Per Capita'},
        #         yaxis={'title': 'Life Expectancy'},
        #         margin={'l': 40, 'b': 40, 't': 10, 'r': 10},
        #         legend={'x': 0, 'y': 1},
        #         hovermode='closest'
        #     )
        # }
    )
])

if __name__ == '__main__':
    app.run_server(debug=True)