I'm trying to call this macro from within a method where the parameters to the macro are passed in to the method. It works fine when I call it directly but there is something about the macro expansion which is preventing the variables lat and lon from being correctly used in the macro.
The macro I'm calling is #select here: https://github.com/Alexander-Barth/NCDatasets.jl/blob/4e35e843a53cdcff7f7ef66ebc3ceab1ee1e860b/src/select.jl#L54-L168
and here is the function where the lat and lon variables are not being expanded correctly
function data_for_lat_lon(ds, region, lat_lon_pair)
println("have latlon piar ", lat_lon_pair)
lat = lat_lon_pair[1]
lon = lat_lon_pair[2]
data = []
if(ArchGDAL.contains(region[1], ArchGDAL.createpoint(lon, lat)))
println(lat, " ", lon)
#the below call fails when called in this way
single_lat_lon = NCDatasets.#select(ds, latitude==$lat && longitude==$lon)
for (varname, var) in single_lat_lon
if varname in ["latitude", "longitude", "time"]
continue
end
push!(var_names, varname)
push!(data, Array[single_lat_lon[varname]][1][:])
end
return reduce(hcat, data)'
end
end
This is the error & stack trace I get when calling it:
MethodError: no method matching (::NCDatasets.var"#154#155")(::Float64)
The applicable method may be too new: running in world age 32645, while current world is 32646.
Closest candidates are:
(::NCDatasets.var"#154#155")(::Any) at none:0 (method too new to be called from this world context.)
Stacktrace:
[1] _broadcast_getindex_evalf
# .\broadcast.jl:670 [inlined]
[2] _broadcast_getindex
# .\broadcast.jl:643 [inlined]
[3] getindex
# .\broadcast.jl:597 [inlined]
[4] copy
# .\broadcast.jl:899 [inlined]
[5] materialize
# .\broadcast.jl:860 [inlined]
[6] findall(testf::NCDatasets.var"#154#155", A::Vector{Float64})
# Base .\array.jl:2311
[7] macro expansion
# C:\Users\scott\.julia\packages\NCDatasets\sLdiM\src\select.jl:242 [inlined]
[8] data_for_lat_lon(ds::NCDatasets.MFDataset{DeferDataset, 1, String, NCDatasets.DeferAttributes, NCDatasets.DeferDimensions, NCDatasets.DeferGroups}, region::DataFrameRow{DataFrame, DataFrames.Index}, lat_lon_pair::Tuple{Float64, Float64})
# Main .\In[46]:8
[9] top-level scope
# .\In[50]:3
[10] eval
# .\boot.jl:368 [inlined]
[11] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String)
# Base .\loading.jl:1428
I'm fairly confident this has something to do with the concept of "hygiene" and variable expansion with a macro but I'm new enough to julia to not understand what needs to be done in my calling function to resolve this. I have reveiwed this question but am not sure it applies to this case: How to pass variable value to a macro in julia?
Thanks!
Turns out the issue was unrelated and was a known issue in julia: https://discourse.julialang.org/t/how-to-bypass-the-world-age-problem/7012
I want to use the hasmethod function to find if an object t::T supports t[!, something] syntax.
The key is something can be of many types and I don't want to check them all, I just want a way to express that hasmethod(getindex, Tuple{T, typeof{!}, S}) regardless of what S is.
How do I do that?
I think the way to get the list of methods is:
methods(getindex, Tuple{Any, typeof(!), Any})
The only problem is that if the second argument allowed by getindex is a supertype of typeof(!) it will be also listed. I do not think it can be avoided though, as you cannot rule out that such getindex definition actually allows ! to be passed as a first argument.
For instance if no packages are loaded the following is the result of the call above:
julia> methods(getindex, Tuple{Any, typeof(!), Any})
# 10 methods for generic function "getindex":
[1] getindex(md::Markdown.MD, args...) in Markdown at C:\cygwin\home\Administrator\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.2\Markdown\src\parse\parse.jl:24
[2] getindex(r::Distributed.Future, args...) in Distributed at C:\cygwin\home\Administrator\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.2\Distributed\src\remotecall.jl:624
[3] getindex(::Type{Any}, vals...) in Base at array.jl:357
[4] getindex(::Type{T}, x, y) where T in Base at array.jl:353
[5] getindex(::Type{T}, vals...) where T in Base at array.jl:344
[6] getindex(A::SparseArrays.SparseMatrixCSC, i, ::Colon) in SparseArrays at C:\cygwin\home\Administrator\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.2\SparseArrays\src\sparsematrix.jl:1879
[7] getindex(A::AbstractArray, I...) in Base at abstractarray.jl:979
[8] getindex(t::AbstractDict, k1, k2, ks...) in Base at abstractdict.jl:476
[9] getindex(itr::Base.SkipMissing, I...) in Base at missing.jl:232
[10] getindex(r::Distributed.RemoteChannel, args...) in Distributed at C:\cygwin\home\Administrator\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.2\Distributed\src\remotecall.jl:626
All of the cases are the ones where getindex does not put restrictions on the second argument so you cannot rule out that they could possibly allow ! as a valid value.
But if e.g. you load DataFrames.jl and restrict the first argument to AbstractDataFrame you get:
julia> methods(getindex, Tuple{AbstractDataFrame, typeof(!), Any})
# 5 methods for generic function "getindex":
[1] getindex(df::DataFrame, ::typeof(!), col_ind::Symbol) in DataFrames at D:\AppData\.julia\packages\DataFrames\yH0f6\src\dataframe\dataframe.jl:367
[2] getindex(df::DataFrame, ::typeof(!), col_ind::Union{Signed, Unsigned}) in DataFrames at D:\AppData\.julia\packages\DataFrames\yH0f6\src\dataframe\dataframe.jl:358
[3] getindex(df::DataFrame, row_ind::typeof(!), col_inds::Union{Colon, Regex, AbstractArray{T,1} where T, All, Between, InvertedIndex}) in DataFrames at D:\AppData\.julia\packages\DataFrames\yH0f6\src\dataframe\dataframe.jl:405
[4] getindex(sdf::SubDataFrame, ::typeof(!), colind::Union{Signed, Symbol, Unsigned}) in DataFrames at D:\AppData\.julia\packages\DataFrames\yH0f6\src\subdataframe\subdataframe.jl:127
[5] getindex(df::SubDataFrame, row_ind::typeof(!), col_inds::Union{Colon, Regex, AbstractArray{T,1} where T, All, Between, InvertedIndex}) in DataFrames at D:\AppData\.julia\packages\DataFrames\yH0f6\src\subdataframe\subdataframe.jl:137
which is now more informative, because in DataFrames.jl we try to be careful not to leave indexing arguments free (i.e. allow them to be Any and only internally check what is valid).
Additionally you can use methodswith to check which methods accept ! explicitly and filter only getindex instances. Here is the result after loading DataFrames.jl:
julia> filter(x -> x.name == :getindex, methodswith(typeof(!)))
[1] getindex(df::DataFrame, ::typeof(!), col_ind::Symbol) in DataFrames at D:\AppData\.julia\packages\DataFrames\yH0f6\src\dataframe\dataframe.jl:367
[2] getindex(df::DataFrame, ::typeof(!), col_ind::Union{Signed, Unsigned}) in DataFrames at D:\AppData\.julia\packages\DataFrames\yH0f6\src\dataframe\dataframe.jl:358
[3] getindex(df::DataFrame, row_ind::typeof(!), col_inds::Union{Colon, Regex, AbstractArray{T,1} where T, All, Between, InvertedIndex}) in DataFrames at D:\AppData\.julia\packages\DataFrames\yH0f6\src\dataframe\dataframe.jl:405
[4] getindex(sdf::SubDataFrame, ::typeof(!), colind::Union{Signed, Symbol, Unsigned}) in DataFrames at D:\AppData\.julia\packages\DataFrames\yH0f6\src\subdataframe\subdataframe.jl:127
[5] getindex(df::SubDataFrame, row_ind::typeof(!), col_inds::Union{Colon, Regex, AbstractArray{T,1} where T, All, Between, InvertedIndex}) in DataFrames at D:\AppData\.julia\packages\DataFrames\yH0f6\src\subdataframe\subdataframe.jl:137
Finally note that x[!, y] syntax can also mean a view (if preceded by e.g. #view) or a setindex! operation (if it appears on LHS of assignment) so you might wan to check also these functions if they accept ! (and in DataFrames.jl they actually do).
You can do that in theory, if you get the syntax right:
julia> hasmethod(getindex, Tuple{Vector{Int}, typeof(!), Any})
true
This should work since Tuples are covariant.
But its returning true is obviously nonsense:
julia> getindex([1], !, 1)
ERROR: ArgumentError: invalid index: ! of type typeof(!)
Stacktrace:
[1] to_index(::Function) at ./indices.jl:270
[2] to_index(::Array{Int64,1}, ::Function) at ./indices.jl:247
[3] to_indices(::Array{Int64,1}, ::Tuple{Base.OneTo{Int64}}, ::Tuple{typeof(!),Int64}) at ./indices.jl:298
[4] to_indices at ./indices.jl:294 [inlined]
[5] getindex(::Array{Int64,1}, ::Function, ::Int64) at ./abstractarray.jl:981
[6] top-level scope at REPL[26]:1
The reason is that it delegates to other methods internally.
I think it's better to constrain T to some abstract type(s) for which this kind of indexing is known to work. Or, as a last resort, use try.
Is there any way to programmatically distinguish between package environments and non-package environment objects? For example, the objects x and y below are both environments, with the same class and attributes.
x <- as.environment(cars)
y <- getNamespace("graphics")
However judging from the print method there is a difference:
> print(x)
<environment: 0x1d38118>
> print(y)
<environment: namespace:graphics>
Now suppose I have an arbitrary object, how can I determine which of the two it is (without looking at the output of print)? I would like to know this to determine how to store the object on disk. In case of the former I need to store the list representation of the environment (and perhaps its parents), but for the latter I would just store the name and version of the package.
isNamespace ?
isNamespace(y)
# [1] TRUE
isNamespace(x)
# [1] FALSE
And, for future reference, apropos is often helpful when you've got a question like this.
apropos("namespace")
# [1] "..getNamespace" ".BaseNamespaceEnv" ".getNamespace"
# [4] ".methodsNamespace" "asNamespace" "assignInMyNamespace"
# [7] "assignInNamespace" "attachNamespace" "fixInNamespace"
# [10] "getFromNamespace" "getNamespace" "getNamespaceExports"
# [13] "getNamespaceImports" "getNamespaceInfo" "getNamespaceName"
# [16] "getNamespaceUsers" "getNamespaceVersion" "isBaseNamespace"
# [19] "isNamespace" "loadedNamespaces" "loadingNamespaceInfo"
# [22] "loadNamespace" "namespaceExport" "namespaceImport"
# [25] "namespaceImportClasses" "namespaceImportFrom" "namespaceImportMethods"
# [28] "packageHasNamespace" "parseNamespaceFile" "requireNamespace"
# [31] "setNamespaceInfo" "unloadNamespace"
Is there a way in R to get a list of all methods defined on an S4 class, given the name of that class?
Edit: I know that showMethods can show me all the methods, but I want to manipulate the list programmatically, so that's no good.
Maybe this would be useful:
mtext <- showMethods(class="SpatialPolygons", printTo =FALSE )
fvec <- gsub( "Function(\\:\\s|\\s\\\")(.+)(\\s\\(|\\\")(.+$)",
"\\2", mtext[grep("^Function", mtext)] )
fvec
[1] ".quad" "[" "addAttrToGeom"
[4] "area" "as.data.frame" "click"
[7] "coerce" "coordinates" "coordnames"
[10] "coordnames<-" "coords" "disaggregate"
[13] "extract" "fromJSON" "isDiagonal"
[16] "isTriangular" "isValidJSON" "jsType"
[19] "over" "overlay" "plot"
[22] "polygons" "polygons<-" "rasterize"
[25] "recenter" "spChFIDs" "spsample"
[28] "spTransform" "text" "toJSON"
The original version did not properly extract the quoted non S4 generics in mtext such as:
[60] "Function \"jsType\":"
[61] " <not an S4 generic function>"
Are you looking for showMethods()?
library(sp)
showMethods(class="SpatialPolygons")
Maybe something like
library(sp)
x=capture.output(showMethods(class="SpatialPolygons"))
unlist(lapply(strsplit(x[grep("Function: ",x,)]," "),function(x) x[2]))
Also stumbled upon it, how about
library(sp)
attr(methods(class="SpatialPolygons"), "info")$generic
# Alternatively:
# attr(.S4methods(class="SpatialPolygons"), "info")$generic
This will directly yield a vector of method names.
Hopefully (one of) the last question on map-files.
Why is this not working, and how would I do that right?
load(url('http://gadm.org/data/rda/CUB_adm1.RData'))
CUB <- gadm
CUB <- spChFIDs(CUB, paste("CUB", rownames(CUB), sep = "_"))
Thank you very much!!!
seems to work with row.names()
load(url('http://gadm.org/data/rda/CUB_adm1.RData'))
CUB <- gadm
CUB <- spChFIDs(CUB, paste("CUB", row.names(CUB), sep = "_"))
The answer is apparent once one reads the help for ?row.names() and ?rownames().
The rownames() function only knows something about matrix-like objects, and CUB is not one of those, hence it doesn't have row names that rownames() can find:
> rownames(CUB)
NULL
row.names() is different, it is an S3 generic function and that means package authors can write methods for specific types of objects such that the row names of those objects can be extracted.
Here is a list of the methods available for row.names() in my current session, with the sp package loaded:
> methods(row.names)
[1] row.names.data.frame
[2] row.names.default
[3] row.names.SpatialGrid*
[4] row.names.SpatialGridDataFrame*
[5] row.names.SpatialLines*
[6] row.names.SpatialLinesDataFrame*
[7] row.names.SpatialPixels*
[8] row.names.SpatialPoints*
[9] row.names.SpatialPointsDataFrame*
[10] row.names.SpatialPolygons*
[11] row.names.SpatialPolygonsDataFrame*
Non-visible functions are asterisked
The class of the object CUB is:
> class(CUB)
[1] "SpatialPolygonsDataFrame"
attr(,"package")
[1] "sp"
So what is happening is that the SpatialPolygonsDataFrame method of the row.names() function is being used and it knows where to find the required row names.