Grafico ponderato incandescente (rete): vertici e bordi
Sto cercando di trovare un modo (desiderabilmente semplice e prestazioni / velocità ottimizzate per grafici più grandi) per fare quanto segue:
Stile dei vertici del grafico in base all'effetto bagliore e alla sua intensità a seconda
VertexWeight
Disegnare i bordi del grafico in base all'effetto bagliore e alla sua intensità a seconda
EdgeWeight
DirectedEdge
anche lo styling effetto bagliore è desiderabile (mentre per semplicità le cose possono iniziareUndirectedEdge
)
Ad esempio per qualcosa di simile:
RandomGraph[{20,100},
VertexWeight->RandomReal[1,20],
EdgeWeight->RandomReal[1,100],
Background->Black,
BaseStyle->White]
sto cercando un'immagine simile a questa qui sotto, tranne che anche i bordi devono brillare:

I problemi che sto riscontrando.
1. Semplice implementazione di un bagliore sbalorditivo
Ho visto vari effetti di bagliore (incluso QUESTO sui punti luminosi) ma non sono un esperto delle migliori idee visive rispetto alle prestazioni. Sorprendentemente, inoltre, non ho visto molto sulle linee luminose intorno. Comincerei ingenuamente con qualcosa di simile, ma probabilmente può essere migliorato visivamente e in termini di prestazioni:
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. Passaggio di pesi per illuminare
Sebbene ne sia a conoscenza VertexShapeFunction
e EdgeShapeFunction
, non sono del tutto sicuro di come passare in modo ottimale i pesi a loro ... e se queste proprietà sono l'approccio giusto.
Bagliore nelle funzioni integrate
Ho notato che queste funzioni producono un po 'di bagliore:
ComplexPlot[z^2+1,{z,-2-2I,2+2I},ColorFunction->"CyclicReImLogAbs"]

E come notato da @EC nella sua risposta sotto qualcosa di simile
ImageAdjust[DistanceTransform[Graphics[Point[RandomReal[1,{100,2}]]]]]

Grazie, il tuo aiuto è molto apprezzato!
Risposte
È possibile ottenere un effetto bagliore generale ImageAdd
con una copia sfocata della maschera dell'immagine. Certo è un po 'semplice, ma l'effetto è convincente. Ho scelto di creare una rete `` cerebrale '' usando AnatomyData
e NearestNeighbourGraph
per farla sembrare una cosa di marketing AI troppo pubblicizzata:
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]]]]
Per fare in modo che i pesi influiscano sulla dimensione del bagliore probabilmente dovrai usare EdgeShapeFunction
e VertexShapeFunction
. Ho creato una trama cartellone di un effetto lente con alfa e ho usato questa immagine per i vertici:
Ho anche usato l'effetto bagliore sui bordi che hai menzionato nella domanda che impila le linee. I bordi con più peso dovrebbero avere più bagliore, mentre i vertici con più peso avranno un bagliore più grande:
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]
Invece di usare il trucco di sovrapposizione / opacità sopra per produrre i bordi luminosi, potresti anche usare poligoni strutturati. Questo è più veloce ma uno svantaggio è che quando i bordi diventano troppo spessi i cappucci sono visibili e brutti:
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]

DistanceTransform
ci fornisce una mappa della distanza del tipo di cui abbiamo bisogno per il bagliore.
Per prima cosa definiamo la sorgente luminosa:
bg = ConstantImage[White, 200];
line = HighlightImage[
bg, {
Black,
Thick,
Line[{{50, 100}, {150, 100}}]
}]

Successivamente, calcoliamo la trasformazione della distanza. Lo scaliamo in modo tale che 1 nell'immagine risultante corrisponda alla diagonale dell'immagine.
glow = ColorNegate@Image[Divide[
ImageData@DistanceTransform[line],
200 Sqrt[2]
]^0.2]

Il numero 0.2 controlla quanto velocemente il bagliore si spegne.
Successivamente, possiamo applicare un colore al bagliore:
glow ConstantImage[Red, 200]

E possiamo anche applicare le funzioni del colore:
ImageApply[List @@ ColorData["AvocadoColors", #] &, glow]

Creare una bella funzione di colore sarà la chiave per creare un bagliore piacevole come quello del tuo esempio.
La creazione di un grafico luminoso è abbastanza semplice utilizzando questa tecnica. Ogni bordo è una linea e ogni vertice è un punto o un disco. Alla fine, possiamo metterli insieme in un'immagine.
Lascio al lettore la creazione di una robusta funzione per questo. Faccio solo un piccolo esempio.
Useremo il grafico Pappus per l'esempio:
embedding = First@GraphData["PappusGraph", "Embeddings"];
coords = List @@@ GraphData["PappusGraph", "Edges"] /. Thread[
Range[Length[embedding]] -> embedding
];
Graphics[{
Point[embedding],
Line[coords]
}]

Disegnarlo su un'immagine invece che in una grafica richiede il ridimensionamento delle coordinate:
toImageCoordinates[{x_, y_}] := {
Rescale[x, {-1, 1}, {0, 200}],
Rescale[y, {-1, 1}, {0, 200}]
}
primitives = Join[
Point@*toImageCoordinates /@ embedding,
Line@*toImageCoordinates /@ coords
];
Questa funzione disegnerà qualsiasi primitiva con un bagliore:
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]

Ora il piano è mappare questa funzione su tutte le primitive.
images = draw[#, 200, 0.2] & /@ primitives;
ImageAdd @@ images // ImageAdjust

È ovvio da questo che bordi e punti possono avere quantità diverse di bagliore. A causa dei vincoli di tempo, non creerò la funzione che mette insieme tutto questo in una funzione "grafico luminoso", ma lo lascio qui come possibile approccio per risolvere questo problema.