Plotly 动画气泡图:图中没有数据

Posted

技术标签:

【中文标题】Plotly 动画气泡图:图中没有数据【英文标题】:Plotly animated bubble chart: no data in the plot 【发布时间】:2018-01-24 11:52:21 【问题描述】:

我正在尝试将标准绘图动画气泡图调整为包含这些列的 csv 文件:

index,country,year,Country code,Total population (Gapminder),Life satisfaction in Cantril Ladder (World Happiness Report 2017),GDP per capita
62,Afghanistan,2008,AFG,29839994.0,3.723589897,1298.14315888
63,Afghanistan,2009,AFG,30577756.0,4.401778221,1531.17399272
64,Afghanistan,2010,AFG,31411743.0,4.75838089,1614.25500126
65,Afghanistan,2011,AFG,32358260.0,3.83171916,1660.73985618
66,Afghanistan,2012,AFG,33397058.0,3.782937527,1839.27357928
67,Afghanistan,2013,AFG,34499915.0,3.572100401,1814.15582533
167,Albania,2007,ALB,3169665.0,4.634251595,8447.88228539
169,Albania,2009,ALB,3192723.0,5.485469818,9524.60981095
170,Albania,2010,ALB,3204284.0,5.268936634,9927.13514733
171,Albania,2011,ALB,3215988.0,5.867421627,10207.7006745
172,Albania,2012,ALB,3227373.0,5.510124207,10369.7616592
173,Albania,2013,ALB,3238316.0,4.550647736,10504.0930888
242,Algeria,2010,DZA,35468208.0,5.46356678,12870.2162376
243,Algeria,2011,DZA,35980193.0,5.317194462,12989.9549601
244,Algeria,2012,DZA,36485828.0,5.604595661,13161.566464
451,Angola,2011,AGO,19618432.0,5.589000702,5911.25433387
452,Angola,2012,AGO,20162517.0,4.360249996,5998.63860099
453,Angola,2013,AGO,20714494.0,3.937106848,6185.0138292

数据点的大小将是人口的函数,我会将生活满意度绘制为国家 GDP 的函数。我在数据集上做了一些工作:

gdp=pd.read_csv('gdp-vs-happiness.csv')

gdp=gdp.ix[~(gdp['year'] < 2005)]
gdp=gdp.dropna()

dataset = gdp

然后是代码:

years = ['2005','2006', '2007','2008','2009','2010','2011','2012','2013','2014','2015','2016']

# make list of continents
countries = []
for country in dataset['country']:
    countries.append(country)

# make figure
figure = 
    'data': [],
    'layout': ,
    'frames': []

config = 'scrollzoom': True

# fill in most of layout
figure['layout']['xaxis'] = 'title': 'GDP per Capita', 'type': 'log'
figure['layout']['yaxis'] = 'range': [0, 10], 'title': 'Life Satisfaction'
figure['layout']['hovermode'] = 'closest'
figure['layout']['sliders'] = 
    'args': [
        'slider.value', 
            'duration': 400,
            'ease': 'cubic-in-out'
        
    ],
    'initialValue': '2005',
    'plotlycommand': 'animate',
    'values': years,
    'visible': True

figure['layout']['updatemenus'] = [
    
        'buttons': [
            
                'args': [None, 'frame': 'duration': 500, 'redraw': False,
                         'fromcurrent': True, 'transition': 'duration': 300, 'easing': 'quadratic-in-out'],
                'label': 'Play',
                'method': 'animate'
            ,
            
                'args': [[None], 'frame': 'duration': 0, 'redraw': False, 'mode': 'immediate',
                'transition': 'duration': 0],
                'label': 'Pause',
                'method': 'animate'
            
        ],
        'direction': 'left',
        'pad': 'r': 10, 't': 87,
        'showactive': False,
        'type': 'buttons',
        'x': 0.1,
        'xanchor': 'right',
        'y': 0,
        'yanchor': 'top'
    
]

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': []


