Proj4 to Cartopy CRS - cartopy

I am trying to create a Cartopy CRS object from rotated pole definitional values (see dict below) in order to pass that CRS to hvplot and plot the xarray.Dataset
{
'grid_mapping_name': 'rotated_latitude_longitude',
'earth_radius': 6370997.0,
'grid_north_pole_latitude': 36.08852040966241,
'grid_north_pole_longitude': 65.30514195843372
}
currently I have it working using pyproj
pyproj.crs.CRS.from_cf(xd_initial.rotated_pole.attrs).to_proj4()
but I get a warning and would love to learn a better way
[output]
/fs/ssm/eccc/cmd/cmds/env/python/latest/lib/python3.9/site-packages/pyproj/crs/crs.py:1282: UserWarning: You will likely lose important projection information when converting to a PROJ string from another format. See: https://proj.org/faq.html#what-is-the-best-format-for-describing-coordinate-reference-systems
proj = self._crs.to_proj4(version=version)
'+proj=ob_tran +o_proj=longlat +o_lon_p=0 +o_lat_p=36.0885204096624 +lon_0=245.305141958434 +ellps=sphere +no_defs +type=crs'

Related

Is Cartopy capable of plotting georeferenced data from another planet (e.g., Mars, the Moon)?

I'm working with several data sets from the Moon and Mars (topography, crustal thickness) and was wondering if Cartopy can manipulate these data given the reference ellipsoids are different. Do custom ellipsoids need to be created, or are they built in to Cartopy?
I figured out how to do this on my own. Here's the solution I came up with...
Step 1
Import Cartopy...
import cartopy.crs as ccrs
After importing Cartopy and loading your data set, you need to change Cartopy's Globe class such that it does not use the WGS84 ellipse. Simply define new semi-major and semi-minor axes and tell Cartopy to refrain from using a terrestrial ellipse.
img_globe = ccrs.Globe(semimajor_axis = semimajor, semiminor_axis = semiminor, ellipse = None)
Step 2
Next, choose a map projection for plotting and identify your data's format. I decided to plot my data using a Mollweide coordinate system and found my data is defined in the Plate Carree coordinate system. Now we can define the map projection and coordinate system for the data using the new Globe class defined above.
projection = ccrs.Mollweide(globe = img_globe)
data_crs = ccrs.PlateCarree(globe = img_globe)
Step 3
Lastly, plot your data using standard Matplotlib syntax with two important caveats. First create axes that implement the map projection.
fig = plt.figure(figsize = (6,6))
ax = plt.axes(projection = projection)
When plotting the data, you have to inform Matplotlib how your data are formatted using the transform argument.
ax.imshow(data, extent = extent, cmap = 'viridis', transform = data_crs)
The end result looks like this...

Use folium Map as holoviews DynamicMap

I have a folium.Map that contains custom HTML Popups with clickable URLs. These Popups open when clicking on the polygons of the map. This is a feature that doesn't seem to be possible to achieve using holoviews.
My ideal example of the final application that I want to build with holoviews/geoviews is here with the source code here, but I would like to exchange the main map with my folium Map and plot polygons instead of rasterized points. Now when I would like to create the holoviews.DynamicMap from the folium.Map, holoviews complains (of course) that the data type "map" is not accepted. Is this somehow still possible?
I have found some notebook on GitHub where a holoviews plot in embedded in a folium map using a workaround that writes and reads again HTML, but it seems impossible to embed a folium map into holoviews such that other plots can be updated from this figure using Streams!?
Here is some toy data (from here) for the datasets that I use. For simplicity, let's assume I just had point data instead of polygons:
import folium as fn
def make_map():
m = fm.Map(location=[20.59,78.96], zoom_start=5)
green_p1 = fm.map.FeatureGroup()
green_p1.add_child(
fm.CircleMarker(
[row.Latitude, row.Longitude],
radius=10,
fill=True,
fill_color=fill_color,
fill_opacity=0.7
)
)
map.add_child(green_p1)
return map
If I understand it correctly, this needs to be tweaked now in the fashion that it can passed as the first argument to a holoviews.DynamicMap:
hv.DynamicMap(make_map, streams=my_streams)
where my_streams are some other plots that should be updated with the extent of the folium map.
Is that somehow possible or is my strategy wrong?

save pyplot figure "as figure" (not as image)

