R ggplotly to Python plotly conversion issues (with beginnings of a possible fix)
Hello Plotly team! I want to make graphs in R’s ggplotly and then run existing Plotly Python code to reformat them. However, I’m getting errors when importing a ggplotly JSON created in R into Plotly in Python.
To fix these errors, I have to resort to either running code to fix them in the JSON (2a below) or setting pio.read_json()’s skip_invalid parameter to true (2b below). , I believe the JSON is valid because 1) The JSON renders correctly in Plotly.js 2) The JSON comes from simple graphs made in ggplotly.
R code:
library(ggplot2)
library(plotly)
# Data
a = data.frame(x = (0:4), y = c(2, 4, 1, 6, 8), group="A")
b = data.frame(x = (0:4), y = c(3, 2, 5, 4, 7), group="B")
data <- rbind(a, b)
# Graph
fig <- ggplot(data, aes(x, y, color = group)) + geom_line()
#Convert to ggplotly, save as JSON, and export
fig_ggplotly <- ggplotly(fig)
fig_ggplotly_json<-plotly_json(fig_ggplotly, FALSE)
write(fig_ggplotly_json,'fig_ggplotly.json')
2a: Python code - Errors when using json.load( )
import json
import sys
with open(“fig_ggplotly.json", "r") as f:
fig_ggplotly_json = json.load(f)
print(fig_ggplotly_json)
go.Figure(fig_ggplotly_json) # throws errors; solved with ggplotly_to_plotly.py
# Example of invalid parameter:
fig_ggplotly_json['layout']['font']['family'] # shows value as ‘’. Does not throw error.
2b: Python code - Using pio.read_json() with skip_invalid=True
import json
import sys
import plotly.io as pio
with open("fig_ggplotly.json", "r") as f:
fig_ggplotly_pio = pio.read_json(f, skip_invalid=True)
# Example of invalid parameter that gets completely eliminated using skip_invalid, causing later issues:
fig_ggplotly_pio.to_dict()['layout']['font']['family'] #throws KeyError
Skipping elements of the JSON seems to be inviting a loss of fidelity. Indeed, the reformatting code I apply has issues handling some elements due to the skipped invalid parameters. I’ve identified a number of specific elements that are not compatible with Plotly.py and would appreciate it if Plotly.py were to handle this valid input correctly. The ggplotly_to_plotly conversion code, which highlights many of the problem areas for basic graphs, can be found here.
font.family="" is indeed invalid - most of the time this is silently ignored by plotly.js, but if you have a figure in a browser and you look at it in the JS console you can see that this has been replaced by the default font, or if you call Plotly.validate on this figure you will see it flagged:
> Plotly.newPlot(gd,[],{title:{text:"abc"},font:{family:""}}) // gd is a <div> element
> gd.layout.font.family
< ''
> gd._fullLayout.font.family // _fullLayout has only validated attributes
< '"Open Sans", verdana, arial, sans-serif'
> Plotly.validate([],{title:{text:"abc"},font:{family:""}})
< LOG: In layout, key font.family is set to an invalid value ()
So ideally ggplotly shouldn't be setting this, but if that were the only issue skip_invalid would give you a usable result. What other attribute values is it complaining about? I see some of the "fixes" in your ggplotly_to_plotly gist but not what the values were before the fix.
Hi - we are tidying up stale issues and PRs in Plotly's public repositories so that we can focus on things that are still important to our community. Since this one has been sitting for a while, I'm going to close it; if it is still a concern, please add a comment letting us know what recent version of our software you've checked it with so that I can reopen it and add it to our backlog. If you'd like to submit a PR, we'd be happy to prioritize a review, and if it's a request for tech support, please post in our community forum. Thank you - @gvwilson