绘制两个Plotly六边形地图之间的差异。

3

我看到了一些关于在matplotlib中绘制两个hexbin地图之间差异的帖子。但是我找不到任何执行相同过程但用于Plotly hexbin地图箱线图的内容。如果我有两个单独的hexbin子图 (t, y),是否可能生成一个单一的图形来计算ty之间的差异?

import pandas as pd
import plotly.express as px
import plotly.graph_objs as go
import plotly.figure_factory as ff
from plotly.subplots import make_subplots

data = pd.DataFrame({
   'Cat': ['t','y','y','t','t','t','t','y','y','y','t','y'],
   'LAT': [5,6,7,5,6,7,5,6,7,5,6,7],
   'LON': [10,11,12,10,11,12,10,11,12,10,11,12],
   })

data = pd.concat([data]*5)

df_t = data[data['Cat'] == 't']
df_y = data[data['Cat'] == 'y']

fig = make_subplots(
    rows = 2, 
    cols = 1, 
    subplot_titles = ('t', 'y'),
    specs = [[{"type": "choroplethmapbox"}], [{"type": "choroplethmapbox"}]],
    vertical_spacing = 0.05,
    horizontal_spacing = 0.05
    )

fig2 = ff.create_hexbin_mapbox(data_frame=df_t,
                           lat="LAT", lon="LON",
                           nx_hexagon=5,
                           opacity=0.5,
                           labels={"color": "Point Count"},
                           mapbox_style='carto-positron',
                          )

fig3 = ff.create_hexbin_mapbox(data_frame=df_y,
                           lat="LAT", lon="LON",
                           nx_hexagon=5,
                           opacity=0.5,
                           labels={"color": "Point Count"},
                           mapbox_style='carto-positron',
                          )


fig.add_trace(fig2.data[0], row=1,col=1)
fig.update_mapboxes(zoom=4, style='carto-positron')
fig.add_trace(fig3.data[0], row=2,col=1)
fig.update_mapboxes(zoom=4, style='carto-positron')

fig.update_layout(height=600, margin=dict(t=20,b=0,l=0,r=0))
fig.show()

预期的输出:

t 的左下角垃圾桶有15个点,而y只有5个。因此这将总计为10。中间箱有10个点,所以结果为0。右上方的箱子中有5个t和15个y,总计为-10。但我将把 vmin 设为0,以确保没有负值。

enter image description here

编辑2:

如果我使用不同大小的数组更改输入数据并将min_count = 1作为参数包含在内,则会返回错误。

data = pd.DataFrame({
       'Cat': ['t','y','y','t','t','t','t','y','y','y','t','y','y'],
       'LAT': [5,6,7,5,6,7,5,6,7,5,6,7,8],
       'LON': [10,11,12,10,11,12,10,11,12,10,11,12,8],
       })

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last) /var/folders/bf/09nyl3td65j2lty5m7138ndw0000gn/T/ipykernel_78237/2142200526.py in <module>
     47 
     48 fig = go.Figure(fig2)
---> 49 fig.data[0]['z'] = (fig2.data[0]['z'] - fig3.data[0]['z']).clip(min=0)
     50 cmax, cmin = max(fig.data[0]['z']), min(fig.data[0]['z'])
     51 

ValueError: operands could not be broadcast together with shapes (3,) (4,) 

жҲ‘们иғҪеҗҰдҪҝз”Ёdf_tе’Ңdf_yд№Ӣй—ҙзҡ„е·®ејӮеҲӣе»әеҸҰдёҖдёӘFigure Factory Hexbin Mapboxе‘ўпјҹжӯӨеӨ–пјҢйў„жңҹзҡ„иҫ“еҮәжҳҜеҚ•дёӘеӣҫеҪўиҝҳжҳҜеңЁеҪ“еүҚдёӨдёӘеӣҫеҪўдёӢж–№ж·»еҠ дёҖдёӘйҷ„еҠ еӣҫеҪўпјҹ - Derek O
另一幅图也可以。预期输出为单个图形。 - jonboy
1个回答

3

由于在创建图形时,plotly 确定每个 hexbin 中的计数,因此您需要访问 fig2fig3 内部的计数数据。

以下是存储在 fig2.data[0]['z'] 中的数组:

array([15.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,
        0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  5.,  0.,  0.,
        0.,  0.,  0.,  0.,  0., 10.,  0.,  0.,  0.,  0.,  0.,  0.,  0.])

我们可以将fig设置为fig2的副本,通过从fig2fig3的计数数组之间取差(并将其截断为0)来创建一个新的数组,并将fig.data[0]['z']设置为这个新数组。您还需要相应地更新colorbar的最小值和最大值。
import pandas as pd
import plotly.express as px
import plotly.graph_objs as go
import plotly.figure_factory as ff
from plotly.subplots import make_subplots

data = pd.DataFrame({
   'Cat': ['t','y','y','t','t','t','t','y','y','y','t','y'],
   'LAT': [5,6,7,5,6,7,5,6,7,5,6,7],
   'LON': [10,11,12,10,11,12,10,11,12,10,11,12],
   })

