How to make vegalite read my topojson file?

I have a topojson file located in this path: "/home/juliana/roc/Data/Topojson/disa_ONT_region"
I want to make a choropleth map, but I do not know how to call that file into my code.

I know it has to go in “values”
I have tried:

Point a) is related to this: https://github.com/rofinn/FilePaths.jl

a) file=p"/home/juliana/roc/Data/Topojson/disa_ONT_region"

b) file=normpath(string(@DIR, “/Data/Topojson/”, “disa_ONT_region”))

This is my code:

@vlplot(width=800, height=600) +
@vlplot(
    mark={
        :geoshape
},
data={
    values=file,
    format={
        typ=:topojson,
        feature=:disa_ONT_region
    }
},
transform=[{
    lookup=:featureId,
    from={
        data=df_splunk,
        key=:featureId,
        fields=["count"]
    }
}],
color={
    "rate:q",
    scale={scheme=:reds},
    legend={title="IP Rate - BST"}
},
projection={
    typ=:albersUsa
}
)

adapting this example - is helping?

I have already done that. I just want to upload a .topojson file from my computer instead of using a VEGAdataset.

What does isfile(file) give you?

Additionally, when your code isn’t working, please post the error message (not a screenshot, with backticks) to help us understand what is going on.

There are two different ways in which you can load data: 1) you can create a Path object from the FilePaths.jl package that points to your file and put that into your spec, or 2) you can pass the values themselves.

In the case of 1) you are not loading the values yourself, but you let vega/vega-lite load the data from disc, i.e. you just put a pointer to the file into the figure. In theory this is great, but in practice we have a problem that this doesn’t work for various display front-ends (it doesn’t work in VS Code, ElectronDisplay and the default browser viewer, not sure about Jupyter). It does work if you save such a figure to disc with save.

In the case of 2) you need to load the data yourself into memory in Julia, and then pass the data itself to vega/vega-lite. This should always work.

In the case of 1) we don’t have to worry about different file formats, vega is going to figure it out.

In the case of 2) we need to differentiate a bit between tabular and other data. For tabular data anything that complies with the TableTraits.jl interface can be passed, which is pretty much everything, so that is easy. For non-tabular data, for example a topjson, you should ideally use JSON.jl to read the file content and pass it to VegaLite.jl. The code might look like this:

data={
    values=JSON.parsefile(filename),
    format={
        typ=:topojson,
        feature=:disa_ONT_region
    }
}

Let me know if this works!

1 Like

Will a dataframe be in the category of a tabular data?
I have my .shp file also as a dataframe. But I was not able to make a choropleth map. That is why I changed to Vegalite.jl.

By the way this is how my data looks like in a dataframe. It can be seen in 2 ways:

A. The fourth and fifth column do not appear

B.
image

false

Please stop posting screenshots, they make discourse not searchable for future people looking for help.

Your file isn’t in the place where you say it is, or your use of normpath is not correct. This is definitely the problem. It’s not to do with vegalite. You need to make sure isfile returns true (meaning the path leads to an actual file on your computer).

2 Likes

It worked!

I installed the JSON.jl and then I used your code.

I have a question… so if I had a dataframe I will need to “parse” it before sending it to VegaLite, right?

What does this command do?

push!(LOAD_PATH,string(@__DIR__,"/Data/Topojson/"))

It gives mes this output:

 "@"                               
 "@v#.#"                           
 "@stdlib"                         
 "/home/juliana/roc/Data/Topojson/"

LOAD_PATH is for where julia looks for julia packages, not files for import. You shouldn’t be using LOAD_PATH to import files.

Maybe try just working with the global path as a big string instead of messing with @__DIR__ for now.

1 Like

I’m having a similar problem – I can plot data from Vegalite’s datasets, but fail trying to use topojson downloaded from GitHub - topojson/world-atlas: Pre-built TopoJSON from Natural Earth.

I’m using VegaLite, VegaDatasets, have parsed a valid topojson file with

countries50m = JSON.parsefile(DOWNLOADEDFILE)

Here’s my failing code:

function plottopo(w = 900, h = 500)
    @vlplot(width=w, height=h) +
    @vlplot(
        projection={
			type=:naturalEarth1
		},
        mark={
            :geoshape,
            fill=:transparent,
            stroke=:gray
        },
        data={
            values=countries50m,
            format={
                type=:topojson,
                features=:land
            }
        }
    ) 
end

The error message begins

ERROR: THIS SHOULDN'T HAPPEN Dict{String,Any}("objects" => Dict{String,Any}("land" => Dict{String,Any}("geometries" => Any[Dict{String,Any}("arcs" => Any[Any[Any[0]], Any[Any[1]], 
....

and continues with the entire geometry of the world.

Comparing it to the data packaged in VegaliteDatasets, I notice this:

julia> dataset("world-110m").data["objects"]["land"]
OrderedCollections.OrderedDict{String,Any} with 2 entries:
  "type" => "MultiPolygon"
  "arcs" => Any[Any[Any[0]], Any[Any[1]], Any[Any[2]], Any[Any[3]], Any[Any[4]]…

julia> countries50m["objects"]["land"]
Dict{String,Any} with 2 entries:
  "geometries" => Any[Dict{String,Any}("arcs"=>Any[Any[Any[853, 1846, 1480, 184…
  "type"       => "GeometryCollection"

Is it significant that the type of the downloaded topojson is "GeometryCollection" and the Vegalite data is "MultiPolygon"?

Any help appreciated!

It’s not so clear from your code what the final goal is, so I hope that these steps to overcome the error help for your next steps.

I downloaded the file https://cdn.jsdelivr.net/npm/world-atlas@2/countries-50m.json to c:\Temp:

using VegaLite, VegaDatasets, JSON
cd("c:\\Temp")
countries50m = JSON.parsefile("c:\\Temp\\countries-50m.json")
d=VegaDatasets.VegaJSONDataset(countries50m,"c:\\Temp\\countries-50m.json")
@vlplot(
    :geoshape,
    width=500, height=300,
    data={
        values=d,
        format={
            type=:topojson,
            feature=:countries
        }
    },
    projection={
        type=:albersUsa
    },
)

grafik

The goal was exactly what you’ve done – display the map. Thanks so much, this is perfect! (I missed the step of creating a VegaJSONDataset, and was trying to pass in the topojson directly)

(The motivation for a function hard coded with a reference to a data set was simply to hide some of the variables and have an easy function to display the layer in a Pluto notebook.)

1 Like

Provide the JSON data as parameter to the function, like:

function plottopo(data, w = 900, h = 500)
    ...
        data={
            values=data, ...

end

to avoid the need of global variables.
(side not, off topic) :slight_smile:

Motivation was specific to Pluto nb enviornment: I’ve got a couple of maps on the same page. This is just a snippet of the function that overlays dynamically filtered data based on criteria set in PlutoUI widgets. The plotting is actually specific to the data set, so not really generalizable.

But thanks for the concern. :slight_smile: I don’t actually randomly use global variables!

1 Like