# Use mapbox to place images with PlotlyJS

**URL:** <https://discourse.julialang.org/t/use-mapbox-to-place-images-with-plotlyjs/86758>\
**Category:** Visualization\
**Tags:** plotlyjs\
**Created:** [September 4, 2022, 2:12pm UTC](https://discourse.julialang.org/t/use-mapbox-to-place-images-with-plotlyjs/86758 "2022-09-04T14:12:37Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![lgo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lgo/32/48751_2.png) [@lgo](https://discourse.julialang.org/u/lgo)\
**Post date:** [September 4, 2022, 2:12pm UTC](https://discourse.julialang.org/t/use-mapbox-to-place-images-with-plotlyjs/86758/1 "2022-09-04T14:12:37Z")

</div>

I want to create a map with PlotlyJS that includes lines and grouped/stacked bar charts. I’ve [asked on stackoverflow](https://stackoverflow.com/questions/73449918/plot-bar-charts-on-a-map-in-plotly) how to achieve this in general and got a solution that deploys mapboxes. Now I’m trying to convert this into Julia and can’t get the image to appear:

```julia
using PlotlyJS, DataFrames, CSV
# create trace for lines (not immediately releveant for mapbox problem)
nm = tempname()
url = "https://raw.githubusercontent.com/plotly/datasets/c34aaa0b1b3cddad335173cb7bc0181897201ee6/2011_february_aa_flight_paths.csv"
download(url, nm)
cord = CSV.read(nm,DataFrame)

M = maximum(cord[:,:cnt])

trace_data = [scattergeo(;locationmode="USA-states",
    lon = [cord[1,:start_lon], cord[1,:end_lon]],
    lat = [cord[1,:start_lat], cord[1,:end_lat]],
    mode = "lines",
    line_width = 2,
    line_color = "red",
    opacity = cord[1,:cnt]/M
)];

# create mapbox data
images_1 = [attr(sourcetype = "raster", source = rand(4, 4), coordinates = [cord[1,:start_lat],cord[1,:start_lon]])]

# create layout and plot
layout = Layout(;showlegend=false, mapbox_style="carto-positron", mapbox_zoom=3, mapbox_layers = images_1)
plot(trace_data, layout)

```

For testing, I’ve also tried to use a geojson as as an input but did not get a result either. Below is the corresponding code and the content of `testGeoJSON.GEOJSON`.

```julia
images_2 = [attr(sourcetype = "geojson", source = "testGeoJSON.GEOJSON")]

```

```julia
{
  "type": "Feature",
  "geometry": {
    "type": "Point",
    "coordinates": [125.6, 10.1]
  },
  "properties": {
    "name": "Dinagat Islands"
  }
}

```

Many thanks!

PS: I’m also greatful for any help on the next step, which is how to convert a PlotlyJS plot into an input for mapboxes. I figure that `source = plot(data,layout)` is probably not the right way to go.

---

<div class="post-metadata">

**Author:** ![empet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/empet/32/221303_2.png) [@empet](https://discourse.julialang.org/u/empet)\
**Post date:** [September 5, 2022, 7:52pm UTC](https://discourse.julialang.org/t/use-mapbox-to-place-images-with-plotlyjs/86758/2 "2022-09-05T19:52:42Z")

</div>

The steps to get a choropleth mapbox with stacked bars:

1. For stacked bars you need a long-form data frame. Here I use a minimalistic example:

```julia
nation	medal	count
String15	String7	Int64
1	South Korea	gold	24
2	China	gold	10
3	Japan	gold	9
4	South Korea	silver	13
5	China	silver	15
6	Japan	silver	12
7	South Korea	bronze	11
8	China	bronze	8
9	Japan	bronze	12

```

1. from such a dataframe you can get stacked bars, as follows:

```julia
using PlotlyJS, CSV, DataFrames, Base64
df=CSV.read("long-medals.csv", DataFrame)
fig = Plot(df, kind="bar", x=:nation, y=:count, color=:medal, 
              Layout(barmode="stack", showlegend=false,
                     xaxis_visible=false, yaxis_visible=false,
                     bargap=0,
                     margin= attr(l= 0, r= 0, t= 0, b= 0),
                     height=100, width=100,
                     paper_bgcolor="rgba(0,0,0,0)",
                     plot_bgcolor="rgba(0,0,0,0)"
    )
)
savefig(fig, "stacked.png")

```

1. Encode the png file as a String, via `base64encode`, to be passed as source for `mapbox_layer`:

```julia
vecuint8 = read("stacked.png") 
bs64 = base64encode(vecuint8)
imgsource= "data:image/png;base64,"*bs64    

```

1. Get data for the dataframe to be used in the choroplethmapbox definition:

```julia
using JSON, HTTP
url= "https://gist.githubusercontent.com/hrbrmstr/94bdd47705d05a50f9cf/raw/0ccc6b926e1aa64448e239ac024f04e518d63954/asia.geojson"
result = HTTP.request("GET", url)
jsondata = JSON.parse(String(result.body))

countries = ["China", "Korea", "Japan"]  
isoc= String[]
for co in countries
    for feat in jsondata["features"]
        if co == feat["properties"]["name"]
             push!(isoc, feat["properties"]["iso_a3"]) 
        end
    end    
end 
print(isoc)
dfchoro = DataFrame(iso_a3=isoc, val= [1, 1, 1])     

```

1. Define the choroplethmapbox:

```julia
url = "https://gist.githubusercontent.com/hrbrmstr/94bdd47705d05a50f9cf/raw/0ccc6b926e1aa64448e239ac024f04e518d63954/a
sia.geojson"
q = Plot(choroplethmapbox(geojson = url,
                          featureidkey = "properties.iso_a3",
                          locations = dfchoro.iso_a3,
                          z=dfchoro.val,
                          colorscale=[[0, "#d3d3d3"], [1, "#d3d3d3"]], showscale=false,
                          marker=attr(opacity=0.85, line=attr(width=0.5, color="black"))),
          Layout(mapbox =attr(center=attr(lon =100.61, lat=40.04),
                                          zoom=1.5, style="open-street-map"),
                 mapbox_layers=[
                               attr(sourcetype= "image",           
                                    source=imgsource,
                                    coordinates= [[104, 38], [110, 38], [110, 29], [104, 29]])]))  

```

![stacked-bars-map](https://global.discourse-cdn.com/julialang/original/3X/2/c/2ca7b8a24f26dd93c123eca0b0e632257927d784.png)  
Following these steps and using your data you can get the map decorated with stacked bars, and similarly with any other images.

---

<div class="post-metadata">

**Author:** ![lgo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lgo/32/48751_2.png) [@lgo](https://discourse.julialang.org/u/lgo)\
**Post date:** [September 6, 2022, 10:25am UTC](https://discourse.julialang.org/t/use-mapbox-to-place-images-with-plotlyjs/86758/3 "2022-09-06T10:25:28Z")

</div>

Many thanks! I will mark the solution as soon as I had the time to test.

---

<div class="post-metadata">

**Author:** ![lgo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lgo/32/48751_2.png) [@lgo](https://discourse.julialang.org/u/lgo)\
**Post date:** [September 27, 2022, 8:39pm UTC](https://discourse.julialang.org/t/use-mapbox-to-place-images-with-plotlyjs/86758/4 "2022-09-27T20:39:58Z")

</div>

How can I get this to work, if the GeoJSON is a local file instead of an url? I tried to exchange the url with a local directory that I placed the same file in but had no success.

---

<div class="post-metadata">

**Author:** ![jd-foster](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jd-foster/32/35824_2.png) [@jd-foster](https://discourse.julialang.org/u/jd-foster)\
**Post date:** [September 28, 2022, 2:31am UTC](https://discourse.julialang.org/t/use-mapbox-to-place-images-with-plotlyjs/86758/5 "2022-09-28T02:31:05Z")

</div>

Say you’ve downloaded the file instead as

```julia
## Alternative to 4:
using JSON, Downloads
url= "https://gist.githubusercontent.com/hrbrmstr/94bdd47705d05a50f9cf/raw/0ccc6b926e1aa64448e239ac024f04e518d63954/asia.geojson"
filename = "asia.geojson"
Downloads.download(url, filename)
jsondata = JSON.parsefile(filename)

```

then instead of  
`q = Plot(choroplethmapbox(geojson = url,` …  
do  
`q = Plot(choroplethmapbox(geojson = attr(type=jsondata["type"], features=jsondata["features"]),` …

---

<div class="post-metadata">

**Author:** ![empet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/empet/32/221303_2.png) [@empet](https://discourse.julialang.org/u/empet)\
**Post date:** [September 28, 2022, 5:52am UTC](https://discourse.julialang.org/t/use-mapbox-to-place-images-with-plotlyjs/86758/6 "2022-09-28T05:52:08Z")

</div>

@lgo  
A local geojson file can be read as a JSON file: [LightOSM : reading GeoJSON files](https://discourse.julialang.org/t/lightosm-reading-geojson-files/87131)

---

<div class="post-metadata">

**Author:** ![lgo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lgo/32/48751_2.png) [@lgo](https://discourse.julialang.org/u/lgo)\
**Post date:** [October 30, 2022, 8:23pm UTC](https://discourse.julialang.org/t/use-mapbox-to-place-images-with-plotlyjs/86758/7 "2022-10-30T20:23:59Z")

</div>

Thanks to your help I was able to achieve what I had in mind but I have a new problem and thought it might be more appropriate to ask here instead of starting a new thread because this closely relates to the original problem.

I mainly design the map to put it on slides or in a paper but the aspect ratio of the mapbox map is not really suited for that. So ideally I would like to use a different projection but the [mapbox layout](https://plotly.com/python/reference/layout/mapbox/) does not a have a corresponding option. On the other hand, I cannot switch to a geo map, because I can’t find a way to place my graph than. The [geo layout](https://plotly.com/python/reference/layout/geo/) does not have such an option.

So far, my best idea is some workaround that just builds on layering graphics and implies loosing some of the plotly map features, like hoovering for example.
