mirror of
https://bitbucket.org/cosmicvoids/vide_public.git
synced 2025-07-04 15:21:11 +00:00
387 lines
12 KiB
Python
387 lines
12 KiB
Python
#+
|
|
# VIDE -- Void IDentification and Examination -- ./python_tools/vide/voidUtil/plotUtil.py
|
|
# Copyright (C) 2010-2014 Guilhem Lavaux
|
|
# Copyright (C) 2011-2014 P. M. Sutter
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; version 2 of the License.
|
|
#
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License along
|
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
#+
|
|
__all__=['plotNumberFunction','plotEllipDist','plotVoidCells','plotVoronoi']
|
|
|
|
from backend.classes import *
|
|
from .plotDefs import *
|
|
import numpy as np
|
|
import os
|
|
import pylab as plt
|
|
from scipy.spatial import ConvexHull
|
|
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
|
|
rng = np.random.default_rng(11)
|
|
import backend.cosmologyTools as vp
|
|
import backend.surveyTools as sp
|
|
from voidUtil import getArray, shiftPart, getVoidPart
|
|
|
|
def fill_between(x, y1, y2=0, ax=None, **kwargs):
|
|
"""Plot filled region between `y1` and `y2`.
|
|
|
|
This function works exactly the same as matplotlib's fill_between, except
|
|
that it also plots a proxy artist (specifically, a rectangle of 0 size)
|
|
so that it can be added it appears on a legend.
|
|
"""
|
|
ax = ax if ax is not None else plt.gca()
|
|
ax.fill_between(x, y1, y2, interpolate=True, **kwargs)
|
|
p = plt.Rectangle((0, 0), 0, 0, **kwargs)
|
|
ax.add_patch(p)
|
|
|
|
# -----------------------------------------------------------------------------
|
|
def plotNumberFunction(catalogList,
|
|
figDir="./",
|
|
plotName="numberfunc",
|
|
cumulative=True,
|
|
binWidth=1):
|
|
|
|
# plots a cumulative number function
|
|
# catalogList: list of void catalogs to plot
|
|
# figDir: output directory for figures
|
|
# plotName: name to prefix to all outputs
|
|
# cumulative: if True, plots cumulative number function
|
|
# binWidth: width of histogram bins in Mpc/h
|
|
# returns:
|
|
# ellipDistList: array of len(catalogList),
|
|
# each element has array of size bins, number, +/- 1 sigma
|
|
|
|
print("Plotting number function")
|
|
|
|
catalogList = np.atleast_1d(catalogList)
|
|
|
|
plt.clf()
|
|
plt.xlabel("$R_{eff}$ [$h^{-1}Mpc$]", fontsize=14)
|
|
|
|
if cumulative:
|
|
plt.ylabel(r"log ($n$ (> R) [$h^3$ Gpc$^{-3}$])", fontsize=14)
|
|
else:
|
|
plt.ylabel(r"log ($dn/dR$ [$h^3$ Gpc$^{-3}$])", fontsize=14)
|
|
|
|
ellipDistList = []
|
|
|
|
for (iSample,catalog) in enumerate(catalogList):
|
|
sample = catalog.sampleInfo
|
|
data = getArray(catalog.voids, 'radius')
|
|
|
|
if sample.dataType == "observation":
|
|
maskFile = sample.maskFile
|
|
|
|
boxVol = sp.getSurveyProps(maskFile,
|
|
sample.zBoundary[0], sample.zBoundary[1],
|
|
sample.zRange[0], sample.zRange[1], "all",
|
|
selectionFuncFile=sample.selFunFile,
|
|
omegaM=sample.omegaM)[0]
|
|
else:
|
|
boxVol = sample.boxLen*sample.boxLen*(sample.zBoundaryMpc[1] -
|
|
sample.zBoundaryMpc[0])
|
|
|
|
boxVol *= 1.e-9 # Mpc->Gpc
|
|
|
|
bins = int(100./binWidth)
|
|
hist, binEdges = np.histogram(data, bins=bins, range=(0., 100.))
|
|
binCenters = 0.5*(binEdges[1:] + binEdges[:-1])
|
|
|
|
if cumulative:
|
|
foundStart = False
|
|
for iBin in range(len(hist)):
|
|
if not foundStart and hist[iBin] == 0:
|
|
continue
|
|
foundStart = True
|
|
hist[iBin] = np.sum(hist[iBin:])
|
|
|
|
nvoids = len(data)
|
|
var = hist * (1. - hist/nvoids)
|
|
sig = np.sqrt(var)
|
|
|
|
lowerbound = hist - sig
|
|
upperbound = hist + sig
|
|
|
|
mean = np.log10(hist/boxVol)
|
|
lowerbound = np.log10(lowerbound/boxVol)
|
|
upperbound = np.log10(upperbound/boxVol)
|
|
|
|
lineColor = colorList[iSample]
|
|
lineTitle = sample.fullName
|
|
|
|
trim = (lowerbound > .01)
|
|
mean = mean[trim]
|
|
binCentersToUse = binCenters[trim]
|
|
lower = lowerbound[trim]
|
|
upper = upperbound[trim]
|
|
|
|
alpha = 0.55
|
|
fill_between(binCentersToUse, lower, upper,
|
|
label=lineTitle, color=lineColor,
|
|
alpha=alpha,
|
|
)
|
|
|
|
lineStyle = '-'
|
|
plt.plot(binCentersToUse, mean, lineStyle,
|
|
color=lineColor,
|
|
linewidth=3)
|
|
|
|
ellipDistList.append((binCentersToUse, mean, lower, upper))
|
|
|
|
plt.legend(loc = "upper right", fancybox=True, prop={'size':14})
|
|
|
|
plt.savefig(figDir+"/fig_"+plotName+".pdf", bbox_inches="tight")
|
|
plt.savefig(figDir+"/fig_"+plotName+".eps", bbox_inches="tight")
|
|
plt.savefig(figDir+"/fig_"+plotName+".png", bbox_inches="tight")
|
|
|
|
return ellipDistList
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
def plotEllipDist(catalogList,
|
|
figDir="./",
|
|
plotName="ellipdist"):
|
|
|
|
# plots ellipticity distributions
|
|
# catalogList: list of void catalogs to plot
|
|
# figDir: output directory for figures
|
|
# plotName: name to prefix to all outputs
|
|
# returns:
|
|
# ellipDistList: array of len(catalogList),
|
|
# each element has array of ellipticity distributions
|
|
|
|
print("Plotting ellipticity distributions")
|
|
|
|
plt.clf()
|
|
plt.xlabel(r"Ellipticity $\epsilon$", fontsize=14)
|
|
plt.ylabel(r"P($\epsilon$)", fontsize=14)
|
|
|
|
ellipDistList = []
|
|
|
|
catalogList = np.atleast_1d(catalogList)
|
|
|
|
for (iSample,catalog) in enumerate(catalogList):
|
|
sample = catalog.sampleInfo
|
|
data = getArray(catalog.voids, 'ellipticity')
|
|
|
|
dataWeights = np.ones_like(data)/len(data)
|
|
dataHist, dataBins = np.histogram(data, bins=10, weights=dataWeights,
|
|
range=(0.0,0.35))
|
|
binCenters = 0.5*(dataBins[1:] + dataBins[:-1])
|
|
|
|
plt.plot(binCenters, dataHist, label=sample.fullName,
|
|
color=colorList[iSample])
|
|
|
|
ellipDistList.append((dataBins, dataHist,))
|
|
|
|
plt.legend(loc = "upper right", fancybox=True, prop={'size':14})
|
|
|
|
plt.savefig(figDir+"/fig_"+plotName+".pdf", bbox_inches="tight")
|
|
plt.savefig(figDir+"/fig_"+plotName+".eps", bbox_inches="tight")
|
|
plt.savefig(figDir+"/fig_"+plotName+".png", bbox_inches="tight")
|
|
|
|
return
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
def plotVoidCells(catalog,
|
|
voidID,
|
|
figDir="./",
|
|
plotName="cells",
|
|
plotDensity=True,
|
|
sliceWidth=250):
|
|
|
|
# plots the particles belonging to a void
|
|
# catalog: void catalog
|
|
# voidID: ID of void to plot
|
|
# figDir: output directory for figures
|
|
# plotName: name to prefix to all outputs
|
|
# sliceWidth: width of slice in Mpc/h
|
|
|
|
sample = catalog.sampleInfo
|
|
periodicLine = getPeriodic(sample)
|
|
|
|
plt.clf()
|
|
|
|
iVoid = -1
|
|
for i in range(len(catalog.voids)):
|
|
if catalog.voids[i].voidID == voidID:
|
|
iVoid = i
|
|
break
|
|
|
|
if iVoid == -1:
|
|
print("Void ID %d not found!" % voidID)
|
|
return
|
|
|
|
sliceCenter = catalog.voids[iVoid].macrocenter
|
|
|
|
xwidth = sliceWidth
|
|
ywidth = sliceWidth
|
|
zwidth = max(sliceWidth/4., 50)
|
|
|
|
xmin = -xwidth/2.
|
|
xmax = xwidth/2.
|
|
ymin = -ywidth/2.
|
|
ymax = ywidth/2.
|
|
zmin = -zwidth/2.
|
|
zmax = zwidth/2.
|
|
|
|
#Slice Particles
|
|
if plotDensity:
|
|
part = catalog.partPos
|
|
part = shiftPart(part, sliceCenter, periodicLine, catalog.ranges)
|
|
|
|
filter = (part[:,0] > xmin) & (part[:,0] < xmax) & \
|
|
(part[:,1] > ymin) & (part[:,1] < ymax) & \
|
|
(part[:,2] > zmin) & (part[:,2] < zmax)
|
|
part = part[filter]
|
|
|
|
extent = [xmin, xmax, ymin, ymax]
|
|
hist, xedges, yedges = np.histogram2d(part[:,0], part[:,1], normed=False,
|
|
bins=64)
|
|
|
|
hist = np.log10(hist+1)
|
|
plt.imshow(hist,
|
|
aspect='equal',
|
|
extent=extent,
|
|
interpolation='gaussian',
|
|
cmap='YlGnBu_r')
|
|
|
|
|
|
# overlay voids as circles
|
|
fig = plt.gcf()
|
|
|
|
voidPart = getVoidPart(catalog, voidID)
|
|
|
|
newpart = np.zeros((len(voidPart),3))
|
|
volume=np.zeros(len(voidPart))
|
|
radius=np.zeros(len(voidPart))
|
|
|
|
newpart[:,0] = getArray(voidPart, 'x')
|
|
newpart[:,1] = getArray(voidPart, 'y')
|
|
newpart[:,2] = getArray(voidPart, 'z')
|
|
|
|
volume = getArray(voidPart, 'volume')
|
|
radius = (3.*volume/(4.*np.pi))**(1./3.)
|
|
|
|
shiftedPartVoid =shiftPart(newpart,sliceCenter, periodicLine, catalog.ranges)
|
|
|
|
#Limiting plotted cells to cells into the slice
|
|
#Possibility to only plot bigger cells (through cellsradiuslim)
|
|
cellsMinlimz = zmin
|
|
cellsMaxlimz = zmax
|
|
cellsradiuslim = 0.0
|
|
|
|
for p in range(len(volume)):
|
|
if (shiftedPartVoid[p,2]>(cellsMinlimz) and \
|
|
shiftedPartVoid[p,2]<(cellsMaxlimz) and \
|
|
radius[p]>cellsradiuslim):
|
|
color = 'blue'
|
|
circle = plt.Circle((shiftedPartVoid[p,0], \
|
|
shiftedPartVoid[p,1]), \
|
|
radius[p],
|
|
alpha =.2, fc=color,edgecolor=None,linewidth=1)
|
|
fig.gca().add_artist(circle)
|
|
|
|
title="cells"+str(voidID)
|
|
plt.title(title, fontsize=20)
|
|
plotName="cells"+str(voidID)
|
|
|
|
plt.savefig(figDir+"/fig_"+plotName+".pdf", bbox_inches="tight")
|
|
plt.savefig(figDir+"/fig_"+plotName+".eps", bbox_inches="tight")
|
|
plt.savefig(figDir+"/fig_"+plotName+".png", bbox_inches="tight")
|
|
|
|
return
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
def plotVoronoi(catalog,
|
|
voidID,
|
|
figDir="./",
|
|
plotName="voronoi",
|
|
plotCenter = (0,0,0),
|
|
plotWidth = (100,100,25),
|
|
sliceWidth=250):
|
|
|
|
# plots the voronoi cells belonging to a void (or a slice if no void given)
|
|
# catalog: void catalog
|
|
# voidID: ID of void to plot (-1 to use all particles)
|
|
# figDir: output directory for figures
|
|
# plotName: name to prefix to all outputs
|
|
|
|
print("Plotting voronoi cells...")
|
|
sample = catalog.sampleInfo
|
|
|
|
plt.clf()
|
|
fig = plt.figure()
|
|
ax = fig.add_subplot(111, projection='3d')
|
|
|
|
|
|
print(" Selecting particles...")
|
|
if (voidID == -1):
|
|
xmin = plotCenter[0]-plotWidth[0]/2.
|
|
xmax = plotCenter[0]+plotWidth[0]/2.
|
|
ymin = plotCenter[1]-plotWidth[1]/2.
|
|
ymax = plotCenter[1]+plotWidth[1]/2.
|
|
zmin = plotCenter[2]-plotWidth[2]/2.
|
|
zmax = plotCenter[2]+plotWidth[2]/2.
|
|
|
|
partList = []
|
|
for p in catalog.part:
|
|
#print(p.x, p.y, p.z)
|
|
#print(xmin,xmax,ymin,ymax,zmin,zmax)
|
|
if (p.x >= xmin and p.x <= xmax and \
|
|
p.y >= ymin and p.y <= ymax and \
|
|
p.z >= zmin and p.z <= zmax):
|
|
partList.append(p)
|
|
|
|
#ax.set_xlim(xmin,xmax)
|
|
#ax.set_ylim(ymin,ymax)
|
|
#ax_set.zlim(zmin,zmax)
|
|
else:
|
|
partList = getVoidPart(catalog, voidID)
|
|
plotCenter = catalog.voids[voidID].macrocenter
|
|
plotRadius = catalog.voids[voidID].radius
|
|
|
|
xmin = plotCenter[0]-plotRadius
|
|
xmax = plotCenter[0]+plotRadius
|
|
ymin = plotCenter[1]-plotRadius
|
|
ymax = plotCenter[1]+plotRadius
|
|
zmin = plotCenter[2]-plotRadius
|
|
zmax = plotCenter[2]+plotRadius
|
|
|
|
#ax.set_xlim(xmin,xmax)
|
|
#ax.set_ylim(ymin,ymax)
|
|
#ax_set_zlim(zmin,zmax)
|
|
|
|
print(" Working with %d particles..." % len(partList))
|
|
print(" Computing convex hulls and creating polygons...")
|
|
for part in partList:
|
|
adjsPart = []
|
|
for adj in part.adjs:
|
|
adjsPart.append(catalog.partPos[adj])
|
|
|
|
hull = ConvexHull(adjsPart)
|
|
polygon = Poly3DCollection(hull.points[hull.simplices], alpha=0.25,
|
|
facecolors=rng.uniform(0,1,3),
|
|
linewidths=0.01, edgecolors='gray')
|
|
ax.add_collection3d(polygon)
|
|
|
|
ax.scatter(part.x, part.y, part.z, s=0.01, color='black')
|
|
|
|
print(" Saving...")
|
|
plt.savefig(figDir+"/fig_"+plotName+".pdf", bbox_inches="tight")
|
|
plt.savefig(figDir+"/fig_"+plotName+".eps", bbox_inches="tight")
|
|
plt.savefig(figDir+"/fig_"+plotName+".png", bbox_inches="tight")
|
|
|
|
print(" Done!")
|
|
return
|