6
votes

I am trying to add a dropdown menu to a plotly line graph that updates the graph data source when selected. My data has 3 columns and looks as such:

1               Country  Average House Price (£)       Date
0  Northern Ireland                      47101.0 1992-04-01
1  Northern Ireland                      49911.0 1992-07-01
2  Northern Ireland                      50174.0 1992-10-01
3  Northern Ireland                      46664.0 1993-01-01
4  Northern Ireland                      48247.0 1993-04-01

The Country column contains the 4 countries in the United Kingdom and is used for creating the separate lines for each using the color parameter. I have 4 different dataframes for different housing types such as all_dwellings, first_timebuyers and when trying to specify the updatemenus args it seems I cannot use the dataframe format. Here is the code to create the entire graph.

lineplt = px.line(data_frame = all_dwellings,
              x='Date',
              y='Average House Price (£)',
              color= 'Country',
              hover_name='Country',
              color_discrete_sequence=['rgb(23, 153, 59)','rgb(214, 163, 21)','rgb(40, 48, 165)', 'rgb(210, 0, 38)']
              )
updatemenus = [
{'buttons': [
            {
            'method': 'restyle',
            'label': 'All Dwellings',
            'args': [{'data_frame': all_dwellings}]
            },
            {
            'method': 'restyle',
            'label': 'First Time Buyers',
            'args': [{'data_frame': first_buyers}]
            }
            ],
'direction': 'down',
'showactive': True,
}
]

lineplt = lineplt.update_layout(
            title_text='Average House Price in UK (£)',
            title_x=0.5,
            #plot_bgcolor= 'rgb(194, 208, 209)',
            xaxis_showgrid=False,
            yaxis_showgrid=False,
            hoverlabel=dict(font_size=10, bgcolor='rgb(69, 95, 154)',
            bordercolor= 'whitesmoke'),
            legend=dict(title='Please click legend item to remove <br>or add to plot',
                        x=0,
                        y=1,
                        traceorder='normal',
                        bgcolor='LightSteelBlue',
                        xanchor = 'auto'),
            updatemenus=updatemenus
            )
lineplt = lineplt.update_traces(mode="lines", hovertemplate= 'Date = %{x} <br>' + 'Price = £%{y:.2f}')
lineplt.show()

However I get the following error:

TypeError: Object of type DataFrame is not JSON serializable

All the examples seem to convert items to lists but this doesn't seem to work with dataframe format. Could anybody help? If question not clear then please let me know.

EDIT - output of all_dwellings.head(20).to_dict()

{'Country': {0: 'Northern Ireland    ', 1: 'Northern Ireland    ', 2: 'Northern Ireland    ', 3: 'Northern Ireland    ', 4: 'Northern Ireland    ', 5: 'Northern Ireland    ', 6: 'Northern Ireland    ', 7: 'Northern Ireland    ', 8: 'Northern Ireland    ', 9: 'Northern Ireland    ', 10: 'Northern Ireland    ', 11: 'Northern Ireland    ', 12: 'Northern Ireland    ', 13: 'Northern Ireland    ', 14: 'Northern Ireland    ', 15: 'Northern Ireland    ', 16: 'Northern Ireland    ', 17: 'Northern Ireland    ', 18: 'Northern Ireland    ', 19: 'Northern Ireland    '}, 'Average House Price (£)': {0: 47101.0, 1: 49911.0, 2: 50174.0, 3: 46664.0, 4: 48247.0, 5: 54891.0, 6: 53773.0, 7: 57594.0, 8: 49804.0, 9: 58586.0, 10: 55154.0, 11: 55413.0, 12: 60239.0, 13: 59094.0, 14: 57131.0, 15: 61849.0, 16: 61951.0, 17: 61595.0, 18: 68705.0, 19: 74869.0}, 'Date': {0: Timestamp('1992-04-01 00:00:00'), 1: Timestamp('1992-07-01 00:00:00'), 2: Timestamp('1992-10-01 00:00:00'), 3: Timestamp('1993-01-01 00:00:00'), 4: Timestamp('1993-04-01 00:00:00'), 5: Timestamp('1993-07-01 00:00:00'), 6: Timestamp('1993-10-01 00:00:00'), 7: Timestamp('1994-01-01 00:00:00'), 8: Timestamp('1994-04-01 00:00:00'), 9: Timestamp('1994-07-01 00:00:00'), 10: Timestamp('1994-10-01 00:00:00'), 11: Timestamp('1995-01-01 00:00:00'), 12: Timestamp('1995-04-01 00:00:00'), 13: Timestamp('1995-07-01 00:00:00'), 14: Timestamp('1995-10-01 00:00:00'), 15: Timestamp('1996-01-01 00:00:00'), 16: Timestamp('1996-04-01 00:00:00'), 17: Timestamp('1996-07-01 00:00:00'), 18: Timestamp('1996-10-01 00:00:00'), 19: Timestamp('1997-01-01 00:00:00')}}

Output of first_buyers

