Как я могу построить тепловую карту на сфере, учитывая список широт и долгот? - PullRequest
0 голосов
/ 23 октября 2018

У меня есть список из более чем 500 точек, указанных в широте и долготе.Эти точки представляют кратеры, и я хочу построить тепловую карту этих кратеров.Например, я хочу, чтобы область с большим количеством кратеров считалась «горячей», а меньшее количество кратеров - «холодной».Я смотрел на KDE с помощью SciPy, а также пытался использовать ListSliceDensityPlot3D в Mathematica, но мне не удалось создать адекватный график.

Я преобразовал каждую точку из широты / долготы в декартову [x, y,z] координаты и нанесение их на поверхность сферы, но я не знаю, как взять список точек и рассчитать плотность в данной области, а затем нанести его на трехмерную поверхность.

Идея заключается в том, что я получаю сюжет, похожий на это изображение Цереры !

Заранее спасибо, пожалуйста, задавайте вопросы, если это необходимо, извините, если я сначала не опубликовал достаточно информации.

Ответы [ 2 ]

0 голосов
/ 14 ноября 2018

Здесь есть две отдельные проблемы: определение подходящих размеров ячеек и функций подсчета для сферы, чтобы вы могли построить соответствующую цветовую функцию, а затем построение этой цветовой функции на трехмерной сфере.Я предоставлю решение Mathematica для обоих.

1.Составление примерных данных

Для начала приведу несколько примерных данных:

