Issue with the robin projection and contourf data with Basemap - projection

I'm using the basemap library to display spatial information from Copernicus program.
The issue is i can not figure out how to project the data on the robin projection, but I do it correctly with the orthogonal projection.
So currently, I tried this :
plt.ioff()
# adapt for location of datasources
filePath = '../data/grib/download.grib'
# load data
grbs = grb.open(filePath)
grbs.seek(0)
data, lats, lons = (None, None, None)
dataUnit = None
title = None
for g in grbs:
data, lats, lons = g.data()
name = g.name
level = g.level
pressureUnit = g.pressureUnits
date = g.validDate
dataUnit = g.units
title = name + ' at ' + str(level) + ' ' + str(pressureUnit) + ' [' + str(date) + ']'
print(title)
break
# mapPlot = Basemap(projection='ortho', lat_0=0, lon_0=0)
mapPlot = Basemap(projection='robin', lat_0=0, lon_0=0, resolution='l')
mapPlot.drawcoastlines(linewidth=0.25)
x, y = mapPlot(lons, lats)
mapPlot.contourf(x, y, data)
mapPlot.colorbar(location='bottom', format='%.1f', label=dataUnit)
plt.title(title)
plt.show()
The orthogonal projection works correctly. But for the robin projection, I have an ... interesting pattern.
What I'm doing wrong ?

So i figure out how to do. I was misled but the first examples I saw.
Here is a my code:
import matplotlib
from mpl_toolkits.basemap import Basemap, shiftgrid
import matplotlib.pyplot as plt
import numpy as np
import pygrib as grb
# Get data
data = g['values']
lats = g['distinctLatitudes'] # 1D vector
lons = g['distinctLongitudes'] # 1D vector
# Useful information for late
name = g.name
level = str(g.level) + g.pressureUnits
date = g.validDate
dataUnit = g.units
# Parse the data
# Shit the data to start à -180. This is important to mark the data to start at -180°
data, lons = shiftgrid(180., data, lons, start=False) # shiftgrid
# Choose a representation (works with both)
# mapPlot = Basemap(projection='ortho', lat_0=0, lon_0=0)
mapPlot = Basemap(projection='robin', lat_0=0, lon_0=0)
mapPlot.drawcoastlines(linewidth=0.25)
# Convert the coordinates into the map projection
x, y = mapPlot(*np.meshgrid(lons, lats))
# Display data
map = mapPlot.contourf(x, y, data, levels=boundaries, cmap=plt.get_cmap('coolwarm'))
# Add what ever you want to your map.
mapPlot.nightshade(date, alpha=0.1)
# Legend
mapPlot.colorbar(map, label=dataUnit)
# Title
plt.title(name + ' at ' + str(level) + ' [' + str(date) + ']')
plt.show()
So it returns what I'm expecting.

Related

Bokeh ColumnDataSource Error when identifying as source - why?

I'm getting error messages when identifying ColumnDataSource as my source, want to do it right.
Let me show the errors.
First, I generate some random data in a DataFrame and put it into the ColumnDataSource:
col_list = ['ob1','ob2','ob3','ob4','ob5']
df = pd.DataFrame(np.random.uniform(73.965,74.03,size=(25, 5)).astype(float), columns=col_list)
df.reset_index(inplace=True)
df = df.rename(columns = {'index':'order'})
df['order'] = df['order'] + 1
cds = ColumnDataSource(data=df)
So far so good.
I try to generate a graph:
p = figure(title = 'ColumnDataSource test', sizing_mode = 'stretch_both')
p.line(x=cds.data['order'], y = cds.data['ob1'], source = cds.data[['order', 'ob1']])
show(p)
and get the following error:
Traceback (most recent call last):
File "e:\Black_Belt_Six_Sigma\first_take.py", line 57, in <module>
p.line(x=cds.data['order'], y = cds.data['ob1'], source = cds.data[['order', 'ob1']])
TypeError: unhashable type: 'list'
Fair enough, I won't give the source parameter a list and try again:
p = figure(title = 'ColumnDataSource test', sizing_mode = 'stretch_both')
p.line(x=cds.data['order'], y = cds.data['ob1'], source = cds.data)
show(p)
I get no graph but only the following error:
RuntimeError:
Expected x and y to reference fields in the supplied data source.
When a 'source' argument is passed to a glyph method, values that are sequences
(like lists or arrays) must come from references to data columns in the source.
For instance, as an example:
source = ColumnDataSource(data=dict(x=a_list, y=an_array))
p.circle(x='x', y='y', source=source, ...) # pass column names and a source
Alternatively, *all* data sequences may be provided as literals as long as a
source is *not* provided:
p.circle(x=a_list, y=an_array, ...) # pass actual sequences and no source
Based on this error message I've tried the following:
cds = ColumnDataSource(data=dict(order = df['order'].to_list(), ob1 = df['ob1'].to_list()))
p = figure(title = 'ColumnDataSource test', sizing_mode = 'stretch_both')
p.line(x=cds.data['order'], y = cds.data['ob1'], source = cds)
show(p)
And
cds = ColumnDataSource(data=dict(order = df['order'], ob1 = df['ob1']))
p = figure(title = 'ColumnDataSource test', sizing_mode = 'stretch_both')
p.line(x=cds.data['order'], y = cds.data['ob1'], source = cds)
show(p)
Both keep returning the same error message.
I can get a graph/plot if I don't specify the source parameter, so maybe that's the right course of action? Seems odd, I imagine it's important if the developers made it a parameter.
You should pass your dictionary keys order and ob1 directly to the arguments x and y. And your ColumDataSource cds to the argument source (see more examples here):
import pandas as pd
import numpy as np
from bokeh.plotting import figure, show
from bokeh.models import ColumnDataSource
col_list = ['ob1','ob2','ob3','ob4','ob5']
df = pd.DataFrame(np.random.uniform(73.965,74.03,size=(25, 5)).astype(float), columns=col_list)
df.reset_index(inplace=True)
df = df.rename(columns = {'index':'order'})
df['order'] = df['order'] + 1
cds = ColumnDataSource(data=df)
p = figure(title = 'ColumnDataSource test', sizing_mode = 'stretch_both')
p.line(x='order',y='ob1',source=cds)
show(p)

