The following code fails with a meaningful error message.
x = 10
exp = quote
for i in 1:10
x = x + 1
end
x
end
eval(exp)
┌ Warning: Assignment to `x` in soft scope is ambiguous because a global variable by the same name exists: `x` will be treated as a new local. Disambiguate by using `local x` to suppress this warning or `global x` to assign to the existing global variable.
└ # REPL[177]:3
ERROR: UndefVarError: x not defined
Stacktrace:
[1] top-level scope
# ./REPL[177]:3
[2] eval
# ./boot.jl:360 [inlined]
[3] eval(x::Expr)
# Base.MainInclude ./client.jl:446
[4] top-level scope
Declaring the scope of x as local makes things work:
exp = quote
local x = 0
for i in 1:10
x = x + 1
end
x
end
eval(exp) # 10 as expected
This however does not work for some reason:
x = 0
exp = quote
global x
for i in 1:10
x = x + 1
end
x
end
eval(exp)
ERROR: UndefVarError: x not defined
Stacktrace:
[1] top-level scope
# ./REPL[182]:4
[2] eval
# ./boot.jl:360 [inlined]
[3] eval(x::Expr)
# Base.MainInclude ./client.jl:446
[4] top-level scope
Change the location of global:
julia> x=0;
julia> exp2 = quote
for i in 1:10
global x = x + 1
end
x
end;
julia> eval(exp2)
10
Related
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 am trying to compute contractions of tensors with vector objects, and construct tensor objects from vectors using TensorOperations.jl. For example, I would like to compute the outer product of two simple vectors
using TensorOperations
first_vec = [1 1 1]
second_vec = [2 2 2]
#tensor combination[a, b]:=first_vec[a]*second_vec[b]
Throws the following error:
TensorOperations.IndexError{String}("invalid permutation of length 2: (1,)")
Stacktrace:
\[1\] contract!(α::Bool, A::Matrix{Int64}, CA::Symbol, B::Matrix{Int64}, CB::Symbol, β::Bool, C::Matrix{Int64}, oindA::Tuple{Int64}, cindA::Tuple{}, oindB::Tuple{Int64}, cindB::Tuple{}, indCinoAB::Tuple{Int64, Int64}, syms::Tuple{Symbol, Symbol, Symbol})
# TensorOperations \~/.julia/packages/TensorOperations/LDxfx/src/implementation/stridedarray.jl:247
\[2\] contract!(α::Bool, A::Matrix{Int64}, CA::Symbol, B::Matrix{Int64}, CB::Symbol, β::Bool, C::Matrix{Int64}, oindA::Tuple{Int64}, cindA::Tuple{}, oindB::Tuple{Int64}, cindB::Tuple{}, indleft::Tuple{Int64, Int64}, indright::Tuple{}, syms::Tuple{Symbol, Symbol, Symbol})
# TensorOperations \~/.julia/packages/TensorOperations/LDxfx/src/implementation/stridedarray.jl:89
\[3\] top-level scope
# In\[329\]:4
\[4\] eval
# ./boot.jl:368 \[inlined\]
\[5\] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String)
# Base ./loading.jl:1428\
The problem is that:
first_vec = [1 1 1]
second_vec = [2 2 2]
define matrices and not vectors.
first_vec = [1,1,1]
second_vec = [2,2,2]
#tensor combination[a, b]:=first_vec[a]*second_vec[b]
works fine.
Note the commas replacing spaces in square brackets. Spaces do hcat (horizontal concatenation) and it becomes a row matrix. Vectors in Julia are usually thought of as columns.
I am having trouble plotting in Julia. After uploading an excel file into a data frame and plotting, I the error: 'Cannot Convert Dataframe to series data for plotting'.
For reference the simplest code to trigger error:
using Plots, XLSX, DataFrames
Colbalt = DataFrame(XLSX.readtable("/Users/jjtan/Downloads/statisticsExport.xlsx", "Sheet 1"))
plot(Colbalt, x = :Year, y = :Total)
and the stack trace:
ERROR: Cannot convert DataFrame to series data for plotting
Stacktrace:
[1] error(s::String)
# Base ./error.jl:35
[2] _prepare_series_data(x::DataFrame)
# RecipesPipeline ~/.julia/packages/RecipesPipeline/F2mWY/src/series.jl:8
[3] _series_data_vector(x::DataFrame, plotattributes::Dict{Symbol, Any})
# RecipesPipeline ~/.julia/packages/RecipesPipeline/F2mWY/src/series.jl:27
[4] macro expansion
# ~/.julia/packages/RecipesPipeline/F2mWY/src/series.jl:127 [inlined]
[5] apply_recipe(plotattributes::AbstractDict{Symbol, Any}, #unused#::Type{RecipesPipeline.SliceIt}, x::Any, y::Any, z::Any)
# RecipesPipeline ~/.julia/packages/RecipesBase/apcHH/src/RecipesBase.jl:290
[6] _process_userrecipes!(plt::Any, plotattributes::Any, args::Any)
# RecipesPipeline ~/.julia/packages/RecipesPipeline/F2mWY/src/user_recipe.jl:36
[7] recipe_pipeline!(plt::Any, plotattributes::Any, args::Any)
# RecipesPipeline ~/.julia/packages/RecipesPipeline/F2mWY/src/RecipesPipeline.jl:70
[8] _plot!(plt::Plots.Plot, plotattributes::Any, args::Any)
# Plots ~/.julia/packages/Plots/W75kY/src/plot.jl:232
[9] #plot#149
# ~/.julia/packages/Plots/W75kY/src/plot.jl:107 [inlined]
[10] top-level scope
# ~/Documents/Research/Grants/CDFA-ANALYSIS/##Packgaes.jl:9
Where did you find that syntax? As the error says, you cannot directly plot a DataFrame object. Instead, pass the columns you want to plot as vectors:
plot(Colbalt.Year, Colbalt.Total)
The StatsPlots extention of Plots offers some convenience macros for plotting DataFrames, here are some examples from the Readme:
using DataFrames
df = DataFrame(a = 1:10, b = 10 .* rand(10), c = 10 .* rand(10))
#df df plot(:a, [:b :c], colour = [:red :blue])
#df df scatter(:a, :b, markersize = 4 .* log.(:c .+ 0.1))
In Julia, one can draw a boxplot using StatsPlots.jl. Assuming There is a DataFrame named df, we can draw a boxplot for one of its columns named a by this:
julia> #df df boxplot(["a"], :a, fillalpha=0.75, linewidth=2)
I want to put the same structure in a function:
julia> function BoxPlotColumn(col::Union{Symbol, String}, df::DataFrame)
if isa(col, String)
#df df boxplot([col], Symbol(col), fillalpha=0.75, linewidth=2)
else
#df df boxplot([String(col)], col, fillalpha=0.75, linewidth=2)
end
end
BoxPlotColumn (generic function with 1 method)
Then, if I say BoxPlotColumn("a", df), Julia throws an error:
ERROR: Cannot convert Symbol to series data for plotting
Stacktrace:
[1] error(s::String)
# Base .\error.jl:35
[2] _prepare_series_data(x::Symbol)
# RecipesPipeline C:\Users\Shayan\.julia\packages\RecipesPipeline\OXGmH\src\series.jl:8
[3] _series_data_vector(x::Symbol, plotattributes::Dict{Symbol, Any})
# RecipesPipeline C:\Users\Shayan\.julia\packages\RecipesPipeline\OXGmH\src\series.jl:35
[4] macro expansion
# C:\Users\Shayan\.julia\packages\RecipesPipeline\OXGmH\src\series.jl:135 [inlined]
[5] apply_recipe(plotattributes::AbstractDict{Symbol, Any}, #unused#::Type{RecipesPipeline.SliceIt}, x::Any, y::Any, z::Any)
# RecipesPipeline C:\Users\Shayan\.julia\packages\RecipesBase\qpxEX\src\RecipesBase.jl:289
[6] _process_userrecipes!(plt::Any, plotattributes::Any, args::Any)
# RecipesPipeline C:\Users\Shayan\.julia\packages\RecipesPipeline\OXGmH\src\user_recipe.jl:36
[7] recipe_pipeline!(plt::Any, plotattributes::Any, args::Any)
# RecipesPipeline C:\Users\Shayan\.julia\packages\RecipesPipeline\OXGmH\src\RecipesPipeline.jl:70
[8] _plot!(plt::Plots.Plot, plotattributes::Any, args::Any)
# Plots C:\Users\Shayan\.julia\packages\Plots\lW9ll\src\plot.jl:209
[9] #plot#145
# C:\Users\Shayan\.julia\packages\Plots\lW9ll\src\plot.jl:91 [inlined]
[10] boxplot(::Any, ::Vararg{Any}; kw::Base.Pairs{Symbol, V, Tuple{Vararg{Symbol, N}}, NamedTuple{names, T}} where {V, N, names, T<:Tuple{Vararg{Any, N}}})
# Plots C:\Users\Shayan\.julia\packages\RecipesBase\qpxEX\src\RecipesBase.jl:410
[11] add_label(::Vector{String}, ::typeof(boxplot), ::Vector{String}, ::Vararg{Any}; kwargs::Base.Pairs{Symbol, Real, Tuple{Symbol, Symbol}, NamedTuple{(:fillalpha, :linewidth), Tuple{Float64, Int64}}}) # StatsPlots C:\Users\Shayan\.julia\packages\StatsPlots\faFN5\src\df.jl:153
[12] (::var"#33#34"{String})(349::DataFrame)
# Main .\none:0
[13] BoxPlotColumn(col::String, df::DataFrame)
# Main c:\Users\Shayan\Documents\Python Scripts\test2.jl:15
[14] top-level scope
# c:\Users\Shayan\Documents\Python Scripts\test2.jl:22
Which is because of this : #df df boxplot([col], Symbol(col), fillalpha=0.75, linewidth=2)
How can I fix this? Why does this happen? I wrote the same thing just in a function.
I wrote the same thing just in a function.
You have not written the same thing. In your original code you use string and Symbol literals, and in function you pass a variable. This is the key difference.
To fix this I recommend you to use #with from DataFramesMeta.jl:
BoxPlotColumn(col::Union{Symbol, String}, df::DataFrame) =
#with df boxplot([string(col)], $col, fillalpha=0.75, linewidth=2)
which does what you want, as #with supports working with column names programmatically with $.
EDIT
Why Julia doesn't operate when we say boxplot(..., col, ...)
It does not operate because both #df and #which are macros. Since they are macros they transform code into other code that is only later executed. These macros are designed in a way that when they see a symbol literal, e.g. :a they treat it in a special way and consider it to be a column of a data frame. When they see a variable col they cannot know that this variable points to a symbol as the macro is executed before code is evaluated (remember - macro is a method to transform code into other code before this code is executed). See https://docs.julialang.org/en/v1/manual/metaprogramming/#man-macros
MethodError: no method matching isfinite(::String15)
Most likely you have a column with strings not numbers, instead write e.g. names(df, Real) to only get a list of columns that store real numbers (without missing). If you want to allow missing then write names(df, Union{Missing,Real}).
Code - Quasi Newton Problem
This is the code for Quasi Newton Problem. For this, I am getting an error
MethodError: no method matching isless(::Matrix{Float64}, ::Matrix{Float64})
Closest candidates are:
isless(::Any, ::Missing) at missing.jl:88
isless(::Missing, ::Any) at missing.jl:87
Stacktrace:
[1] <(x::Matrix{Float64}, y::Matrix{Float64})
# Base .\operators.jl:279
[2] >(x::Matrix{Float64}, y::Matrix{Float64})
# Base .\operators.jl:305
[3] bracket_minimum(f::var"#45#46"{typeof(k), Matrix{Float64}, Matrix{Float64}}, x::Int64; s::Float64, k::Float64)
# Main .\In[122]:12
[4] bracket_minimum(f::Function, x::Int64) (repeats 2 times)
# Main .\In[122]:10
[5] line_search(f::typeof(k), x::Matrix{Float64}, d::Matrix{Float64})
# Main .\In[122]:35
[6] step!(M::BFGS, f::Function, ∇f::typeof(l), x::Matrix{Float64})
# Main .\In[122]:48
[7] quasi_method(f::typeof(k), g::Function, x0::Matrix{Float64})
# Main .\In[122]:67
[8] top-level scope
# In[128]:3
[9] eval
# .\boot.jl:360 [inlined]
[10] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String)
# Base .\loading.jl:1116
I still couldn't figure what's the issue with line 10 and 12. So help me out here? Maybe it's due to Matrix we are using or some other issues, I couldn't debug.
You forgot to vectorize your code.
See the example below for reference:
julia> a=[1. 2.; 3. 4.]; b=[1. 3.; 5. 7.];
julia> a < b
ERROR: MethodError: no method matching isless(::Matrix{Float64}, ::Matrix{Float64})
Now let us add dot to vectorize:
julia> a .< b
2×2 BitMatrix:
0 1
1 1
If you want to check if all elements are lower use all:
julia> all(a .< b)
false
In your code bracket_minimum does the comparison yc > yb and those values are matrices while your code expects scalars.