# make data
year = 2005
for country in countries:
    dataset_by_year = dataset[dataset['year'] == year]
    dataset_by_year_and_count = dataset_by_year[dataset_by_year['country'] == country]
    data_dict = 
        'x': list(dataset_by_year_and_count['GDP per capita']),
        'y': list(dataset_by_year_and_count['Life satisfaction in Cantril Ladder (World Happiness Report 2017)']),
        'mode': 'markers',
        'text': list(dataset_by_year_and_count['country']),
        'marker': 
            'sizemode': 'area',
            'sizeref': 200000,
            'size': list(dataset_by_year_and_count['Total population (Gapminder)'])
        ,
        'name': country

    
    figure['data'].append(data_dict)

# make frames
for year in years:
    frame = 'data': [], 'name': str(year)
    for country in countries:
        dataset_by_year = dataset[dataset['year'] == int(year)]
        dataset_by_year_and_cont = dataset_by_year[dataset_by_year['country'] == country]

        data_dict = 
        'x': list(dataset_by_year_and_count['GDP per capita']),
        'y': list(dataset_by_year_and_count['Life satisfaction in Cantril Ladder (World Happiness Report 2017)']),
            'mode': 'markers',
            'text': list(dataset_by_year_and_count['country']),
            'marker': 
                'sizemode': 'area',
                'sizeref': 200000,
                'size': list(dataset_by_year_and_count['Total population (Gapminder)'])
            ,
        'name': country

        
        frame['data'].append(data_dict)

    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]

iplot(figure, config=config)

这里的问题是我得到一个空图(滑块、布局、轴标签动画正在工作),根本没有数据,也没有引发错误。所以老实说,我不知道问题出在哪里。这显然与脚本中的数据构建有关,但我不知道具体是什么。

【问题讨论】:

您能否在数据集中为每年提供 2 行的模型数据框,df = pd.DataFrame('county': ['Cochice', 'Pima', 'Santa Cruz', 'Maricopa', 'Yuma'], 'year': [2012, 2012, 2013, 2014, 2014], 'reports': [4, 24, 31, 2, 3]),请参考示例,但将一些示例数据和列与您的文件相同并将其添加到问题中 我刚刚编辑了这个问题,谢谢。通过查看该文件,我认为这可能取决于并非每个国家/地区都有所有指定年份的数据这一事实,但我不知道情节如何处理这个问题,以及如何让它发挥作用(对于例如,如果该年没有可用数据,则使国家/地区数据点消失)。 事实上,如果我将起始年份更改为 2008 年,则会填充图例(每个国家/地区,它在数据集中出现的每一年 - 这是我稍后将处理的内容)并出现一个数据点在情节中:津巴布韦 2008 年的情节。它在整个动画中都没有改变。所以这肯定取决于读取数据的方式。 【参考方案1】:

我使用了您提供的示例数据并对其进行了处理,我遇到了一些问题并在每一行添加了我的 cmets,主要原因在 cmets 部分指出,但您可以交叉检查我的代码和您的代码得到你需要的东西

代码:

from plotly.offline import init_notebook_mode, iplot
from IPython.display import display, html

import pandas as pd

init_notebook_mode(connected=True)

url = 'testing.csv'
dataset = pd.read_csv(url)
# instead of hardcoding you can use unique() function to get the years present in the file, then convert to list and sort based on years
# years = dataset['year'].unique().tolist()
# years.sort()
years = ['2007','2008','2009','2010','2011','2012','2013'] # try to provide years that contain data in the data set

# make list of continents
countries = []
for country in dataset['country'].unique():
    countries.append(country)
# make figure
figure = 
    'data': [],
    'layout': ,
    'frames': []

config = 'scrollzoom': True

# fill in most of layout

# there is a small ranging issue, where some points go out of the plot so try this code if you notice it

#figure['layout']['xaxis'] = 'title': 'GDP per Capita',  'autorange': False, 'range': [int(dataset['GDP per capita'].min()), int(dataset['GDP per capita'].max())] #was not set properly
#figure['layout']['yaxis'] = 'title': 'Life Expectancy', 'autorange': False, 
#                             'range': [int(dataset['Life satisfaction in Cantril Ladder (World Happiness Report 2017)'].min()), 
#                                    int(dataset['Life satisfaction in Cantril Ladder (World Happiness Report 2017)'].max())] #was not set properly