Plotting a 3D surface in Julia, using either Plots or PyPlot

I would like to plot a two variable function(s) (e_pos and e_neg in the code). Here, t and a are constants which I have given the value of 1.
My code to plot this function is the following:
t = 1
a = 1
kx = ky = range(3.14/a, step=0.1, 3.14/a)
# Doing a meshgrid for values of k
KX, KY = kx'.*ones(size(kx)[1]), ky'.*ones(size(ky)[1])
e_pos = +t.*sqrt.((3 .+ (4).*cos.((3)*KX*a/2).*cos.(sqrt(3).*KY.*a/2) .+ (2).*cos.(sqrt(3).*KY.*a)));
e_neg = -t.*sqrt.((3 .+ (4).*cos.((3)*KX*a/2).*cos.(sqrt(3).*KY.*a/2) .+ (2).*cos.(sqrt(3).*KY.*a)));
using Plots
plot(KX,KY,e_pos, st=:surface,cmap="inferno")
If I use Plots this way, sometimes I get an empty 3D plane without the surface. What am I doing wrong? I think it may have to do with the meshgrids I did for kx and ky, but I am unsure.
Edit: I also get the following error:
I changed some few things in my code.
First, I left the variables as ranges. Second, I simply computed the functions I needed without mapping the variables onto them. Here's the code:
t = 2.8
a = 1
kx = range(-pi/a,stop = pi/a, length=100)
ky = range(-pi/a,stop = pi/a, length=100)
#e_pos = +t*np.sqrt(3 + 4*np.cos(3*KX*a/2)*np.cos(np.sqrt(3)*KY*a/2) + 2*np.cos(np.sqrt(3)*KY*a))
e_pos(kx,ky) = t*sqrt(3+4cos(3*kx*a/2)*cos(sqrt(3)*ky*a/2) + 2*cos(sqrt(3)*ky*a))
e_neg(kx,ky) = -t*sqrt(3+4cos(3*kx*a/2)*cos(sqrt(3)*ky*a/2) + 2*cos(sqrt(3)*ky*a))
# Sort of broadcasting?
e_posfunc = e_pos.(kx,ky);
e_negfunc = e_neg.(kx,ky);
For the plotting I simply used the GR backend:
using Plots
gr()
plot(kx,ky,e_pos,st=:surface)
plot!(kx,ky,e_neg,st=:surface, xlabel="kx", ylabel="ky",zlabel="E(k)")
I got what I wanted!

VTK Plane through 3D points

I have a set of 3D points and need to fit the best fitting plane which I am doing with the following code (found on stackoverflow):
points = np.reshape(points, (np.shape(points)[0], -1))
assert points.shape[0] <= points.shape[1], "There are only {} points in {} dimensions.".format(points.shape[1], points.shape[0])
ctr = points.mean(axis=1)
x = points - ctr[:, np.newaxis]
M = np.dot(x, x.T)
return ctr, svd(M)[0][:,-1] # return point and normal vector
Afterwards I want to display the plane in VTK. The problem is I have to scale the plane, but when I do so the plane is translated as well. How can I prevent that from happening ?
def create_vtk_plane_actor(point, normal_vector):
print("\n Display plane with point: %s and vector: %s" % (point, normal_vector))
plane_source = vtk.vtkPlaneSource()
plane_source.SetOrigin(point[0], point[1], point[2])
plane_source.SetNormal(normal_vector[0], normal_vector[1], normal_vector[2])
plane_source.Update()
transform = vtk.vtkTransform()
transform.Scale(1.5, 1.5, 1.0)
transform_filter = vtk.vtkTransformFilter()
transform_filter.SetInputConnection(plane_source.GetOutputPort())
transform_filter.SetTransform(transform)
actor = vtk.vtkActor()
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(transform_filter.GetOutputPort())
The scale is not applied on some coordinates local to your plan but on those you set. So indeed, the center will move. If you want to let it, you need to set a Translate on your transform.
Fitting planes is a builtin feature in vtkplotter, scaling is done with mesh.scale():
from vtkplotter import *
from vtkplotter import datadir
from vtkplotter.pyplot import histogram
plt = Plotter()
apple = load(datadir+"apple.ply").subdivide().addGaussNoise(1)
plt += apple.alpha(0.1)
variances = []
for i, p in enumerate(apple.points()):
pts = apple.closestPoint(p, N=12) # find the N closest points to p
plane = fitPlane(pts) # find the fitting plane and scale
variances.append(plane.variance)
if i % 400: continue
print(i, plane.variance)
plt += plane.scale(2)
plt += Points(pts)
plt += Arrow(plane.center, plane.center+plane.normal/10)
plt += histogram(variances).scale(6).pos(1.2,.2,-1)
plt.show()

