DKRZ PyNGL example scatterplot with two additional histograms attached#
Example script:
# File:
# scatter_plot_add_2_histograms.py
#
# Synopsis:
# Create a scatter plot of the data a(t), b(t) and color the
# polymarker by the color of variable c(t). Add additional
# histograms of the counts per selected axis range to the plot.
#
# Category:
# xy plot
# polylines, polygons
# functions
# text
#
# Based on DKRZ's NCL example:
# scatter_plot_add_2_histograms.ncl
#
# Author:
# Karin Meier-Fleischer
#
# Date of initial publication:
# December, 2018
#
# Description:
# Create a scatter plot of the data a(t), b(t) and color the
# polymarker by the color of variable c(t). Add additional
# histograms of the counts per selected axis range to the plot.#
#
# Effects illustrated:
# o Create an xy-plot
# o Define functions
# o Add polymarker, polylines, and polygons
# o Add text
#
# Output:
# One visualization is produced.
#
'''
PyNGL Example: scatter_plot_add_2_histograms.py
- Create an xy-plot
- Define functions
- Add polymarker, polylines, and polygons
- Add text
'''
import numpy as np
import Ngl
#----------------------------------------------------------------------
# Procedure add_histogram: attach a to the plot
#----------------------------------------------------------------------
def add_histogram(wks, plot, data, levels, opt):
#-- retrieve viewport width and height
vpx = Ngl.get_float(plot,"vpXF") #-- retrieve plot x-position
vpy = Ngl.get_float(plot,"vpYF") #-- retrieve plot y-position
vpw = Ngl.get_float(plot,"vpWidthF") #-- retrieve plot width
vph = Ngl.get_float(plot,"vpHeightF") #-- retrieve plot height
if(opt):
if(hasattr(opt,'orientation')):
if(opt.orientation == 'horizontal'):
w = vpw
h = 0.2*vph
ampa = -0.50
amor = -0.66
else:
opt.orientation == 'vertical'
h = vph
w = 0.2*vpw
ampa = 0.58
amor = 0.0
if(hasattr(opt,'numLevels')):
nt = opt.numLevels
else:
nt = 10
if(hasattr(opt,'xRange')):
min1d = opt.xRange[0]
max1d = opt.xRange[1]
else:
min1d = min(data)
max1d = max(data)
hist_levels = np.linspace(min1d, max1d,nt+1)
#-- get the values (counts) for the bars
count = []
for i in range(0,len(hist_levels)-1):
xind = Ngl.ind(np.logical_and(data >= hist_levels[i], data < hist_levels[i+1]))
count.append(len(xind))
#-- set resources
hres = Ngl.Resources()
hres.nglDraw = False
hres.nglFrame = False
if(opt.orientation == "horizontal"):
hres.vpWidthF = w
hres.vpHeightF = h
hres.tmYMajorGrid = True
hres.tmYMajorGridLineColor = "gray50"
hres.tmYMajorGridLineDashPattern = 2
hres.trXMinF = min1d
hres.trXMaxF = max1d
hres.trYMinF = 0
hres.trYMaxF = max(count)+1
elif(opt.orientation == "vertical"):
hres.vpWidthF = w
hres.vpHeightF = h
hres.tmXMajorGrid = True
hres.tmXMajorGridLineColor = "gray50"
hres.tmXMajorGridLineDashPattern = 2
hres.trXMinF = 0
hres.trXMaxF = max(count)+1
hres.trYMinF = min1d
hres.trYMaxF = max1d
hres.tmXBLabelFontHeightF = 0.014
hres.tmYLLabelFontHeightF = 0.014
hres.tmXBLabelStride = 2
hres.tmXBLabelDeltaF = -0.7
hres.tmYLLabelDeltaF = -0.7
hres.tmLabelAutoStride = True #-- use nice tick mark labels
histo = Ngl.blank_plot(wks, hres) #-- create blank plot
#-- set resources for the polylines
polyres = Ngl.Resources() #-- set up defaults
polyres.gsLineColor = 'black' #-- color of lines
polyres.gsFillColor = 'gray70' #-- color of lines
polyres.gsLineThicknessF = 1.5 #-- thickness of lines
polyres.gsLineDashPattern = 0
#-- compute the x- and y-values for the bars and create polygons and polylines
plid = []
pgid = []
for i in range(0,len(hist_levels)-1):
if(opt.orientation == 'horizontal'):
x = [hist_levels[i], hist_levels[i+1], hist_levels[i+1], hist_levels[i], hist_levels[i]]
y = [0,0,count[i],count[i],0]
elif(opt.orientation == 'vertical'):
y = [hist_levels[i], hist_levels[i+1], hist_levels[i+1], hist_levels[i], hist_levels[i]]
x = [0,0,count[i],count[i],0]
pgid.append(Ngl.add_polygon(wks,histo,x,y,polyres)) #-- add polygon to histo
plid.append(Ngl.add_polyline(wks,histo,x,y,polyres)) #-- add polyline to histo
#-- attach histogram to plot
amres = Ngl.Resources()
amres.amJust = "CenterLeft"
amres.amParallelPosF = ampa
amres.amOrthogonalPosF = amor
annoidpg = Ngl.add_annotation(plot,histo,amres)
return(plot)
#----------------------------------------------------------------------
# Procedure add_labelbar: attach a vertical labelbar to the right
# side of the plot
#----------------------------------------------------------------------
def add_labelbar(wks,plot,colors,levels, orient):
#-- retrieve viewport width and height
vpx = Ngl.get_float(plot,"vpXF") #-- retrieve plot x-position
vpy = Ngl.get_float(plot,"vpYF") #-- retrieve plot y-position
vpw = Ngl.get_float(plot,"vpWidthF") #-- retrieve plot width
vph = Ngl.get_float(plot,"vpHeightF") #-- retrieve plot height
if(orient == "horizontal"):
vw = vpw
vh = 0.1*vph
ampa = -0.5
amor = 0.63
elif(orient == "vertical"):
vw = 0.15*vpw
vh = 0.99*vph
ampa = 0.55
amor = 0.0
#-- define labels and retrieve the number of color boxes
labels = levels.astype('str') #-- convert to type string
nboxes = len(colors[:,0]) #-- number of color boxes (nlevels+1)
#-- create labelbar
lbres = Ngl.Resources() #-- labelbar only resources
lbres.vpWidthF = vw #-- labelbar width
lbres.vpHeightF = vh #-- labelbar height
lbres.nglDraw = False
lbres.lbAutoManage = False #-- Necessary to control sizes
lbres.lbFillColors = colors #-- labelbar colors
lbres.lbMonoFillPattern = True #-- Solid fill pattern
lbres.lbLabelFontHeightF = 0.016 #-- font height. default is small
lbres.lbLabelAlignment = "InteriorEdges" #-- line of box
lbres.lbOrientation = orient
lbres.lbPerimOn = False
lbid = Ngl.labelbar_ndc(wks,nboxes,list(labels),0.1,0.5,lbres)
#-- attach labelbar to the plot
amres = Ngl.Resources()
amres.amJust = "CenterLeft"
amres.amParallelPosF = ampa
amres.amOrthogonalPosF = amor
annoid = Ngl.add_annotation(plot,lbid,amres)
#-----------------------------------------------------------------------
#-- Function: main
#-----------------------------------------------------------------------
def main():
#-- set minimum, maximum and interval value to group the data to color and create the labelbar
cmin = -0.8
cmax = 0.8
cint = 0.01
nt = 100 #-- number of data per array
#-- x-,y-data
min1d = -4.0
max1d = 6.0
hist_levels = np.linspace(min1d, max1d,22)
#-- generate random data 100 points (e.g. time steps) data for x-axis
a = np.random.uniform(min1d,max1d,nt)
#-- data for y-axis
b = np.random.uniform(min1d,max1d,nt)
#-- data for coloring
c = np.random.uniform(cmin,cmax,nt)
#-- title string
title = "Scatter plot: x=a(t), y=b(t), colored by c(t)"
#-- set colormap name
colmap = "MPL_viridis" #-- colormap blue-green,yellow
#-- define levels for labelbar and colors
levels1 = np.arange(np.ceil(cmin*10),np.floor(cmax*10),1)/10.0 #-- define levels
levels2 = np.arange(np.ceil(cmin*10),np.floor(cmax*10),1)/10.0 #-- define levels
nlevels = levels1.size #-- number of levels
#-- open workstation
wks_type = "png"
wksres = Ngl.Resources()
wksres.wkWidth = 1200
wksres.wkHeight = 1200
wks = Ngl.open_wks(wks_type,"plot_scatter_attach_two_histograms",wksres)
Ngl.define_colormap(wks,colmap)
#-- retrieve the colors# don't use the first dark blues
colors = Ngl.retrieve_colormap(wks) #-- retrieve color map
colind = np.linspace(20,255,nlevels+1).astype('int') #-- don't use first 20 colors
colors = colors[colind,:]
ncolors = len(colors)
#-- resources
res = Ngl.Resources() #-- plot mods desired
res.nglDraw = False #-- don't draw plot, yet
res.nglFrame = False #-- don't advance frame, yet
res.trYMinF = min1d #-- y-axis minimum to have enough space for legend
res.trYMaxF = max1d #-- y-axis maximum
res.trXMinF = min1d #-- y-axis minimum to have enough space for legend
res.trXMaxF = max1d #-- y-axis maximum
res.tmLabelAutoStride = True #-- use nice tick mark labels
res.vpWidthF = 0.63 #-- viewport width
res.vpHeightF = 0.63 #-- viewport height
res.vpXF = 0.12 #-- viewport x-position
res.vpYF = 0.75 #-- viewport y-position
#-- create blank plot
plot = Ngl.blank_plot(wks, res)
#-- group data and add it as filled circle markers, slightly transparent
mres = Ngl.Resources()
mres.gsMarkerThicknessF = 2.5 #-- marker thickness
mres.gsMarkerOpacityF = 0.8 #-- marker opacity
pltmarker = []
for i in range(0,nlevels-2):
ii = Ngl.ind(np.logical_and(levels1[i] <= c, levels1[i+1] > c))
mres.gsMarkerIndex = 16 #-- filled circle marker
mres.gsMarkerSizeF = 0.01 #-- marker size
mres.gsMarkerColor = colors[i,:] #-- marker color
pltmarker.append(Ngl.add_polymarker(wks,plot,a[ii],b[ii],mres)) #-- add marker
#-- add labelbar
add_labelbar(wks,plot,colors,levels1,'horizontal')
#-- special histogram resources for function add_histogram
opt = Ngl.Resources()
opt.numLevels = 20 #-- number of levels
opt.barColor = 'gray60' #-- fill color
opt.xRange = [min1d,max1d] #-- x-axis range
#-- add histogram at the top
opt.orientation = 'horizontal'
pltid1 = add_histogram(wks, plot, a, levels1, opt)
#-- add histogram at the right side
opt.orientation = 'vertical'
pltid2 = add_histogram(wks, plot, b, levels2, opt)
#-- write title to plot
title = "Scatter plot: x=a(t), y=b(t), colored by c(t)"
txres = Ngl.Resources()
txres.txJust = 'CenterCenter'
txres.txFontHeightF = 0.018
xx = Ngl.get_float(plot,'vpXF')+Ngl.get_float(plot,'vpWidthF')/2
Ngl.text_ndc(wks,title,xx,0.96,txres)
#-- draw the plot and advance the frame
Ngl.draw(plot)
Ngl.frame(wks)
#-- call main function
if __name__ == '__main__':
main()
Result: