Closed IndigoCurnick closed 1 year ago
Hello @NathanielCurnick ,
I think this is a bug or to be more precise an API that isn't yet implemented. I personally haven't used the Mapbox based charts at all. So chances are you are the first user who found out about the API key issue.
I think, the best workaround would be to try to build the HTML code directly yourself. Just use the library to generate HTML/JS code for the <div>
that holds the chart. JSON.create(from: figure)
is all you should need.
Here's how it is currently used:
https://github.com/vojtamolda/Plotly.swift/blob/main/Sources/Plotly/IO/HTML.swift
.
Then have full control of the generated HTML and you can insert the JS calls to set the Mapbox API key wherever it is needed.
BTW, a PR with a fix would be welcome too ;)
Hi @vojtamolda! Thanks for your super quick reply! If nobody has implemented this yet, I might be able to do it. I will be needing a lot of map plotting tools soon, so I will make it a priority to get a few hours of development into making this That being said, I'm new to swift so I might take a little while to figure out how to actually do it 😅
Sure thing! I'll be happy to talk if you get stuck. Just ping me.
Especially the part of the codebase located in the Codegen
directory is very difficult to understand. It parses Plotly JS templates and generates corresponding Codable
Plotly structs.
But to implement what you need here, I don't think you have to touch it.
After a long time I can move forward with this again. I've been diving through the code, and the Layout file does seem to support something Mapboxy here
public var mapbox: [Mapbox] = []
Plus there's an extension to Array here
extension Array where Element == Mapbox {
public static func preset(domain: Domain? = nil, accessToken: String? = nil, style: Anything? =
nil, center: Mapbox.Center? = nil, zoom: Double? = nil, bearing: Double? = nil, pitch: Double? =
nil, layers: [Mapbox.Layer]? = nil, uiRevision: Anything? = nil) -> [Mapbox] {
let axis = Mapbox(uid: 1)
axis.domain = domain
axis.accessToken = accessToken
axis.style = style
axis.center = center
axis.zoom = zoom
axis.bearing = bearing
axis.pitch = pitch
axis.layers = layers
axis.uiRevision = uiRevision
return [axis]
}
So the access token system exists.
After hacking around a bit, I figured out I can do this
let trace = ScatterMapbox(name: "Trace", longitude: [1.0], latitude: [1.0]);
var layout = Layout();
layout.mapbox = [Mapbox(accessToken: "SOME TOKEN")];
let fig = Figure(data: [trace], layout: layout);
try! fig.show();
Which produces the following
Plotly.react('441E18FE-CE47-4769-BD11-111D8ECA9C5E',
{"layout":{"mapbox1":{},"mapbox17407751477860320571":{"accesstoken":"SOME TOKEN"}},"data":[{"subplot":"mapbox1","lat":[1],"transforms":[],"type":"scattermapbox","name":"Trace","lon":[1]}],"config":{},"frames":[]}
)
I made the equivalent Python code like this
import plotly.graph_objects as go
fig = go.Figure()
fig.add_trace(go.Scattermapbox(lat=[1.0], lon=[1.0]))
fig.update_layout(mapbox=dict(accesstoken="SOME TOKEN"))
json = fig.to_plotly_json()
print(json)
Which produces a much much bigger JSON than the Swift version (but most of it is just defining the defaults) but it does have the key
'mapbox': {'accesstoken': 'SOME TOKEN'}
Which is, I think, the only thing that needs to change for the Swift version to work perfectly? I don't know how to do this exactly, but I am willing to help out with PRs :)
Let's try to work towards a minimal code example that should work but doesn't.
It seems to me that all your code is missing a Config
object passed to the Figure
constructor. The Config
object has a mapboxAccessToken
property that needs to be set for the Mapbox access traces to work.
I think something like this is a good minimal code example:
let trace = ScatterMapbox(name: "Trace", longitude: [1.0], latitude: [1.0])
let config = Config(mapboxAccessToken: "ACCESS_TOKEN_HERE")
let fig = Figure(data: [trace], config: config)
try! fig.show()
Does it work for you?
PS: I haven't actually compiled it, so take it with a grain of salt and correct whatever is needed.
Oh, it does work, guess I just didn't understand how to use the Config the whole time -_- Thanks for the help! Sorry to take up too much time
Perfect! No worries, I'm glad all works. Good luck with your project!
Using
ScatterMapbox
,show()
makes a window open in the webbrowser, but it doesn't contain anything, just white. I think that I need to include a Mapbox API key in order to get the map data, but I can't figure out how to do that. Is this supported? I have used the Python and Rust versions of Plotly before, and they both have anupdate_layout()
method which allows for injecting the API key