Getting Error "list indices must be integers or slices, not float" using folium to draw cluster points on a map

I am trying to create a cluster point on a map using. This is the code i have used but i am getting the error "list indices must be integers or slices, not float"
# Create map
map_clusters = folium.Map(location=[kol_lat, kol_lng], zoom_start=11)
# Set color scheme for the clusters
x = np.arange(kclusters)
ys = [i + x + (i*x)**2 for i in range(kclusters)]
colors_array = cm.rainbow(np.linspace(0, 1, len(ys)))
rainbow = [colors.rgb2hex(i) for i in colors_array]
# Add markers to the map
markers_colors = []
for lat, lon, poi, cluster in zip(kolkata_merged['Latitude'], kolkata_merged['Longitude'], kolkata_merged['Neighbourhood'], kolkata_merged['Cluster Labels']):
label = folium.Popup(str(poi) + ' (Cluster ' + str(cluster + 1) + ')', parse_html=True)
map_clusters.add_child(
folium.features.CircleMarker(
[lat, lon],
radius=5,
popup=label,
color=rainbow[cluster-1],
fill=True,
fill_color=rainbow[cluster-1],
fill_opacity=0.7))
map_clusters
Make sure there are no NaN values in your dataframe.
Then try using color=rainbow[int(cluster)-1],

Add Unique Links to all Data Points in Graph with rCharts

I'm using rCharts to create a scatterplot that displays ratings that I have calculated over time. I have more information for each individual data point (rating) and would like to have each data point on the graph link to a unique page with more information about that specific data point.
For example: I would like to be able to hover over the first data point on the graph and click on it to go to a specific page (http://www.example.com/info?id=1) that provides more information about that rating or data point. Each data point has a unique id and unique url that I would like to link to.
Here is the code that I am using to generate the graph
library(rCharts)
age <- c(1:20)
tall <- seq(0.5, 1.90, length = 20)
name <- paste(letters[1:20], 1:20, sep = "")
df <- data.frame(age = age, tall = tall, name = name)
n1 <- nPlot(age ~ tall ,data = df, type = "scatterChart")
n1$xAxis(axisLabel = "the age")
n1$yAxis(axisLabel = "the tall", width = 50)
n1$chart(tooltipContent = "#! function(key, x, y, e ){
var d = e.series.values[e.pointIndex];
return 'x: ' + x + ' y: ' + y + ' name: ' + d.name
} !#")
n1
This should definitely be considered a hack for now, but it works. Issues that we face here that cause us to require this hack are the draw function in the standard rCharts template does not offer us a place to add bits of code for nvd3, and the afterScript for nvd3 falls outside of our draw so is called before the chart is rendered. Also, the nvd3 tooltip is just html, but the problem with providing a link here to click is that mouseover is triggered and the tooltip disappears before we can click on it (fun trick but not useful). So, in this hack we will hijack the tooltip content function to also specify a click event function.
I tried to be clear with comments, but please let me know if none of this makes sense. I certainly do not make a career out of support :), so I have not built up that skill set.
library(rCharts)
age <- c(1:20)
tall <- seq(0.5, 1.90, length = 20)
name <- paste(letters[1:20], 1:20, sep = "")
#this next line is not entirely necessary if other data
#provides the part of the link address
#will also comment in the js piece below to show
#how to handle that
links <- paste0("http://example.com/",name)
df <- data.frame(age = age, tall = tall, name = name, links = links)
n1 <- nPlot(age ~ tall ,data = df, type = "scatterChart")
n1$xAxis(axisLabel = "the age")
n1$yAxis(axisLabel = "the tall", width = 50)
n1$chart(tooltipContent = "#! function(key, x, y, e ){
d3.selectAll('[class*=\"nv-path\"]').on('click',function(){
//uncomment debugger if you want to see what you have
//debugger;
window.open(d3.select(this).datum().data['point'][4].links,'_blank');
//as stated in the r code generating this
//the link address might be in the data that we already have
//window.open(
// 'http://example.com/' + d3.select(this).datum().data['point'][4].name,
// '_blank'
//);
})
//looks like the actual point is below the hover tooltip path
//if tooltips disabled we could do click on the actual points
//d3.selectAll('.nv-group circle').on('click',function(){
// debugger;
//})
var d = e.series.values[e.pointIndex];
return 'x: ' + x + ' y: ' + y + ' name: ' + d.name
} !#")
n1
I hope it helps.

Resources