輝く重み付きグラフ(ネットワーク):頂点とエッジ

Aug 19 2020

私は次のことを行う方法(できればシンプルで、より大きなグラフ用に最適化されたパフォーマンス/速度)を見つけようとしています:

  • グロー効果によるグラフ頂点のスタイリングとそれに応じた強度 VertexWeight

  • グロー効果によるグラフエッジのスタイリングとそれに応じた強度 EdgeWeight

  • DirectedEdgeグロー効果のスタイリングも望ましいです(簡単にするために、から始めることができますUndirectedEdge

たとえば、次のようなものの場合:

RandomGraph[{20,100},
VertexWeight->RandomReal[1,20],
EdgeWeight->RandomReal[1,100],
Background->Black,
BaseStyle->White]

エッジも光る必要があることを除いて、以下のようなビジュアルを探しています。

私が経験している問題。

1.見事な輝きの簡単な実装

私はさまざまなグロー(含む効果を見てきましたTHISポイントを輝く程度)ではなく、パフォーマンスのアイデア対最高のビジュアルの専門家を。驚いたことに、私は周りの輝く線についてあまり見ていません。私は素朴にこのようなものから始めますが、それはおそらく視覚的およびパフォーマンス的に改善することができます:

bsc=BSplineCurve[{{0,0},{1,1},{2,0}}];
Graphics[
    Table[{White,Opacity[1/k^1.2],Thickness[.005k],CapForm["Round"],bsc},{k,20}],
Background->Black]

2.ウェイトを渡して光らせる

私が知っている間VertexShapeFunctionEdgeShapeFunction、私は最適それらに重みを渡す方法は非常にわからない...と、これらの特性は、正しいアプローチであれば。

組み込み関数で光る

これらの関数がいくつかの輝きを生み出すことに気づきました:

ComplexPlot[z^2+1,{z,-2-2I,2+2I},ColorFunction->"CyclicReImLogAbs"]

そして、@ ECが彼の答えで気づいたように

ImageAdjust[DistanceTransform[Graphics[Point[RandomReal[1,{100,2}]]]]]

ありがとう、あなたの助けは大歓迎です!

回答

14 flinty Aug 19 2020 at 22:41

ImageAddイメージマスクのコピーをぼかして、全体的なグロー効果を得ることができます。確かにそれは少し基本的ですが、効果は説得力があります。私が使用しての脳のネットワークを作ることを選んだAnatomyDataNearestNeighbourGraph、それはいくつかの過剰宣伝AIのマーケティングの事のように見えるようにします:

SeedRandom[123];
brain = AnatomyData[Entity["AnatomicalStructure", "Brain"], "MeshRegion"];
boundary = RegionBoundary[brain];
nng = NearestNeighborGraph[RandomPoint[boundary, 1000], 7];
brainnetimg = Rasterize[
   GraphPlot3D[nng, ViewPoint -> Left, 
    VertexStyle -> Directive[AbsolutePointSize[7], White], 
    EdgeStyle -> Directive[AbsoluteThickness[2], White], 
    Background -> Black]
   , ImageSize -> 1000];
ImageAdd[ImageAdjust[Blur[Binarize@brainnetimg, 7], .1], 
 ImageMultiply[brainnetimg, 
  LinearGradientImage[{Blue, Cyan, Purple}, 
   ImageDimensions[brainnetimg]]]]

あなたの輝きの大きさに影響を与えるように重みを取得するには、おそらく使用する必要がありますEdgeShapeFunctionVertexShapeFunction。アルファを使用してレンズ効果のビルボードテクスチャを作成し、この画像を頂点に使用しました。

また、線を重ねる質問でおっしゃったエッジグロー効果も使用しました。ウェイトが大きいエッジほどグローが大きくなり、ウェイトが大きい頂点ほどフレアが大きくなります。

SeedRandom[123];
G = SpatialGraphDistribution[100, 0.20];
g = RandomGraph[G];
glowtexture = Import["lensbb.png"];
edgeWeights = RandomReal[1, EdgeCount[g]];
vertexWeights = RandomReal[1, VertexCount[g]];

edgeShapeFunc = 
  With[{weight = AnnotationValue[{g, #2}, EdgeWeight]}, 
    Table[{RGBColor[0.7, 1.0, 0.9], Opacity[1/k^1.3], 
      Thickness[.001 k*weight], CapForm["Round"], Line[#1]}, {k, 20}]] &;

vertexShapeFunc = 
  With[{weight = AnnotationValue[{g, #2}, VertexWeight]}, 
    Inset[glowtexture, #1, Center, weight*0.3]] &;

g = Graph[g, EdgeWeight -> edgeWeights, VertexWeight -> vertexWeights,
   VertexShapeFunction -> vertexShapeFunc, Background -> Black, 
  EdgeShapeFunction -> edgeShapeFunc, PlotRangePadding -> .1]

上記のラインスタッキング/不透明度のトリックを使用して光るエッジを生成するのではなく、代わりにテクスチャポリゴンを使用することもできます。これは高速ですが、エッジが厚くなりすぎると、キャップが見えて醜くなります。

g = Graph[UndirectedEdge @@@ {{1, 2}, {2, 3}, {3, 1}}];
edgeWeights = {1, 2, 3}/6.;
vertexWeights = {1, 2, 3}/6.;

glowtexture = Import["lensbb.png"];
edgegradimg = LinearGradientImage[{Transparent,Cyan,Transparent}, {64,64}];

edgeShapeFunc = 
  Module[{weight = AnnotationValue[{g, #2}, EdgeWeight], s = 1/10., 
     vec = #1[[2]] - #1[[1]], perp},
    perp = Cross[vec];
    {Texture[edgegradimg], 
     Polygon[{
         #1[[1]]-perp*weight*s, 
         #1[[1]]+perp*weight*s,
         #1[[2]]+perp*weight*s,
         #1[[2]]-perp*weight*s
     }, VertexTextureCoordinates -> {{0,0},{1,0},{1,1},{0,1}}]
    }] &;

vertexShapeFunc = 
  With[{weight = AnnotationValue[{g, #2}, VertexWeight]}, 
    Inset[glowtexture, #1, Center, weight*3]] &;

g = Graph[g, EdgeWeight -> edgeWeights, VertexWeight -> vertexWeights,
   VertexShapeFunction -> vertexShapeFunc, Background -> Black, 
  EdgeShapeFunction -> edgeShapeFunc, PlotRangePadding -> .5]

8 C.E. Aug 19 2020 at 14:37

DistanceTransform グローに必要なタイプの距離マップを提供します。

まず、光源を定義します。

bg = ConstantImage[White, 200];
line = HighlightImage[
  bg, {
   Black,
   Thick,
   Line[{{50, 100}, {150, 100}}]
   }]

次に、距離変換を計算します。結果の画像の1が画像の対角線に対応するようにスケーリングします。

glow = ColorNegate@Image[Divide[
     ImageData@DistanceTransform[line],
     200 Sqrt[2]
     ]^0.2]

数値0.2は、グローが消える速さを制御します。

次に、グローに色を適用できます。

glow ConstantImage[Red, 200]

また、色関数を適用することもできます。

ImageApply[List @@ ColorData["AvocadoColors", #] &, glow]

素敵なカラー関数を作成することは、あなたの例のような素敵な輝きを作成するための鍵になります。

この手法を使用すると、光るグラフを作成するのは非常に簡単です。すべてのエッジは線であり、すべての頂点は点またはディスクです。結局、それらを1つの画像にまとめることができます。

このための堅牢な関数を作成するのは読者に任せます。小さな例を挙げます。

例として、パップスグラフを使用します。

embedding = First@GraphData["PappusGraph", "Embeddings"];
coords = List @@@ GraphData["PappusGraph", "Edges"] /. Thread[
    Range[Length[embedding]] -> embedding
    ];
Graphics[{
  Point[embedding],
  Line[coords]
  }]

グラフィックではなく画像に描画するには、座標を再スケーリングする必要があります。

toImageCoordinates[{x_, y_}] := {
  Rescale[x, {-1, 1}, {0, 200}],
  Rescale[y, {-1, 1}, {0, 200}]
  }

primitives = Join[
   Point@*toImageCoordinates /@ embedding,
   Line@*toImageCoordinates /@ coords
   ];

この関数は、グローでプリミティブを描画します。

draw[primitive_, size_, glow_] := Module[{bg, img},
  bg = ConstantImage[White, 200];
  img = HighlightImage[bg, {
     Black,
     PointSize[Large],
     Thick,
     primitive
     }];
  ColorNegate@Image[Divide[
      ImageData@DistanceTransform[img],
      size Sqrt[2]
      ]^glow]
  ]

draw[First@primitives, 200, 0.2]

ここでの計画は、この関数をすべてのプリミティブにマップすることです。

images = draw[#, 200, 0.2] & /@ primitives;
ImageAdd @@ images // ImageAdjust

このことから、エッジとポイントのグローの量が異なる可能性があることは明らかです。時間の制約があるため、これらすべてをまとめた関数を「グローインググラフ」関数にすることはしませんが、この問題を解決するための可能なアプローチとしてここに残しておきます。