Get current state of graph after elements are added dynamically - cytoscape.js

I am using Cytoscape.js and the context menus extension within a React app through react-cytoscape.js. Right now, I can dynamically add nodes through an onClickFunction as a menu item. I would like to get the current state of the graph - that is, all the nodes that have been added as well as the ones it started with.
How can I do this? So far, I've tried cy.json(), but that only returns the initial state of the graph.
Below is all of my cytoscape code.
class MyApp extends React.Component {
constructor(props){
super(props);
}
render(){
const elements = [ // Nodes and edges to be added initially
{ data: { id: 'one', label: 'Node 1' }, position: { x: 250, y: 250 } },
{ data: { id: 'two', label: 'Node 2' }, position: { x: 300, y: 250 } },
{ data: { source: 'one', target: 'two', label: 'Edge from Node1 to Node2' } }
];
return <CytoscapeComponent
cy = {cy => { // Extensions and their options
cy.contextMenus({
menuItems: [
{ // Adds the ability to add nodes from the right-click menu
id: 'add-node',
content: 'add node',
tooltipText: 'add node',
image: {src: "./node_modules/cytoscape-context-menus/assets/add.svg", width: 12, height: 12, x: 6, y: 4},
coreAsWell: true,
// When we move adding nodes to a sidebar, probably use this as reference
onClickFunction: function (event) {
var data = {
group: 'nodes'
};
var pos = event.position || event.cyPosition;
cy.add({
data: data,
position: {
x: pos.x,
y: pos.y
}
});
}
}
]
})
}}
elements={elements}
style={ { width: '100%', height: '40vmax'} } />;
}
}

Related

Hide Pie Chart Slice on Load

I would like to hide a pie chart slice on load but cannot figure out how to do so.
I'm not sure it's possible, but it seems like it might be. There is a property "selected", but it does not seem to change when I manually select or unselect a wedge via the legend. I've tried to dispatchAction like this example (example), but haven't had any luck:
I think you are close to the solution... Actually, you should tweak legend.selected.
Take a look at this basic example:
let option = {
legend: {
selected: {
'B': false // <--- HERE
}
},
series: [
{
type: 'pie',
label: {
position: 'inner'
},
data: [
{ value: 10, name: 'A' },
{ value: 20, name: 'B' },
{ value: 15, name: 'C' }
]
}
]
};
let myChart = echarts.init(document.getElementById('main'));
myChart.setOption(option);
#main {
width: 300px;
height: 300px;
}
<script src="https://cdn.jsdelivr.net/npm/echarts#5.4.1/dist/echarts.min.js"></script>
<div id="main"></div>

update vue chart-js y axis max value without re rendering entire chart