How can I save a figure using PyPlot in Julia, so that the figure can be reloaded as a figure later in Julia? (not as an image)
You can use serialize to store any Julia object. This beautifully works for plots as well.
Let us start by generating a plot:
using Plots
pyplot()
p = plot(rand(10));
using Serialization
Serialization.serialize("myfile.jld", p);
Note that you need a semicolon after plot command so it does not appear on the screen.
Let us now read the plot (to have a full test I ended the previous Julia session and started a new one):
using Plots
pyplot();
using Serialization
p2 = Serialization.deserialize("myfile.jld");
In order to display it now it is enough to type in REPL:
julia> p2
You might want also want to use plain PyPlot (I strongly recommend Plots for flexibility). In that case your best bet is to follow rules described in object-oriented API of Matplotlib:
using PyPlot
ioff()
fig = subplot()
fig.plot(rand(10))
fig.set_title("Hello world")
using Serialization
serialize("pp.jld", fig)
In order to plot de-serialize back the object:
using PyPlot
ioff()
using Serialization
fig = deserialize("pp.jld")
show()
Finally, note that the serialization is good only for short term storage. If anything changes (e.g. you update Julia packages) you might not be able to de-serialize the plot.
Hence another good alternative for processable plots are saving them to LaTeX or SVG format - both is possible in Julia.

PyPlot Error in Julia: type PyObject has no field set_yscale

I am programming in Julia but using PyPloy library. I want to plot an histogram with log y-axis. But when I use the following code:
using PyPlot
List = [rand() for i = 1:100]
plt.hist(List)
plt.gca().set_yscale("log")
I get the following error:
type PyObject has no field set_yscale
while loading In[45], in expression starting on line 3
in getindex at /home/rm/.julia/v0.4/PyCall/src/PyCall.jl:642
in pysequence_query at /home/rm/.julia/v0.4/PyCall/src/conversions.jl:743
in pytype_query at /home/rm/.julia/v0.4/PyCall/src/conversions.jl:759
in convert at /home/rm/.julia/v0.4/PyCall/src/conversions.jl:808
in pycall at /home/rm/.julia/v0.4/PyCall/src/PyCall.jl:812
in fn at /home/rm/.julia/v0.4/PyCall/src/conversions.jl:181
in close_queued_figs at /home/rm/.julia/v0.4/PyPlot/src/PyPlot.jl:295
Is this a path error? If so, is there a simpler way to do a log-log plot with a different command?
Thanks in advance.
I feel like this should be more prominently explained in the documentation, but if you scroll down to the bottom of the Readme for PyCall (which PyPlot uses) it says:
Important: The biggest difference from Python is that object attributes/members are accessed with o[:attribute] rather than o.attribute, so that o.method(...) in Python is replaced by o[:method](...)
So, as #jverzani mentioned, after you call any module-level function from PyPlot that returns an object, that object is a PyObject and all of the attributes and methods have to be called using the bracket notation with a symbol.

PathPatch object in julia with PyPlot

I was trying to reproduce this example from the matplotlib website using the PyPlot package for Julia. As far as I know, the PyPlot is essentialy the matplotlib.pyplot module, so I imported the other modules of matplotlib that I needed (with the #pyimport macro):
using PyCall
#pyimport matplotlib.path as mpath
#pyimport matplotlib.patches as mpatches
Then I proceed to define the path object:
Path = mpath.Path
but then I get:
fn (generic function with 1 method) .
As if I had defined a function. Moreover, when I assign the path_data I get the following error:
ERROR: type Function has no field MOVETO
Of course, that's due to Path, which Julia tries as a function and not as a type or something like that. As you might guess the same happens when I try to define the variable patch .
So, there are incompatibilities of modules from matplotlib different to pyplot for Julia since the expected objects (types) are taken as functions. This behaviour can be expected if it were different the PyPlot.jl file wouldn't be needed.
My questions are:
-Am I doing something wrong?
-Is there a simple way to make it works?
-Do you know another package for Julia in which I can define patches and work in a similar way to matplotlib?
I have in mind to do this kind of animations.
Thanks for your ideas.
You need to get the "raw" Python object for Path. By default, PyCall converts Python type objects into functions (which call the corresponding constructor), but then you cannot access static members of the class.
Instead, do e.g. Path = mpath.pymember("Path") to get the "raw" PyObject, and then you can do Path["MOVETO"] or Path[:MOVETO] to access the MOVETO member.
(This difficulty will hopefully go away in Julia 0.4 once something like https://github.com/JuliaLang/julia/pull/8008 gets merged (so that we can make PyObjects callable directly.)