{'Country': {0: 'Northern Ireland    ', 1: 'Northern Ireland    ', 2: 'Northern Ireland    ', 3: 'Northern Ireland    ', 4: 'Northern Ireland    ', 5: 'Northern Ireland    ', 6: 'Northern Ireland    ', 7: 'Northern Ireland    ', 8: 'Northern Ireland    ', 9: 'Northern Ireland    ', 10: 'Northern Ireland    ', 11: 'Northern Ireland    ', 12: 'Northern Ireland    ', 13: 'Northern Ireland    ', 14: 'Northern Ireland    ', 15: 'Northern Ireland    ', 16: 'Northern Ireland    ', 17: 'Northern Ireland    ', 18: 'Northern Ireland    ', 19: 'Northern Ireland    '}, 'Average House Price (£)': {0: 29280.0, 1: 32690.0, 2: 29053.0, 3: 30241.0, 4: 31032.0, 5: 31409.0, 6: 31299.0, 7: 28922.0, 8: 28621.0, 9: 31519.0, 10: 33497.0, 11: 35861.0, 12: 32472.0, 13: 34493.0, 14: 33662.0, 15: 32630.0, 16: 33426.0, 17: 37154.0, 18: 36555.0, 19: 36406.0}, 'Date': {0: Timestamp('1992-04-01 00:00:00'), 1: Timestamp('1992-07-01 00:00:00'), 2: Timestamp('1992-10-01 00:00:00'), 3: Timestamp('1993-01-01 00:00:00'), 4: Timestamp('1993-04-01 00:00:00'), 5: Timestamp('1993-07-01 00:00:00'), 6: Timestamp('1993-10-01 00:00:00'), 7: Timestamp('1994-01-01 00:00:00'), 8: Timestamp('1994-04-01 00:00:00'), 9: Timestamp('1994-07-01 00:00:00'), 10: Timestamp('1994-10-01 00:00:00'), 11: Timestamp('1995-01-01 00:00:00'), 12: Timestamp('1995-04-01 00:00:00'), 13: Timestamp('1995-07-01 00:00:00'), 14: Timestamp('1995-10-01 00:00:00'), 15: Timestamp('1996-01-01 00:00:00'), 16: Timestamp('1996-04-01 00:00:00'), 17: Timestamp('1996-07-01 00:00:00'), 18: Timestamp('1996-10-01 00:00:00'), 19: Timestamp('1997-01-01 00:00:00')}}
1

1 Answers

2
votes

I've made a preliminary setup using your full datasample, and I think I've got it figured out. The challenge here is that px.line will group your data by the color argument. And that makes it a bit harder to edit the data displayed using a dropdownmenu with a direct reference to the source of your px.line plot.

But you can actually build multiple px.line figures for the different datasets, and "steal" the data with the correct structure for your figure there. This will give you these figures for the different dropdown options:

enter image description here

enter image description here

I'm a bit worried that the second plot might be a bit off, but I'm using the date you've provided which looks like this for first_timebuyers:

enter image description here

So maybe it makes sense after all?

Below is the complete code without your data. We can talk about the details and further tweaking tomorrow. Bye for now.

import numpy as np
import pandas as pd
import plotly.express as px
from pandas import Timestamp

all_dwellings=pd.DataFrame(<yourData>)
first_timebuyers = pd.DataFrame(<yourData>)

# datagrab 1
lineplt_all = px.line(data_frame = all_dwellings,
              x='Date',
              y='Average House Price (£)',
              color= 'Country',
              hover_name='Country',
              color_discrete_sequence=['rgb(23, 153, 59)','rgb(214, 163, 21)','rgb(40, 48, 165)', 'rgb(210, 0, 38)']
              )

# datagrab 2
lineplt_first = px.line(data_frame = first_timebuyers,
              x='Date',
              y='Average House Price (£)',
              color= 'Country',
              hover_name='Country',
              color_discrete_sequence=['rgb(23, 153, 59)','rgb(214, 163, 21)','rgb(40, 48, 165)', 'rgb(210, 0, 38)']
              )

### Your original setup
lineplt = px.line(data_frame = all_dwellings,
              x='Date',
              y='Average House Price (£)',
              color= 'Country',
              hover_name='Country',
              color_discrete_sequence=['rgb(23, 153, 59)','rgb(214, 163, 21)','rgb(40, 48, 165)', 'rgb(210, 0, 38)']
              )
updatemenus = [
{'buttons': [
            {
            'method': 'restyle',
            'label': 'All Dwellings',
            'args': [{'y': [dat.y for dat in lineplt_all.data]}]
            },
            {
            'method': 'restyle',
            'label': 'First Time Buyers',
            'args': [{'y': [dat.y for dat in lineplt_first.data]}]
            }
            ],
'direction': 'down',
'showactive': True,
}
]

lineplt = lineplt.update_layout(
            title_text='Average House Price in UK (£)',
            title_x=0.5,
            #plot_bgcolor= 'rgb(194, 208, 209)',
            xaxis_showgrid=False,
            yaxis_showgrid=False,
            hoverlabel=dict(font_size=10, bgcolor='rgb(69, 95, 154)',
            bordercolor= 'whitesmoke'),
            legend=dict(title='Please click legend item to remove <br>or add to plot',
                        x=0,
                        y=1,
                        traceorder='normal',
                        bgcolor='LightSteelBlue',
                        xanchor = 'auto'),
            updatemenus=updatemenus
            )
lineplt = lineplt.update_traces(mode="lines", hovertemplate= 'Date = %{x} <br>' + 'Price = £%{y:.2f}')
lineplt.show()