I am working on a project where I am implementing some charts from the Vue-Chartjs library. I need the Y-axis max value to change everytime the user changes the filters given. I Import an existing barchart from the vue-chartjs library. In the code there is a javascript file that has some defaults already, to set extra options I can use the extraOptions object as a prop to personalize each chart accordingly. Here is the default component:
import { Bar } from 'vue-chartjs'
import { hexToRGB } from "./utils";
import reactiveChartMixin from "./mixins/reactiveChart";
let defaultOptions = {
tooltips: {
tooltipFillColor: "rgba(0,0,0,0.5)",
tooltipFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
tooltipFontSize: 14,
tooltipFontStyle: "normal",
tooltipFontColor: "#fff",
tooltipTitleFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
tooltipTitleFontSize: 14,
tooltipTitleFontStyle: "bold",
tooltipTitleFontColor: "#fff",
tooltipYPadding: 6,
tooltipXPadding: 6,
tooltipCaretSize: 8,
tooltipCornerRadius: 6,
tooltipXOffset: 10,
},
legend: {
display: false
},
scales: {
yAxes: [{
ticks: {
fontColor: "#9f9f9f",
fontStyle: "bold",
beginAtZero: true,
display: false,
min: 0,
max: 100
},
gridLines: {
display: false,
drawBorder: false,
}
}],
xAxes: [{
gridLines: {
display: false,
drawBorder: false,
},
}],
}
};
export default {
name: 'BarChart',
extends: Bar,
mixins: [reactiveChartMixin],
props: {
labels: {
type: [Object, Array],
description: 'Chart labels. This is overridden when `data` is provided'
},
datasets: {
type: [Object, Array],
description: 'Chart datasets. This is overridden when `data` is provided'
},
data: {
type: [Object, Array],
description: 'Chart.js chart data (overrides all default data)'
},
color: {
type: String,
description: 'Chart color. This is overridden when `data` is provided'
},
extraOptions: {
type: Object,
description: 'Chart.js options'
},
title: {
type: String,
description: 'Chart title'
},
},
methods: {
assignChartData() {
let { gradientFill } = this.assignChartOptions(defaultOptions);
let color = this.color || this.fallBackColor;
return {
labels: this.labels || [],
datasets: this.datasets ? this.datasets : [{
label: this.title || '',
backgroundColor: gradientFill,
borderColor: color,
pointBorderColor: "#FFF",
pointBackgroundColor: color,
pointBorderWidth: 2,
pointHoverRadius: 4,
pointHoverBorderWidth: 1,
pointRadius: 4,
fill: true,
borderWidth: 1,
data: this.data || []
}]
}
},
assignChartOptions(initialConfig) {
let color = this.color || this.fallBackColor;
const ctx = document.getElementById(this.chartId).getContext('2d');
const gradientFill = ctx.createLinearGradient(0, 170, 0, 50);
gradientFill.addColorStop(0, "rgba(128, 182, 244, 0)");
gradientFill.addColorStop(1, hexToRGB(color, 0.6));
let extraOptions = this.extraOptions || {}
return {
...initialConfig,
...extraOptions,
gradientFill
};
}
},
mounted() {
this.chartData = this.assignChartData({});
this.options = this.assignChartOptions(defaultOptions);
this.renderChart(this.chartData, this.options, this.extraOptions);
}
}
I use this js file to import the bar chart inside a vue component like you see down below.
everytime the input of the form changes i need to re render the chart. I use the onInputChange() method to turn the boolean loaded to false and call the loadData() method.
Inside the loadData() method I make an axios request that gets me the right data every time. I also get the maximum value for my Y axis.
Then in the response I call on updateChart() so that I can update the data and the max value of the chart. then i turn the boolean loaded to true again so that my chart renders accordingly.
The problem with this approach is that the chart disappears completely for a split of a second. Before deciding to change the max Value of the Y axis I was able to update the data of my chart without having to use the v-if="loaded".
I need to find a solution where the chart re renders without it completely disappearing from the page. I know some suggested to use computed variables but i don't fully understand how it is supposed to work. Here is the component minus the form fields.
I guess in it's essence what I want is to update the Y axis max value without having to re render the entire chart.
<template>
<div>
<BarChart v-if="loaded" :labels="chartLabels"
:datasets="datasets"
:height="100"
:extraOptions="extraOptions"
>
</BarChart>
<br>
</div>
</template>
<script>
import BarChart from '../../components/Library/UIComponents/Charts/BarChart'
import Dropdown from "../../components/Library/UIComponents/Dropdown"
import GroupedMultiSelectWidget from "~/components/widgets/GroupedMultiSelectWidget"
import SelectWidget from "../../components/widgets/SelectWidget";
export default{
name: 'PopularChart',
components: {BarChart, Dropdown, SelectWidget, GroupedMultiSelectWidget},
data(){
return {
loaded:true,
form:{
day: 'Today',
workspace:'',
machine_family: [],
duration: [],
user_group: [],
dt_start:'',
dt_end:''
},
url: `/api/data_app/job_count_by_hour/`,
chart_data: [],
days: [ {day:"Today", id:"Today"},
{day:"Monday", id:"0"},
{day:"Tuesday",id:"1"},
{day:"Wednesday",id:"2"},
{day:"Thursday",id:"3"},
{day:"Friday",id:"4"},
{day:"Saturday",id:"5"},
{day:"sunday",id:"6"} ],
chartLabels: ["00u", "1u", "2u", "3u","4u","5u", "6u", "7u", "8u", "9u", "10u", "11u", "12u", "13u", "14u", "15u","16u", "17", "18u","19u","20u","21u","22u","23u"],
datasets: [],
maximumValue: '',
extraOptions:{}
}
},
methods: {
onInputChange() {
this.loaded = false
this.loadData()
},
async loadData() {
await this.$axios.get(`${this.url}?day=${this.form.day}&date_start=${this.form.dt_start}&date_end=${this.form.dt_end}&workspace=${this.form.workspace}&user_group=${this.form.user_group}&machine_family=${this.form.machine_family}`)
.then(response => {
this.updateChart(response.data.results,response.data.maximum)
this.loaded = true
})
},
updateChart(data,maxValue) {
this.datasets = [{
label: ["jobs %"],
backgroundColor:"#f93232",
data: data
},]
this.maximumValue = maxValue
this.extraOptions = {
tooltips: {
callbacks:{
label: function (tooltipItems,){
if (tooltipItems.value > ((50/100) * maxValue)){
return 'busy';
}else if (tooltipItems.value < ((30/ 100) * maxValue) ){
return ' not busy';
}else if ( tooltipItems.value < ((40/ 100) * maxValue )){
return 'kind of busy'
}
}
}
},
scales: {
yAxes: [{
gridLines: {
zeroLineColor: "transparent",
display: false,
drawBorder: false,
},
ticks: {
max: this.maximumValue,
display: true,
}
}],
xAxes: [{
gridLines: {
zeroLineColor: "transparent",
display: false,
drawBorder: false,
},
}],
},
}
},
},
mounted() {
this.loadData()
},
}
</script>
You can bind the chart to a variable in data(), initialize it with some defaults in mounted() and whenever you want to update the chart data, you use the Chart.js API.
An implementation could look something like this:
export default {
data() {
return {
chart: null
};
},
mounted() {
this.chart = new Chart(/* defaults */);
},
methods: {
updateChart(data) {
this.chart.data.datasets = data;
/* rest of the chart updating */
this.chart.update();
}
}
};

