I’m trying to use the "movableRowsConnectedTables" built-in functionality as explained in the tabulator.js examples
It doesn’t seem to work as expected:
import dash
from dash import html
import dash_bootstrap_components as dbc
import dash_tabulator
columns = [
{ "title": "Name",
"field": "name",}
]
options_from = {
'movableRows' : True,
'movableRowsConnectedTables':"tabulator_to",
'movableRowsReceiver': "add",
'movableRowsSender': "delete",
'height':200,
'placeholder':'No more Rows'
}
options_to = {
'movableRows' : True,
'height':200,
'placeholder':'Drag Here'
}
data = [
{"id":1, "name":"a"},
{"id":2, "name":"b"},
{"id":3, "name":"c"},
]
layout = html.Div(
[
dbc.Row(
[
dbc.Col(
[ html.Header('DRAG FROM HERE'),
dash_tabulator.DashTabulator(
id='tabulator_from',
columns=columns,
options=options_from,
data=data,
),
], width = 6
),
dbc.Col(
[ html.Header('DROP HERE'),
dash_tabulator.DashTabulator(
id='tabulator_to',
columns=columns,
options=options_to,
data = []
),
], width = 6
)
]
)
]
)
app = dash.Dash(external_stylesheets=[dbc.themes.BOOTSTRAP])
app.layout = dbc.Container(layout, fluid=True)
if __name__ == '__main__':
app.run_server(debug=True)
Is it also possible to get callbacks when elements were dropped?
It would be great to have this functionality inside dash!
example
im not familiar with tabulator_dash but the table your sending too also needs a 'movableRowsConnectedTables':"tabulator_from" option
Related
I created a very simple (one page) application in Dash that appends random data to a plotly chart using a dcc.Interval component and the extendData method (I'd like to have x values max).
The program worked like a charm, until I tried to port it to a multi-page application:
I used the following example:
https://github.com/facultyai/dash-bootstrap-components/blob/main/examples/python/templates/multi-page-apps/responsive-collapsible-sidebar/sidebar.py
and replaced:
elif pathname == "/page-1":
return html.P("This is the content of page 1. Yay!")
with:
import page_1
...
elif pathname == "/page-1":
return page_1.layout
My page_1.py contains the following code:
from dash import dcc, html
import dash_bootstrap_components as dbc
import plotly.graph_objs as go
layout = dbc.Card(dbc.CardBody([
html.H4('Live Feed'),
dcc.Graph(id='live-update-graph',
figure=go.Figure({'data':
[
{'x': [], 'y': []},
{'x': [], 'y': []},
{'x': [], 'y': []},
{'x': [], 'y': []}
]
}),
),
dcc.Interval(
id='interval-component',
interval=0.1*1000, # in milliseconds
n_intervals=0
)
]
))
I put my Callback in my app.py file:
#app.callback(Output('live-update-graph', 'extendData'),
Input('interval-component', 'n_intervals')
)
def update_graph_live(n):
# Collect some data
y1 = np.random.normal(loc = 10, scale=10)
y2 = y1 + random.randint(-5, 5)
y3 = y2 + random.randint(-10, 60)
y4 = y3 + random.randint(-40, 2)
return [{'x': [[datetime.datetime.now()]] * 4,'y': [[y1], [y2], [y3], [y4]]}, [0,1, 2, 3], 300]
...
if __name__ == '__main__':
app.run_server(debug=True)
Unfortunatly, my chart will only update when I'm browsing another tab in Chrome, not when I'm displaying it.
I have another page with some other components and an associated callback declared in my app.py file as :
#app.callback(
Output("result-code", "children"),
Input("slider", "value"),
)
def create_python_script(slider):
markdown = markdown_start
markdown += '''
msg = {{
"slider_value": {slider}
}}'''.format(slider=slider)
markdown += markdown_end
return markdown
And my Markdown component is updated in real-time, no problem with that.
Here is a copy of my callback status:
Callback status in Dash
My developper console shows every incoming message in the front-end part:
{
"multi": true,
"response": {
"live-update-graph": {
"extendData": [
{
"x": [
[
"2023-02-13T16:58:37.533426"
],
[
"2023-02-13T16:58:37.533426"
],
[
"2023-02-13T16:58:37.533426"
],
[
"2023-02-13T16:58:37.533426"
]
],
"y": [
[
-4.26648933108117
],
[
-3.2664893310811696
],
[
-8.26648933108117
],
[
-9.26648933108117
]
]
},
[
0,
1,
2,
3
],
300
]
}
}
}
Am I doing something wrong?
Thanks in advance !
I was using http://localhost:8888 instead of http://127.0.0.1:8888 to connect to my web app and somehow didn't see it, and that was preventing the chart from being updated.
I am very new to the Groovy scripts and would like to build a JSON output from the below JSON input. Kindly help!
My JSON input looks like this:
{
"id":"1222",
"storageNode": {
"uuid": "22255566336",
"properties": {
"BuinessUnit": [
"Light",
"Fan",
"Watch"
],
"Contact": [
"abc#gmail.com",
"fhh#gmail.com"
],
"Location": [
"Banglore",
"Surat",
"Pune"
]
}
}
}
Expected Output:
[
{
"BuinessUnit": "Light",
"Contact": "abc#gmail.com",
"Location": "Banglore"
},
{
"BuinessUnit": "Fan",
"Contact": "fhh#gmail.com",
"Location": "Surat"
},
{
"BuinessUnit": "Watch",
"Contact": "",
"Location": "Pune"
}
]
Please note that in case any array is not matching the value count that will always be the last one and in that case, a blank value ("") has to be populated. The "BusinessUnit" object can be referred for array size validation.
My code looks like this:
import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;
import groovy.json.*;
def Message processData(Message message) {
//Body
def body = message.getBody(String.class);
def jsonSlurper = new JsonSlurper()
def list = jsonSlurper.parseText(body)
String temp
def BU = list.storageNode.properties.get("BusinessUnit")
def builder = new JsonBuilder(
BU.collect {
[
BusinessUnit: it
]
}
)
message.setBody(builder.toPrettyString())
return message
}
It is only returning this:
[
{
"BusinessUnit": "Light"
},
{
"BusinessUnit": "Fan"
},
{
"BusinessUnit": "Watch"
}
]
Now how will I add other parts to it? Please help!
I have come up with the following solution that converts source JSON string to the target JSON string:
import groovy.json.JsonBuilder
import groovy.json.JsonSlurper
def json = '''
{
"id":"1222",
"storageNode": {
"uuid": "22255566336",
"properties": {
"BusinessUnit": [
"Light",
"Fan",
"Watch"
],
"Contact": [
"abc#gmail.com",
"fhh#gmail.com"
],
"Location": [
"Banglore",
"Surat",
"Pune"
]
}
}
}
'''
println convert(json)
String convert(String json) {
def list = new JsonSlurper().parseText(json)
List<String> units = list.storageNode.properties.BusinessUnit
List<String> contacts = list.storageNode.properties.Contact
List<String> locations = list.storageNode.properties.Location
def result = []
units.eachWithIndex { unit, int index ->
result << [
BusinessUnit: unit,
Contact : contacts.size() > index ? contacts[index] : '',
Location : locations.size() > index ? locations[index] : '',
]
}
return new JsonBuilder(result).toPrettyString()
}
I've omitted the logic of getting string from the message and packaging transformed JSON into message.
I hope it will help you to move forward. Please let me know if you need further assistance here.
You can use the built-in Groovy facilities, like transpose():
import groovy.json.*
def json = new JsonSlurper().parseText '''{ "id":"1222", "storageNode": { "uuid": "22255566336", "properties": {
"BuinessUnit": [ "Light", "Fan", "Watch" ],
"Contact": [ "abc#gmail.com", "fhh#gmail.com" ],
"Location": [ "Banglore", "Surat", "Pune" ] } } }'''
def names = json.storageNode.properties*.key
def values = json.storageNode.properties*.value
int maxSize = values*.size().max()
// pad lists with trainiling spaces
values.each{ v -> ( maxSize - v.size() ).times{ v << '' } }
def result = values.transpose().collect{ tuple -> [ names, tuple ].transpose().collectEntries{ it } }
assert result.toString() == '[[BuinessUnit:Light, Contact:abc#gmail.com, Location:Banglore], [BuinessUnit:Fan, Contact:fhh#gmail.com, Location:Surat], [BuinessUnit:Watch, Contact:, Location:Pune]]'
This piece of code can process everything under storageNode.properties.
I would like to parse the below nested JSON in Groovy and get the values of "it","ft","stg","prd" for each application and store in separate array.Can someone help please ?
{
"Application1": {
"environments": {
"it": [
"server1"
],
"ft": [
"server2"
],
"stg": [
"server3"
],
"prd": [
"server4"
]
},
"war-path" : "/opt/tomcat/",
"war-name" : "Application1"
},
"Application2": {
"environments": {
"it": [
"serverA"
],
"ft": [
"serverB"
],
"stg": [
"serverC"
],
"prd": [
"serverD"
]
},
"war-path" : "/var/lib",
"war-name" : "Application2"
}
}
}
Expected output something like below in separate list for each environment. Also the 1st level(Application1,Application2..) will be dynamic always
it = [server1,serverA]
ft = [server2,serverB]
stg = [server3, serverC]
prd = [server4,serverD]
Updated: After deriving expected answer with the inputs from Philip Wrage.
def projects = readJSON file: "${env.WORKSPACE}//${infrafile}"
def json_str = JsonOutput.toJson(projects)
def json_beauty = JsonOutput.prettyPrint(json_str)
def envlist = ["it","ft","stg","prd"]
def fileListResult = []
for (envname in envlist) {
servers=serverlist(json_beauty,envname)
println(servers)
}
def serverlist(json_beauty,envname){
def jsonSlurper = new JsonSlurper()
def jsonMap = jsonSlurper.parseText(json_beauty)
assert jsonMap instanceof Map
jsonMap.each { appName, appDetails ->
assert appDetails instanceof Map
appDetails.environments.each { envName, servers ->
for (items in servers{
if (envName == "${envname}"){
fileListResult.add(items)
}
}
}
}
return fileListResult
}
As suggested by #Chris, you can use the built-in JsonSlurper to parse the JSON and then navigate the parsed results as a Map.
In the following example I show how you can simply print the results to the console. However, using this as a guide, you can see how to extract the data into whatever kind of data structure that suits your purpose.
Assume that you have the JSON in a String variable jsonText. You may be pulling in from a file or an HTTP POST or whatever your app requires. I used the following code to set this value for testing.
def jsonText = """
{
"Application1": {
"environments": {
"it": [
"server1"
],
"ft": [
"server2"
],
"stg": [
"server3"
],
"prd": [
"server4"
]
},
"war-path" : "/opt/tomcat/",
"war-name" : "Application1"
},
"Application2": {
"environments": {
"it": [
"serverA"
],
"ft": [
"serverB"
],
"stg": [
"serverC"
],
"prd": [
"serverD"
]
},
"war-path" : "/var/lib",
"war-name" : "Application2"
}
}
"""
The meat of the solution then follows. Parse the JSON text into a Map, and then iterate over the entries in that Map, performing whatever operations you require. The servers for each environment will already be contained within a List.
import groovy.json.JsonSlurper
def jsonSlurper = new JsonSlurper()
def jsonMap = jsonSlurper.parseText(jsonText)
assert jsonMap instanceof Map
jsonMap.each { appName, appDetails ->
println "Application: $appName"
assert appDetails instanceof Map
appDetails.environments.each { envName, servers ->
assert servers instanceof List
println "\tEnvironment: $envName"
println "\t\t$servers"
}
}
From this code I obtain the following console output.
Application: Application1
Environment: it
[server1]
Environment: ft
[server2]
Environment: stg
[server3]
Environment: prd
[server4]
Application: Application2
Environment: it
[serverA]
Environment: ft
[serverB]
Environment: stg
[serverC]
Environment: prd
[serverD]
EDIT (based on clarification of required output):
import groovy.json.JsonSlurper
def jsonText = "\n{\n \"Application1\": {\n \"environments\": {\n \"it\": [\n \"server1\"\n ],\n \"ft\": [\n \"server2\"\n ],\n \"stg\": [\n \"server3\"\n ],\n \"prd\": [\n \"server4\"\n ]\n },\n \"war-path\" : \"/opt/tomcat/\",\n \"war-name\" : \"Application1\"\n},\n \"Application2\": {\n \"environments\": {\n \"it\": [\n \"serverA\"\n ],\n \"ft\": [\n \"serverB\"\n ],\n \"stg\": [\n \"serverC\"\n ],\n \"prd\": [\n \"serverD\"\n ]\n },\n \"war-path\" : \"/var/lib\",\n \"war-name\" : \"Application2\"\n}\n}\n"
def jsonSlurper = new JsonSlurper()
def jsonMap = jsonSlurper.parseText(jsonText)
def result = [:]
jsonMap.each { appName, appDetails ->
appDetails.environments.each { envName, servers ->
if ( !result.containsKey(envName) ) {
result.put(envName, [])
}
result.get(envName).addAll(servers)
}
}
println result
Results are a Map where the keys are the various environments specified within JSON file, and the values are Lists of servers associated with those environments across all applications. You can access any List individually with something like result.stg, or assign these the different variables later if that's desired/required (def stg = result.stg).
[it:[server1, serverA], ft:[server2, serverB], stg:[server3, serverC], prd:[server4, serverD]]
If you want all environments, you can use the spread operator to take
all environments from the values. Next you have to merge the maps on
the keys. E.g.
def json = """ { "Application1": { "environments": { "it": [ "server1" ], "ft": [ "server2" ], "stg": [ "server3" ], "prd": [ "server4" ] }, }, "Application2": { "environments": { "it": [ "serverA" ], "ft": [ "serverB" ], "stg": [ "serverC" ], "prd": [ "serverD" ] }, } } }"""
def data = new groovy.json.JsonSlurper().parseText(json)
println data.values()*.environments.inject{ a, b ->
b.inject(a.withDefault{[]}) { m, kv ->
// with groovy 2.5+: m.tap{ get(kv.key).addAll(kv.value) }
m[kv.key].addAll(kv.value); m
}
}
// → [it:[server1, serverA], ft:[server2, serverB], stg:[server3, serverC], prd:[server4, serverD]]
I have the following example.json. How can I parse it to csv in order to get the mean value (between ** mean_value **).
I want something like in example.csv:
305152,277504,320512
[
{
"name": "stats",
"columns": [
"time",
"mean"
],
"points": [
[
1444038496000,
**305152**
],
[
1444038494000,
**277504**
],
[
1444038492000,
**320512**
]
]
}
]
In python it looks like this
import json
results = []
with open('example.json', 'r') as f:
content = json.loads(f.read())
for element in content:
results.append(','.join([str(y[1]) for y in element['points']]))
with open('example.csv', 'w') as f:
f.write('\n'.join(results))
What's the best way to collect a list of attributes from a JSON hierarchy? Here's what I'm trying to do:
import groovy.json.JsonSlurper
def jsontxt = '''
{
"lvl1": [
{
"lvl2": [
{
"lvl3": [
{
"a1": false,
"a2": {
"a2b1": false,
"a2b2": false
},
"a3": "wantvalue1"
},
{
"a1": false,
"a2": {
"a2b1": false,
"a2b2": false
},
"a3": "wantvalue2"
}
],
},
],
}
]
}
'''
def jsresult = new JsonSlurper().parseText(jsontxt)
def mytry = jsresult.lvl1.lvl2.lvl3.collect{it.a3} // [[[wantvalue1, wantvalue2]]]
assert ["wantvalue1","wantvalue2"] == mytry
Apologies the input is not as clean as it could be but I didn't want to lose my situation.
What I want is a basic list without the additional empty lists. I know there must be a really cool way to do this but I'm not groovy enough for it. . . help??
Pretty close. Try flatten().
Try jsresult.lvl1.lvl2.lvl3.collect{it.a3}.flatten() or myTry.flatten()