I would like to display a radar chart with JavaScript by using the element values from PyScript. However, I could not display the chart after trying my code.
I have tried:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>
Read CSV with Pandas using PyScript
</title>
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
<script defer src="https://cdn.jsdelivr.net/pyodide/v0.23.4/full/pyodide.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/echarts.min.js"></script>
<script src="echarts.js"></script>
</head>
<body>
<p id="csv"></p>
<py-config type="json">
{
"packages": ["pandas"]
}
</py-config>
<py-script>
import pandas as pd
import numpy as np
from pyodide.http import open_url
#from js import createObject
#from pyodide.ffi import create_proxy
#createObject(create_proxy(globals()), "pyodideGlobals")
url_content = open_url("https://raw.githubusercontent.com/linnlim/Laptop/main/Laptop.csv")
df = pd.read_csv(url_content)
L1_VRAM = df['VRAM'].loc[df.index[0]]
L2_VRAM = df['VRAM'].loc[df.index[1]]
L3_VRAM = df['VRAM'].loc[df.index[2]]
L1_RAM = df['RAM'].loc[df.index[0]]
L2_RAM = df['RAM'].loc[df.index[1]]
L3_RAM = df['RAM'].loc[df.index[2]]
L1_ROM = df['ROM'].loc[df.index[0]]
L2_ROM = df['ROM'].loc[df.index[1]]
L3_ROM = df['ROM'].loc[df.index[2]]
L1_CPU = df['CPU'].loc[df.index[0]]
L2_CPU = df['CPU'].loc[df.index[1]]
L3_CPU = df['CPU'].loc[df.index[2]]
L1_Price = df['Price'].loc[df.index[0]]
L2_Price = df['Price'].loc[df.index[1]]
L3_Price = df['Price'].loc[df.index[2]]
def L1_VRAM():
return df['VRAM'].loc[df.index[0]]
def L2_VRAM():
return df['VRAM'].loc[df.index[1]]
def L3_VRAM():
return df['VRAM'].loc[df.index[2]]
def L1_RAM():
return df['RAM'].loc[df.index[0]]
def L2_RAM():
return df['RAM'].loc[df.index[1]]
def L3_RAM():
return df['RAM'].loc[df.index[2]]
def L1_ROM():
return df['ROM'].loc[df.index[0]]
def L2_ROM():
return df['ROM'].loc[df.index[1]]
def L3_ROM():
return df['ROM'].loc[df.index[2]]
def L1_CPU():
return df['CPU'].loc[df.index[0]]
def L2_CPU():
return df['CPU'].loc[df.index[1]]
def L3_CPU():
return df['CPU'].loc[df.index[2]]
def L1_Price():
return df['Price'].loc[df.index[0]]
def L2_Price():
return df['Price'].loc[df.index[1]]
def L3_Price():
return df['Price'].loc[df.index[2]]
csv = Element('csv')
csv.write(L3_CPU())
</py-script>
<div id="main" style="width: 600px;height:400px;"></div>
<script type="text/javascript">
var chartDom = document.getElementById('main');
var myChart = echarts.init(chartDom);
var option;
console.log(`In Python right now, x = ${pyscript.interpreter.globals.get('L1_CPU')})
option = {
title: {
text: 'Basic Radar Chart'
},
legend: {
data: ['Laptop 1', 'Laptop 2', 'Laptop 3']
},
radar: {
// shape: 'circle',
indicator: [
{ name: 'VRAM', max: 10 },
{ name: 'RAM', max: 10 },
{ name: 'ROM', max: 10 },
{ name: 'CPU', max: 10 },
{ name: 'Price', max: 10 }
]
},
series: [
{
name: 'Laptop Specification',
type: 'radar',
data: [
{
value: [${pyscript.interpreter.globals.get('L1_VRAM')}, ${pyscript.interpreter.globals.get('L1_RAM')}, ${pyscript.interpreter.globals.get('L1_ROM')}, ${pyscript.interpreter.globals.get('L1_CPU')}, ${pyscript.interpreter.globals.get('L1_Price')}],
name: 'Laptop 1'
},
{
value: [${pyscript.interpreter.globals.get('L2_VRAM')}, ${pyscript.interpreter.globals.get('L2_RAM')}, ${pyscript.interpreter.globals.get('L2_ROM')}, ${pyscript.interpreter.globals.get('L2_CPU')}, ${pyscript.interpreter.globals.get('L2_Price')}],
name: 'Laptop 2'
},
{
value: [${pyscript.interpreter.globals.get('L3_VRAM')}, ${pyscript.interpreter.globals.get('L3_RAM')}, ${pyscript.interpreter.globals.get('L3_ROM')}, ${pyscript.interpreter.globals.get('L3_CPU')}, ${pyscript.interpreter.globals.get('L3_Price')}],
name: 'Laptop 3'
}
]
}
]
};
option && myChart.setOption(option);
</script>
</body>
</html>
I am expecting to display a radar chart with 3 polygons of the laptop specifications (VRAM, RAM, ROM, CPU, Price).
I think the problem is with the ${pyscript.interpreter.globals.get()} function.
Thanks in advance.
2
Answers
There are some minor issues with the code you posted:
get
):pyscript.interpreter.globals.get('L3_VRAM')()
`${pyscript.interpreter.globals.get('L3_VRAM')())}`
;to get the numbers. I used the
Number
constructor likeNumber(pyscript.interpreter.globals.get('L3_VRAM')())
The main issue is when the javascript gets executed. The way
you run it, the javascript code was executed way before the
pyscript had completed, so it had no data to represent.
Clearly, the code that builds the chart has to be included
inside a function (I called it
makeChart
), and thatfunction has to be called when pyscript is ready.
The approach taken by most examples (examples
that start a javascript function that uses pyscript
defined variables), is to call the function as an
event handler – that is display a button initially
let the user press it and then display the chart.
To avoid that, it seems sufficient to just allow
the code sequence that called the function complete,
and then, when the event loop takes over, call the
function that needs to access pyscript global variables.
For that I defined a javascript function
startScript
Here’s a full snippet with these and other details:
I refrained from optimizing the code in order to keep it as much as possible similar to the original post. While the snippet shows the javascript on top, the original sequence that had the javascript at the end of the file works.