BoundsError: attempt to access 55-element Vector{Float64} at index [3-element BitVector] OR UndefVarError: `vertex_counter` not defined

Hello,

I’ve created bank and depositor agents and would now like to render as a graph with banks as the nodes and the depositors forming the edges that change at every time step. A snippet of the data frame is inserted below. For example, at time 0 depositor #1 withdraws from bank #405.

I want the network to look something like this.

The problem is the bank “FOR loop.” If the “vertex_counter” is inside the FOR loop, there’s a “BoundsError.” If the “vertex_counter” is outside the FOR loop, there’s an “UnderVarError.” I’d appreciate your insights. Thank you.

‘’’

df = CSV.read(“//Users/teresafranks/Documents/Dissertation/Charts/testDepositorBankData.csv”, DataFrame)

Create a directed graph

g = SimpleDiGraph()

Add vertices for banks and group them by social_network

banks = unique(df.bank_id)
social_network_groups = Dict{Int, Vector{Int}}()

Create a mapping from bank IDs to graph vertices

vertex_map = Dict{Int, Int}()
vertex_counter = 1 # ??? vertex_counter before loop or after loop? Neither works.

for bank in banks
#vertex_counter = 1
vertex_map[bank] = vertex_counter
add_vertex!(g)
social_network = df[df.bank_id .== bank, :social_network][1]
if haskey(social_network_groups, social_network)
push!(social_network_groups[social_network], vertex_counter)
else
social_network_groups[social_network] = [vertex_counter]
end
vertex_counter += 1
end

Function to update the network at each time step

function update_network!(g, df, t)
# Clear existing edges
for e in edges(g)
rem_edge!(g, edges(g))
end

# Add edges from depositors to banks based on the current time step
for row in eachrow(df)
    if row.time <= t
        depositor_id = row.depositor_id
        bank_vertex = vertex_map[row.bank_id]
        add_edge!(g, depositor_id, bank_vertex)
    end
end

end

Function to plot the network

function plot_network(g, social_network_groups, group_colors, t)
# Assign colors to vertices based on their social_network group
vertex_colors = fill(“black”, nv(g))
for (group, vertices) in social_network_groups
for vertex in vertices
vertex_colors[vertex] = group_colors[group]
end
end

# Plot the graph with vertex colors using Plots.jl and GraphRecipes.jl
graphplot(g, names=1:nv(g), nodecolor=vertex_colors, method=:spring, title="Time Step: $t")

end

Define colors for different social_network groups

group_colors = Dict{Int, String}()
color_palette = distinguishable_colors(length(keys(social_network_groups)))

#i = 1
for group in keys(social_network_groups)
i = 1
group_colors[group] = hex(color_palette[I])
i += 1
end

Simulate the network evolution

max_time = maximum(df.time)
for t in 1:max_time
update_network!(g, df, t)
plot_network(g, social_network_groups, group_colors, t)
sleep(1) # Pause for a second to visualize the evolution
end
‘’’

Hi,

Formatting

Could you edit your post to improve the readability? You seem to currently have written the code using > (e.g.

This is a comment

str = “Hello world”
println(str)

), while to get proper formatting you should use triple backticks (```, not apostrophes (‘’') or quotes (“”)) and no > (e.g.

# This is a comment
str = "Hello world"
println(str)

).

Error message / stacktrace

Could you post the full error message and stacktrace? This would help pinpoint the location of the problem. Also, in the case of vertex_counter outside of the for loop, if would help to know which variable is undefined :slight_smile: .

Data

It would also help if you could share the data for the DataFrame (if legally possible), or even better, generate (fake) data, for a minimal working example. That way others can also debug the code.

For the same reason please also mention the dependencies you are using (presumably using CSV, DataFrames, Graphs, Plots, GraphRecipes).

Some notes

  • If you define vertex_counter inside the loop as

    for bank in banks
        vertex_counter = 1
        # Do stuff with vertex_counter
        vertex_counter += 1
    end
    

    then vertex_counter will always have a value of 1, as you reset it at the start of each iteration.

  • In fact, you do not need a variable vertex_counter at all, as this information is already contained in g and can be extracted using nv(g). Alternatively, since you just increment vertex_counter by 1 at the end of every iteration, you could use for (vertex_counter, bank) in enumerate(banks).

  • (The line

    social_network = df[df.bank_id .== bank, :social_network][1]
    

    looks for all rows in the DataFrame df whose bank_id equals bank, extracts the social_network value for those rows, and then takes the first value, i.e. throws away all other found rows. Instead you could use something like df[findfirst(df.bank_id .== bank), :social_network] to directly obtain only the first relevant row. It’s probably also a bit more efficient (though not optimal in this regard as we still materialise the BitVector - you could use a generator), though that’s probably not very important at this point.)

  • In

    for e in edges(g)
        rem_edge!(g, edges(g))
    end
    

    you probably want rem_edge!(g, e). I would expect the current code to throw an error (but am not familiar with Graphs.jl).

1 Like

Dear Eldee,

Thank you. I’ll go through your feedback with care.

I see the backtick now; it’s with the Tilda character.

Here’s the error message with the counter outside the bank FOR loop:

┌ Warning: Assignment to vertex_counter in soft scope is ambiguous because a global variable by the same name exists: vertex_counter will be treated as a new local. Disambiguate by using local vertex_counter to suppress this warning or global vertex_counter to assign to the existing global variable.
└ @ ~/Documents/dissertation/Julia/Network.jl:39
ERROR: UndefVarError: vertex_counter not defined
Stacktrace:
[1] top-level scope
@ ~/Documents/dissertation/Julia/Network.jl:31

Since I restarted my laptop, I’m now getting a different error message with the counter inside the bank FOR loop:

Warning: Assignment to vertex_counter in soft scope is ambiguous because a global variable by the same name exists: vertex_counter will be treated as a new local. Disambiguate by using local vertex_counter to suppress this warning or global vertex_counter to assign to the existing global variable.
└ @ ~/Documents/dissertation/Julia/Network.jl:30
ERROR: Unknown color: 000000
Stacktrace:
[1] error(::String, ::String)
@ Base ./error.jl:44
[2] _parse_colorant(desc::String)
@ Colors ~/.julia/packages/Colors/E2qak/src/parse.jl:151
[3] parse(::Type{RGBA{Float64}}, desc::String)
@ Colors ~/.julia/packages/Colors/E2qak/src/parse.jl:207
[4] plot_color
@ ~/.julia/packages/PlotUtils/wo8RM/src/colors.jl:5 [inlined]
[5] |>
@ ./operators.jl:917 [inlined]
[6] get_series_color(c::String, sp::Plots.Subplot{Plots.GRBackend}, n::Int64, seriestype::Symbol)
@ Plots ~/.julia/packages/Plots/kLeqV/src/args.jl:1982
[7] _update_series_attributes!(plotattributes::RecipesPipeline.DefaultsDict, plt::Plots.Plot{…}, sp::Plots.Subplot{…})
@ Plots ~/.julia/packages/Plots/kLeqV/src/args.jl:2078
[8] add_series!(plt::Plots.Plot{Plots.GRBackend}, plotattributes::RecipesPipeline.DefaultsDict)
@ Plots ~/.julia/packages/Plots/kLeqV/src/pipeline.jl:377
[9] _process_seriesrecipe(plt::Any, plotattributes::Any)
@ RecipesPipeline ~/.julia/packages/RecipesPipeline/BGM3l/src/series_recipe.jl:46
[10] _process_seriesrecipes!(plt::Any, kw_list::Any)
@ RecipesPipeline ~/.julia/packages/RecipesPipeline/BGM3l/src/series_recipe.jl:27
[11] recipe_pipeline!(plt::Any, plotattributes::Any, args::Any)
@ RecipesPipeline ~/.julia/packages/RecipesPipeline/BGM3l/src/RecipesPipeline.jl:99
[12] _plot!(plt::Plots.Plot, plotattributes::Any, args::Any)
@ Plots ~/.julia/packages/Plots/kLeqV/src/plot.jl:223
[13] plot#188
@ ~/.julia/packages/Plots/kLeqV/src/plot.jl:102 [inlined]
[14] plot
@ ~/.julia/packages/Plots/kLeqV/src/plot.jl:93 [inlined]
[15] graphplot
@ ~/.julia/packages/RecipesBase/BRe07/src/RecipesBase.jl:380 [inlined]
[16] plot_network(g::SimpleDiGraph{…}, social_network_groups::Dict{…}, group_colors::Dict{…}, t::Int64)
@ Main ~/Documents/dissertation/Julia/Network.jl:70
[17] top-level scope
@ ~/Documents/dissertation/Julia/Network.jl:88
Some type information was truncated. Use show(err) to see complete types.

#File to create a network graph from the DepositorBankData.csv file
using Pkg
Pkg.activate(".")
Pkg.instantiate()

using DataFrames
using Graphs
using CSV
using GraphPlot
using Plots
using GraphRecipes
using Colors

# Load the data from the CSV file
df = CSV.read("//Users/teresafranks/Documents/Dissertation/Charts/DepositorBankData.csv", DataFrame)

# Create a directed graph
g = SimpleDiGraph()


# Add vertices for banks and group them by social_network
banks = unique(df.bank_id)
social_network_groups = Dict{Int, Vector{Int}}()

# Create a mapping from bank IDs to graph vertices
vertex_map = Dict{Int, Int}()
#vertex_counter = 1  # ???? vertex_counter before loop or after loop?  Neither works.

for bank in banks
    vertex_counter = 1
    vertex_map[bank] = vertex_counter
    add_vertex!(g)
    social_network = df[df.bank_id .== bank, :social_network][1]
    if haskey(social_network_groups, social_network)
        push!(social_network_groups[social_network], vertex_counter)
    else
        social_network_groups[social_network] = [vertex_counter]
    end
    vertex_counter += 1
end

# Function to update the network at each time step
function update_network!(g, df, t)
    # Clear existing edges
    for e in edges(g)
        rem_edge!(g, edges(g))
    end

    # Add edges from depositors to banks based on the current time step
    for row in eachrow(df)
        if row.time <= t
            depositor_id = row.depositor_id
            bank_vertex = vertex_map[row.bank_id]
            add_edge!(g, depositor_id, bank_vertex)
        end
    end
end

# Function to plot the network
function plot_network(g, social_network_groups, group_colors, t)
    # Assign colors to vertices based on their social_network group
    vertex_colors = fill("black", nv(g))
    for (group, vertices) in social_network_groups
        for vertex in vertices
            vertex_colors[vertex] = group_colors[group]
        end
    end

    # Plot the graph with vertex colors using Plots.jl and GraphRecipes.jl
    graphplot(g, names=1:nv(g), nodecolor=vertex_colors, method=:spring, title="Time Step: $t")
end

# Define colors for different social_network groups
group_colors = Dict{Int, String}()
color_palette = distinguishable_colors(length(keys(social_network_groups)))

#i = 1
for group in keys(social_network_groups)
    i = 1
    group_colors[group] = hex(color_palette[i])
    i += 1
end

# Simulate the network evolution
max_time = maximum(df.time)
for t in 1:max_time
    update_network!(g, df, t)
    plot_network(g, social_network_groups, group_colors, t)
    sleep(1)  # Pause for a second to visualize the evolution
end

Perhaps this message file size is too big, since I can’t upload the data frames. I’ll send in a separate message. Thanks again.

For some reason, I’m not able to upload a CSV. Only allows JPEG? Please advise. Thank you.

Paste it in a GitHub gist or some other pastebin

Thank you, jling!

I see, you’re running your code as a script. In general you should then place (almost) all of the code inside functions (e.g. a main function which you call at the end of your script). This will help for performance, and also get rid of your scope issue when defining vertex_counter (and later i) outside of the for loop.

Example

When run as a script

x = 0
for i = 1:5
    x += 1
end
println(x)

indeed throws an exception

┌ 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.
└ @ (...)\example.jl:3
ERROR: LoadError: UndefVarError: `x` not defined
Stacktrace:
 [1] top-level scope
   @ (...)\example.jl:3
in expression starting at (...)\example.jl:2

while

function main()
	x = 0
	for i = 1:5
		x += 1
	end
	println(x)
end

main()

runs fine:

5

If you then define your variables outside of the loop (which you should, keeping the first note in my previous post in mind), you will still run into the second error. The solution here is to simply not use hex.

Example
using Plots

function main()
    x = rand(10) |> sort
	y = rand(10)
	color_palette = distinguishable_colors(10)
	plot(x, y, color=hex.(color_palette))
end

main()

will throw

ERROR: Unknown color: 000000

but

using Plots

function main()
    x = rand(10) |> sort
	y = rand(10)
	color_palette = distinguishable_colors(10)
	plot(x, y, color=color_palette)
end

main()

successfully displays.

1 Like

Super. That works.

Thank you!

1 Like