data = Map[
  Apply@Function[{x, y, z},
    {
     Mod[ArcTan[x, y], 2 π],
     ArcSin[z/Sqrt[x^2 + y^2 + z^2]]
     }
    ],
  Map[
   #/Norm[#]&,
   Select[
    RandomReal[{-1, 1}, {200000, 3}],
    And[
      Norm[#] > 0.01,
      Or[
       Norm[# - {0, 0.3, 0.2}] < 0.6,
       Norm[# - {-0.3, -0.15, -0.3}] < 0.3
       ]
      ] &
    ]
   ]
  ]

Я сделал его немного кусковатым, чтобы у него было больше интересных функций, когда дело доходит до графика..

2.Построение цветовой функции

Для построения цветовой функции в Mathematica самое чистое решение - использовать HistogramList, но это необходимо изменить, чтобы учесть тот факт, что ящики на высокой широтебудет иметь различные области, поэтому плотность должна быть скорректирована.

Тем не менее, встроенные инструменты построения гистограммы довольно хороши:

DensityHistogram[
 data,
 {5°}
 , AspectRatio -> Automatic
 , PlotRangePadding -> None
 , ImageSize -> 700
 ]

Mathematica graphics

Вы можете получить необработанные данные через

{{ϕbins, θbins}, counts} =  HistogramList[data, {15°}]

, а затем для удобства давайте определим

ϕcenters = 1/2 (Most[ϕbins] + Rest[ϕbins])
θcenters = 1/2 (Most[θbins] + Rest[θbins])

с областью бункера, вычисленной с использованием

SectorArea[ϕmin_, ϕmax_, θmin_, θmax_] = (Abs[ϕmax - ϕmin]/(4 π)) * 
                                         Integrate[Sin[θ], {θ, θmin, θmax}]

.Вы можете определить свою собственную цветовую функцию как

function[ϕ_, θ_] := With[{
   iϕ = First[Nearest[ϕcenters -> Range[Length[ϕcenters]], ϕ]],
   iθ = First[Nearest[θcenters -> Range[Length[θcenters]], θ]]
   },
  (N@counts[[iϕ, iθ]]/
   SectorArea[ϕbins[[iϕ]], ϕbins[[iϕ + 1]], θbins[[iθ]], θbins[[iθ + 1]]])/max
  ]

Итак, вот эта функция в действии:

texture = ListDensityPlot[
  Flatten[
   Table[
    {
     ϕcenters[[iϕ]],
     θcenters[[iθ]],
     function[ϕcenters[[iϕ]], θcenters[[iθ]]]
     }
    , {iϕ, Length[ϕbins] - 1}
    , {iθ, Length[θbins] - 1}
    ], 1]
  , InterpolationOrder -> 0
  , AspectRatio -> Automatic
  , ColorFunction -> ColorData["GreenBrownTerrain"]
  , Frame -> None
  , PlotRangePadding -> None
  ]

Mathematica graphics

3.Построение графика

Чтобы построить данные на сфере, я вижу два основных варианта: вы можете создать график поверхности, а затем обернуть его вокруг параметрического графика как Texture, как в

ParametricPlot3D[
 {Cos[ϕ] Sin[θ], Sin[ϕ] Sin[θ], 
  Cos[θ]}
 , {ϕ, 0, 2 π}, {θ, 0, π}
 , Mesh -> None
 , Lighting -> "Neutral"
 , PlotStyle -> Directive[
   Specularity[White, 30],
   Texture[texture]
   ]
 ]

Mathematica graphics

Или вы можете определить его как явное ColorFunction на том же параметрическом графике:

ParametricPlot3D[
 {Cos[ϕ] Sin[θ], Sin[ϕ] Sin[θ], 
  Cos[θ]}
 , {ϕ, 0, 2 π}, {θ, 0, π}
 , ColorFunctionScaling -> False
 , ColorFunction -> Function[{x, y, z, ϕ, θ},
   ColorData["GreenBrownTerrain"][function[ϕ, θ]]
   ]
 ]

Mathematica graphics


Все вышеперечисленное, конечно, очень модульно, поэтому вы можете свободно комбинировать и сочетать в своих интересах.

0 голосов
/ 24 октября 2018

Это своего рода метод грубой силы, но он работает до определенного момента.Это будет проблематично, если вы сделаете сетку очень тонкой или будете иметь тысячи кратеров.Если размер ячейки достаточно мал, нет большой разницы между расстоянием на поверхности и трехмерным расстоянием, поэтому я выбрал последнее, так как его легче вычислить, но можно изменить это.

Код выглядит так:

from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm


def random_point( r=1 ):
    ct = 2*np.random.rand() - 1
    st = np.sqrt( 1 - ct**2 )
    phi = 2* np.pi *  np.random.rand()
    x = r * st * np.cos( phi)
    y = r * st * np.sin( phi)
    z = r * ct
    return np.array( [x, y, z ] )

def near( p, pntList, d0 ):
    cnt=0
    for pj in pntList:
        dist=np.linalg.norm( p - pj )
        if dist < d0:
            cnt += 1 - dist/d0
    return cnt


"""
https://stackoverflow.com/questions/22128909/plotting-the-temperature-distribution-on-a-sphere-with-python
"""

pointList = np.array([ random_point( 10.05 ) for i in range( 65 ) ] )

fig = plt.figure()
ax = fig.add_subplot( 1, 1, 1, projection='3d')

u = np.linspace( 0, 2 * np.pi, 120)
v = np.linspace( 0, np.pi, 60 )

# create the sphere surface
XX = 10 * np.outer( np.cos( u ), np.sin( v ) )
YY = 10 * np.outer( np.sin( u ), np.sin( v ) )
ZZ = 10 * np.outer( np.ones( np.size( u ) ), np.cos( v ) )

WW = XX.copy()
for i in range( len( XX ) ):
    for j in range( len( XX[0] ) ):
        x = XX[ i, j ]
        y = YY[ i, j ]
        z = ZZ[ i, j ]
        WW[ i, j ] = near(n p.array( [x, y, z ] ), pointList, 3)
WW = WW / np.amax( WW )
myheatmap = WW

# ~ ax.scatter( *zip( *pointList ), color='#dd00dd' )
ax.plot_surface( XX, YY,  ZZ, cstride=1, rstride=1, facecolors=cm.jet( myheatmap ) )
plt.show() 

Результат выглядит так:

Density shpere

Вы также можете изменить функцию расстояния, чтобы учесть размер кратера, может быть.

...