data = pd.concat([data]*5)

df_t = data[data['Cat'] == 't']
df_y = data[data['Cat'] == 'y']

# fig = make_subplots(
#     rows = 2, 
#     cols = 1, 
#     subplot_titles = ('t', 'y'),
#     specs = [[{"type": "choroplethmapbox"}], [{"type": "choroplethmapbox"}]],
#     vertical_spacing = 0.05,
#     horizontal_spacing = 0.05
#     )

fig2 = ff.create_hexbin_mapbox(data_frame=df_t,
                           lat="LAT", lon="LON",
                           nx_hexagon=5,
                           opacity=0.5,
                           labels={"color": "Point Count"},
                           mapbox_style='carto-positron',
                          )

fig3 = ff.create_hexbin_mapbox(data_frame=df_y,
                           lat="LAT", lon="LON",
                           nx_hexagon=5,
                           opacity=0.5,
                           labels={"color": "Point Count"},
                           mapbox_style='carto-positron',
                          )

fig = go.Figure(fig2)
fig.data[0]['z'] = (fig2.data[0]['z'] - fig3.data[0]['z']).clip(min=0)
cmax, cmin = max(fig.data[0]['z']), min(fig.data[0]['z'])

fig.update_mapboxes(zoom=6, style='carto-positron')
fig.update_layout(height=600, margin=dict(t=20,b=0,l=0,r=0))
fig.update_coloraxes(cmax=cmax, cmin=cmin)
fig.show()

enter image description here

更新:在fig2.data [0] ['z']fig3.data [0] ['z']是不同长度的数组的情况下,您需要填充较短的数组。我假设填充值为零,并且我们将以相同的方式计算差异。
使用您编辑过的示例数据,我们得到fig2.data [0] ['z']为array([15., 5., 10.]),fig3.data [0] ['z']为array([10., 15., 5., 5.])。因此,我们用0填充array([15., 5., 10.])以匹配另一个数组的长度,这意味着我们使用array([15., 5., 10., 0.])。我添加了一些代码,它会填充较短的数组,然后像之前一样计算差异并剪辑负值。
import numpy as np
import pandas as pd
import plotly.express as px
import plotly.graph_objs as go
import plotly.figure_factory as ff
from plotly.subplots import make_subplots

# data = pd.DataFrame({
#    'Cat': ['t','y','y','t','t','t','t','y','y','y','t','y'],
#    'LAT': [5,6,7,5,6,7,5,6,7,5,6,7],
#    'LON': [10,11,12,10,11,12,10,11,12,10,11,12],
#    })

data = pd.DataFrame({
       'Cat': ['t','y','y','t','t','t','t','y','y','y','t','y','y'],
       'LAT': [5,6,7,5,6,7,5,6,7,5,6,7,8],
       'LON': [10,11,12,10,11,12,10,11,12,10,11,12,8],
       })

data = pd.concat([data]*5)

df_t = data[data['Cat'] == 't']
df_y = data[data['Cat'] == 'y']

fig2 = ff.create_hexbin_mapbox(data_frame=df_t,
                           lat="LAT", lon="LON",
                           nx_hexagon=5,
                           opacity=0.5,
                           labels={"color": "Point Count"},
                           mapbox_style='carto-positron',
                           min_count=1
                          )

fig3 = ff.create_hexbin_mapbox(data_frame=df_y,
                           lat="LAT", lon="LON",
                           nx_hexagon=5,
                           opacity=0.5,
                           labels={"color": "Point Count"},
                           mapbox_style='carto-positron',
                           min_count=1,
                          )

fig = go.Figure(fig2)
fig2_values, fig3_values = fig2.data[0]['z'], fig3.data[0]['z']

## we pad whichever figure has fewer z values
if len(fig2_values) < len(fig3_values):
   pad_length = len(fig3_values) - len(fig2_values)
   fig2_values = np.pad(fig2_values, (0, pad_length), 'constant')
elif len(fig2_values) > len(fig3_values):
   pad_length = len(fig2_values) - len(fig3_values)
   fig3_values = np.pad(fig3_values, (0, pad_length), 'constant')
else:
   pass

fig.data[0]['z'] = (fig2_values - fig3_values).clip(min=0)
cmax, cmin = max(fig.data[0]['z']), min(fig.data[0]['z'])

fig.update_mapboxes(zoom=6, style='carto-positron')
fig.update_layout(height=600, margin=dict(t=20,b=0,l=0,r=0))
fig.update_coloraxes(cmax=cmax, cmin=cmin)
fig.show()

enter image description here


有没有一种方法可以对数据进行子集处理,并且如果两个数组的大小不同,则将min_count绘制为1。我会添加编辑2。 - jonboy
@jonboy 如果你遇到两个六边形大小不同的情况,你需要填充长度较短的那个数组。我会在我的答案中更新一些更具体的细节。 - Derek O

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接