Highchart gauge not displaying min/max value in Vue.js

I have a weird issue. I am displaying data from a neo4j database onto the highcharts. I am able to retrieve the data, but when i try to put it onto the charts, some of it doesnt display. Here is my gauge code
CustomGauge.vue
<template>
<highcharts :options="chartOptions"></highcharts>
</template>
<script>
import { Chart } from "highcharts-vue";
export default {
name: "CustomGuage",
components: {
highcharts: Chart
},
props: ["data", "title", "range1", "range2", "min", "max"],
data() {
return {
chartOptions: {
chart: {
type: "gauge",
// plotBackgroundColor: null,
// plotBackgroundImage: null,
// plotBorderWidth: 0,
// plotShadow: false,
//marginBottom: 170,
},
credits: {
enabled: false
},
title: {
text: this.title,
align: "left"
},
pane: {
startAngle: -150,
endAngle: 150,
size: 200,
background: {
borderWidth: 0
}
},
// the value axis
yAxis: {
min: this.min,
max: this.max,
// tickPixelInterval: 30,
// tickWidth: 2,
// tickColor: "#666",
plotBands: [
{
from: 0,
to: this.range1,
color: "#55BF3B" // green
},
{
from: this.range1,
to: this.range2,
color: "#DDDF0D" // yellow
},
{
from: this.range2,
to: 1000,
color: "#DF5353" // red
}
]
},
series: [
{
data: this.data
// tooltip: {
// valueSuffix: " km/h"
// }
},
// // {
// // data: this.target,
// // dataLabels: {
// // enabled: true,
// // format: "Target: {y}%",
// // verticalAlign: "bottom",
// // borderWidth: 0
// // //useHTML: true,
// // },
// }
]
}
};
},
watch: {
data(newVal) {
this.chartOptions.series[0].data = newVal;
}
}
};
I define my chart like this
<CustomGuage :title="gaugeTitle1" :data="gaugeData1" :min="gauge1min" :max="gauge1max" :range1="gauge1Range1" :range2="gauge1Range2" />
I initialize it in data() like this -
gaugeTitle1: [],
gaugeData1: [],
gauge1Range1: [],
gauge1Range2: [],
gauge1min: [],
gauge1max: [],
Using the neo4j-vuejs connector, i retrieve the data like this -
const session19 = this.$neo4j.getSession();
// KPI 1
session19
.run(
"match (n:proj) where exists(n.min) return n.name as title,n.min as min,n.max as max,n.range1
as range1,n.range2 as range2,n.target AS target, n.current as data"
)
.then((res) => {
// KPI 1-------------------------
this.data1 = res.records[0].get("data");
var a = JSON.parse(this.data1);
this.gaugeData1.push(a);
console.log(a)
this.min1 = res.records[0].get("min");
var b = JSON.parse(this.min1);
this.gauge1min = b;
console.log(this.gauge1min)
this.max1 = res.records[0].get("max");
var c = JSON.parse(this.max1);
this.gauge1max = c;
console.log(this.gauge1max)
this.title1 = res.records[0].get("title");
this.gaugeTitle1.push(this.title1)
console.log(this.gaugeTitle1);
})
.then(() => {
session.close();
});
The retrieval of data works fine, i checked in the console.The weird part is if i comment/uncomment or change something in CustomGauge.vue, the charts displays perfectly, displays everything perfectly from the database.But once i refresh the page, it is gone. Could someone help me out. thanks for your help in advance
Probably a reactivity issue.
Instead of
this.chartOptions.series[0].data = newVal;
Try
this.$set(this.chartOptions.series[0], 'data', newVal)

What config and options do I need for react-native-highcharts to make a highstock OHLC graph?

