Repository: streamlit/streamlit

Issue:
pydeck_chart: Error (not a valid JSON) when data contains NaN
### Checklist

- [X] I have searched the [existing issues](https://github.com/streamlit/streamlit/issues) for similar issues.
- [X] I added a very descriptive title to this issue.
- [X] I have provided sufficient information below to help reproduce this issue.

### Summary

If the data used in pydeck contains NaN (even if it is not used), the application fails with 
![image](https://user-images.githubusercontent.com/25638902/205078988-992fdce1-a6b8-4183-9237-5cd4e358e2ff.png)


### Reproducible Code Example

```Python
import math, pandas, pydeck, streamlit

streamlit.set_page_config(layout="wide")
data = pandas.DataFrame({"lng": [-109.037673], "lat": [36.994672], "weight": [math.nan]})
layer = pydeck.Layer("ScatterplotLayer", data=data, get_position=["lng", "lat"], radius_min_pixels=4)
deck = pydeck.Deck(layers=[layer], map_style=pydeck.map_styles.CARTO_LIGHT, tooltip={"text": "weight: {weight}"})
deck.to_html("test.html")
streamlit.pydeck_chart(deck, use_container_width=True)
```


### Steps To Reproduce

Run the code as usual.

### Expected Behavior

No error, as in the file ```test.html``` generated

### Current Behavior

SyntaxError:
Unexpected token 'N', ...""weight": NaN "... is not valid JSON


### Is this a regression?

- [ ] Yes, this used to work in a previous version.

### Debug info

- Streamlit version: Streamlit v1.15.1
- Python version: 3.10.4 (tags/v3.10.4:9d38120, Mar 23 2022, 23:13:41) [MSC v.1929 64 bit (AMD64)]
- Operating System: Windows 10.0.19045.2251
- Browser: Chome, Opera, Edge, Firefox
- Virtual environment: poetry


### Additional Information

_No response_

### Are you willing to submit a PR?

- [ ] Yes, I am willing to submit a PR!


Discussion:
Hi @clo-vis ! Thank you for filing the issue! I've investigated it, and it is indeed a tricky problem. Python's `json.dumps` does not produce completely valid JSON, which is what Pydeck uses. In any case, we can fix this by using our JSON5 library. I'll create a PR for this.

Resolving patch:
diff --git a/e2e/scripts/st_pydeck_chart.py b/e2e/scripts/st_pydeck_chart.py
--- a/e2e/scripts/st_pydeck_chart.py
+++ b/e2e/scripts/st_pydeck_chart.py
@@ -12,6 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import math
 from typing import Any, cast
 
 import numpy as np
@@ -63,3 +64,15 @@
         ],
     )
 )
+
+# Chart w/ invalid JSON - issue #5799.
+data = pd.DataFrame({"lng": [-109.037673], "lat": [36.994672], "weight": [math.nan]})
+layer = pdk.Layer(
+    "ScatterplotLayer", data=data, get_position=["lng", "lat"], radius_min_pixels=4
+)
+deck = pdk.Deck(
+    layers=[layer],
+    map_style=pdk.map_styles.CARTO_LIGHT,
+    tooltip={"text": "weight: {weight}"},
+)
+st.pydeck_chart(deck, use_container_width=True)


Test patch:
diff --git a/frontend/lib/src/components/elements/DeckGlJsonChart/DeckGlJsonChart.test.tsx b/frontend/lib/src/components/elements/DeckGlJsonChart/DeckGlJsonChart.test.tsx
--- a/frontend/lib/src/components/elements/DeckGlJsonChart/DeckGlJsonChart.test.tsx
+++ b/frontend/lib/src/components/elements/DeckGlJsonChart/DeckGlJsonChart.test.tsx
@@ -15,6 +15,7 @@
  */
 
 import React from "react"
+import JSON5 from "json5"
 import { render } from "@streamlit/lib/src/test_util"
 
 import { DeckGlJsonChart as DeckGlJsonChartProto } from "@streamlit/lib/src/proto"
@@ -177,7 +178,7 @@ describe("DeckGlJsonChart element", () => {
     const mockJsonParse = jest.fn().mockReturnValue(newJson)
 
     beforeEach(() => {
-      JSON.parse = mockJsonParse
+      JSON5.parse = mockJsonParse
     })
 
     afterEach(() => {
@@ -193,26 +194,26 @@ describe("DeckGlJsonChart element", () => {
       it(description, () => {
         DeckGlJsonChart.getDeckObject(getProps(), originalState)
 
-        expect(JSON.parse).not.toHaveBeenCalled()
+        expect(JSON5.parse).not.toHaveBeenCalled()
 
         DeckGlJsonChart.getDeckObject(getProps(), {
           ...originalState,
           ...stateOverride,
         })
 
-        expect(JSON.parse).toHaveBeenCalledTimes(1)
+        expect(JSON5.parse).toHaveBeenCalledTimes(1)
       })
     }
 
     testJsonParsing(
-      "should call JSON.parse when the element id is different",
+      "should call JSON5.parse when the element id is different",
       { id: newId }
     )
-    testJsonParsing("should call JSON.parse when FullScreen state changes", {
+    testJsonParsing("should call JSON5.parse when FullScreen state changes", {
       id: mockId,
       isFullScreen: true,
     })
-    testJsonParsing("should call JSON.parse when theme state changes", {
+    testJsonParsing("should call JSON5.parse when theme state changes", {
       id: mockId,
       isLightTheme: true,
     })