figure['layout']['xaxis'] = 'title': 'GDP per Capita', 'type': 'log', 'autorange': True #was not set properly
figure['layout']['yaxis'] = 'title': 'Life Expectancy', 'autorange': True #was not set properly
figure['layout']['hovermode'] = 'closest'
figure['layout']['showlegend'] = True
figure['layout']['sliders'] = 
    'args': [
        'slider.value', 
            'duration': 400,
            'ease': 'cubic-in-out'
        
    ],
    'initialValue': '2007',
    'plotlycommand': 'animate',
    'values': years,
    'visible': True

figure['layout']['updatemenus'] = [
    
        'buttons': [
            
                'args': [None, 'frame': 'duration': 500, 'redraw': False,
                         'fromcurrent': True, 'transition': 'duration': 300, 'easing': 'quadratic-in-out'],
                'label': 'Play',
                'method': 'animate'
            ,
            
                'args': [[None], 'frame': 'duration': 0, 'redraw': False, 'mode': 'immediate',
                'transition': 'duration': 0],
                'label': 'Pause',
                'method': 'animate'
            
        ],
        'direction': 'left',
        'pad': 'r': 10, 't': 87,
        'showactive': False,
        'type': 'buttons',
        'x': 0.1,
        'xanchor': 'right',
        'y': 0,
        'yanchor': 'top'
    
]

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': []


# make data -  here you need to specify the year being used as starting point, important to change
year = 2007
for country in countries:
    dataset_by_year = dataset[dataset['year'] == year]
    dataset_by_year_and_cont=dataset_by_year[dataset_by_year['country'] == country]

    data_dict = 
        'x': list(dataset_by_year_and_cont['GDP per capita']),
        'y': list(dataset_by_year_and_cont['Life satisfaction in Cantril Ladder (World Happiness Report 2017)']),
        'mode': 'markers',
        'text': [country], # since there is only one country we do not need to provide the list for text -  
        #Suggestion: No need to have this
        'marker': 
            'sizemode': 'area',
            'sizeref': 200000,
            'size': list(dataset_by_year_and_cont['Total population (Gapminder)'])
        ,
        'name': country
    
    figure['data'].append(data_dict)

# make frames
for year in years:
    frame = 'data': [], 'name': str(year)
    dataset_by_year = dataset[dataset['year'] == int(year)] # here this has been moved because if the country 
    # is not present for that particular year there is no need to plot those traces
    for country in dataset_by_year['country']:

        dataset_by_year_and_cont=dataset_by_year[dataset_by_year['country'] == country]

        data_dict = 
            'x': list(dataset_by_year_and_cont['GDP per capita']),
            'y': list(dataset_by_year_and_cont['Life satisfaction in Cantril Ladder (World Happiness Report 2017)']),
            'mode': 'markers',
            'text': [country], # since there is only one country we do not need to provide the list for text - 
            #Suggestion: No need to have this
            'marker': 
                'sizemode': 'area',
                'sizeref': 200000,
                'size': list(dataset_by_year_and_cont['Total population (Gapminder)'])
            ,
            'name': country,
            'type': 'scatter',
            'showlegend': True
        
        frame['data'].append(data_dict)

    figure['frames'].append(frame) #this block was indented and should not have been.
    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]

iplot(figure, config=config)

输出:

【讨论】:

非常感谢您的帮助。它有效,并且通过一些细微的调整它将是完美的。我正在研究你所做的每一个改变,以理清你做了什么以及为什么这样做。今天,您在攀登我的情节学习曲线方面帮助了我很多:) 非常感谢! @sato 很高兴为您提供帮助,Plotly 是一个很棒的库,我们只需要通过 reference guide 并习惯参数 :)

以上是关于Plotly 动画气泡图:图中没有数据的主要内容,如果未能解决你的问题,请参考以下文章

Plotly:将时间序列/烛台图与气泡/散点图相结合

当我在 plotly 中绘制气泡图时出现错误

Plotly / Dash:如何在气泡图的边缘强制裁剪?

用 Python 在一个矩形中打包气泡图堆栈

新冠疫情形势气泡图(python还有这么可爱的气泡图哦)

数据输入——生成你需要的echart图(世界地图,气泡图)