I've been going through HighStock API to try and find which config and options I need to pass to the ChartView component in react-native-highcharts to draw my graph. I'm having a hard time finding what combination of config and options will get my desired result, things like series, dataGrouping, etc... . My data is a 2 dimensional array with 4 values for OHLC. My desired result is the photo at the top of this stackoverflow.
Here is my code so far.
class OHLC extends React.Component {
static navigationOptions = ({ navigation }) => ({
title: "OHLC",
headerLeft: (
<TouchableOpacity
style={NavStyles.headerButton}
onPress={() => navigation.openDrawer()}>
<Icon name="bars" size={20} />
</TouchableOpacity>
),
})
render() {
var Highcharts='Highcharts';
var conf={
title: {
text: 'Stock Name'
},
xAxis: {
type: 'datetime',
tickPixelInterval: 150
},
yAxis: {
title: {
text: 'Price'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
// tooltip: {
// formatter: function () {
// return '<b>' + this.series.name + '</b><br/>' +
// Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', this.x) + '<br/>' +
// Highcharts.numberFormat(this.y, 2);
// }
// },
legend: {
enabled: false
},
// exporting: {
// enabled: false
// },
series: [{
type: 'ohlc',
name: 'AAPL Stock Price',
data: (function () {
let arrays = aExtractFromJson(data,'data', null,null);
arrays = ohlcExtractor(arrays);
return arrays;
// look at toFixed method for number to limit decimal point
}()),
dataGrouping: {
units: [[
'week', // unit name
[1] // allowed multiples
], [
'month',
[1, 2, 3, 4, 6]
]]
}
}]
};
const options = {
global: {
useUTC: false
},
lang: {
decimalPoint: ',',
thousandsSep: '.'
}
};
return (
<View>
<ChartView style={{height:300}} config={conf} options={options} stock={true} ></ChartView>
//To see if anything gets rendered.
<Text>HELLO DAVID!</Text>
</View>
);
}
}
After further research, I was able to find the config and options needed to create an OHLC Graph using the ChartView component in react-native-highcharts. I encountered some issues with rendering a blank screen so I added javaScriptEnabled={true} domStorageEnabled={true} originWhitelist={['']} to my ChartView.
In the config the essentials:
series with type: 'ohlc' and data: [[1,2,3,4],[2,3,4,5]] inside.
In options, no arguments are required, I left it as options='' in the ChartView.
Don't forget to add stock={true} in ChartView
My code, basic example:
import React, {Component} from 'react';
import {View} from 'react-native';
import ChartView from 'react-native-highcharts';
class OHLC extends React.Component {
constructor(props) {
super(props);
}
render() {
var Highcharts='Highcharts';
var conf={
chart: {
animation: Highcharts.svg, // don't animate in old IE
marginRight: 10,
},
title: {
text: 'Live random data'
},
xAxis: {
type: 'datetime',
tickPixelInterval: 150
},
yAxis: {
title: {
text: 'Value'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
legend: {
enabled: false
},
exporting: {
enabled: false
},
series: [{
type: 'ohlc',
name: 'Random data',
/*Open, high,low,close values in a two dimensional array(two days)*/
data: [[1,2,3,4],[2,3,4,5]],
}]
};
return (
<View style={{borderRadius: 4, marginTop: 30,}}>
<ChartView style={{height:500}} config={conf} javaScriptEnabled={true} domStorageEnabled={true} originWhitelist={['']} stock={true} options=''></ChartView>
</View>
);
}
}

Cytoscape.js setting node colour and other details

I am using Cytoscape.js to create a basic diagram and am curious as to how to set the colour and particular shape of each node. Here is my existing code:
layout: {
name: 'preset'
},
ready: function(){
window.cy = this;
cy.add([
{ group: "nodes", data: { id: "n0" }, position: { x: 100, y: 100 } },
{ group: "nodes", data: { id: "n1", shape: 'rectangle' }, position: { x: 200, y: 200 } },
{ group: "edges", data: { id: "e0", source: "n0", target: "n1" } }
]);
}
});
});
I was also curious as to how to animate the diagram and if there were any similar examples out there on that.
cheers,
...
style: [ // the stylesheet for the graph
{
selector: 'node',
style: {
'background-color': '#666',
'shape': 'rectangle',
}
},
],
...
background-color is probably the attribute you are looking for, this is set in the style option. More info can be in http://js.cytoscape.org/#getting-started/specifying-basic-options.
As for the shape, cytoscape has a few predefined shapes such as rectangle, circle, etc. You can even make your own, or have an svg as the node's image. Options for nodes are listed in http://js.cytoscape.org/#style/node-body.
For animation I would look at some of the demos uploaded and go from there. This one is particularly interesting js.cytoscape.org/demos/aedff159b0df05ccfaa5