Live Updates to Javascript Plotly graph C# MVC - javascript

I am new to Javascript, MVC, and making websites. I am making a company internal site that is used as a GUI for controlling hardware. The computer (Server) is connected to another machine taking measurements (data points). I have successfully created a page that plots this data using the plotly library, but instead of sending all of the data points from the server to the client after all the measurements have been taken, they want one point to be plotted at a time. This means making calls back to the server for each point. The class (object) that contains the functionality to do this is called the MeasurementManager. My first though was to pass this class into the view by ViewBag, then call the function that takes the measurement in a loop using razor syntax. For testing we can say we are taking 10 measurements. Then call the Javascript function that updates the plotly plot also inside of the loop and pass the data from the MeasurementManager to the plotly update function. I'm just not sure how to do this. For argument sake if it is possible to call the MeasurmentManager function inside of a javascript loop, that would be fine as well.
Controller: (Just created the MeasurementManager object and checks if it was created without error. I didn't want to do this error checking in the view with razor syntax. I tried passing the model strictly but I couldn't figure out how to get access to the same instance of the object, so ViewBag was the way to go. This function runs after clicking a button in another view)
[HttpPost]
public IActionResult Calibrate()
{
MeasurementManager measurementManager;
try
{
measurementManager = new MeasurementManager(ref ErrorMessage);
}
catch (Exception ex)
{
ErrorMessage = ex.Message;
return RedirectToAction("ErrorView");
}
ViewBag.MeasurementManager = measurementManager;
return View();
View: (This is the Calibrate view returned from the above function. It is enough code to get a plotly plot with no points plotted, and it contains an update plot function)
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<div class="row">
<div class="col-12">
<div id="CalibrationPlot" style="width:100%; height:1000px" class="js-plotly-plot"></div>
<div class="plot-container plotly"></div>
</div>
</div>
<script>
// Define Layout
var layout = {
xaxis: {range: [0, 256], title: "Mux"},
yaxis: {range: [0, 5*Math.pow(10, -10)], title: "Capacitance"},
title: "Capacitance vs Mux"
};
// Display using Plotly
Plotly.newPlot("CalibrationPlot", data, layout);
</script>
<script>
function updatePlot(capacitancePoint, elementPoint)
{
var update = [{
x: elementPoint,
y: capacitancePoint
}];
Plotly.update("CalibrationPlot", update, 0)
}
</script>
What I would like to add to the view is something like this which will measure a point and plot that value on the plotly plot. Hopefully this would achieve making a live plot on the webpage.
#{
for(int i = 0; i < 10; i++)
{
double MeasuredValue = ViewBag.measurementManager.MeasureValue(); // Y Coordinate
int xValue = i; // X Coordinate
// Make a call to Plotly.update (updatePlot function) and pass in these two values here
}
}
Feel free to add any solution that you think would work. I'm new to all of this and this is my first stackoverflow question.

Please use SignalR to update the frontend graph in real-time. OR Try to Blazor maybe that helps also.

Related

element.$server is undefined when passing data from java to javascript in vaadin 14

I'm trying to interact between Vaadin and amcharts. Basically I need to draw a map using amcharts libraries, and when I click on the map I need to send back information about the click to Java. My problem is that I can't figure out how to properly interact between the two, with the documentation showing very simple examples.
In the vaadin docs it shows an example like:
getElement().executeJS("jsMethodName($0)", getElement());
and then to send back data to Java:
element.$server.javaMethodName(args);
My problem is that I can send from Java to JS correctly, and the element is loaded correctly. But when I do element.$server.javaMethodName(), element.$server is always undefined. I don't understand if I'm missing something or if I dind't understand the correct way to use this.
This is my Java method:
#ClientCallable
private void clickBullet(String area) {
log.error("Clicked area: " + area);
}
and this is the call from JS:
function clickBullet(name, element) {
if(element !== null){
element.$server.clickBullet(name);
}
else {
console.log("element is null");
}
}
Note that element is not null, it is correct.
What am I doing wrong?

Dinamically populate google chart just using only Javascript

I'm using Google Charts API inside my C# project (using the WebBrowser from CefSharp), and it works with the data hard coded to it, but I'm running into a problem whenever I try to dinamically populate it using data.addRows(). I need to have something simple, like a external csv/json, so it's possible to run inside C# (WebBrowser is really limited and sometimes buggy), but every solution tells me to do that via php server or something more "complex" like that. So, is there a way to populate that chart just using JavaScript and an external file (or something different but viable)?
Thats the code, if useful:
<html>
<head>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
google.charts.load('current', {packages:["orgchart"]});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var data = new google.visualization.DataTable();
data.addColumn('string', 'Name');
data.addColumn('string', 'Manager');
data.addColumn('string', 'ToolTip');
// For each orgchart box, provide the name, manager, and tooltip to show.
data.addRows([['Alice', 'Mike', ''],['Bob', 'Jim', 'Bob Sponge'],['Carol', 'Bob', '']]);
// Create the chart.
var chart = new google.visualization.OrgChart(document.getElementById('chart_div'));
// Draw the chart, setting the allowHtml option to true for the tooltips.
chart.draw(data, {'allowHtml':true});
}
</script>
</head>
<body>
<div id="chart_div"></div>
</body>
</html>
Obs: CefSharp WebBrowser just calls this code above as a normal HTML file and runs it inside the C# application.
Thank you!
I've done something similar, but I've been using the arrayToDataTable() method of the google charts API, but I'm sure this can be done similarly. You will need to lean on C# though. I wanted to be thorough so this is a big one. More than happy to clarify because I'm sure that at least some of this will be poorly worded/confusing.
TLDR
Create a Class to hold your data points and a way to represent them as a list.
In Your Controller class, Create a method that returns a list containing your data points represented as lists. Turn that List of lists into JSON and Post it to a URL endpoint
Read your json data from that endpoint using ajax in the cshtml
Put the read json into your AddRows method.
Party
This will touch on : the .cshtml, the Home Controller, and Wherever you are pulling your data.
Wherever you are pulling your Data
My case is a bit complicated. But basically I have a method that just returns a list of type object that holds these objects, represented as lists. (eg. [<Timestamp>,<Temperature>,<Humidity>])
public class WeatherEntry
{
public string Timestamp { get; set; }
public double TEMPERATURE { get; set; }
public double Humidity { get; set; }
... Other stuff ...
}
If you can generate a list of data points, represented as lists on the c# side, you are in business.
The Controller class
Assuming you are using ASP.net MVC, you'll have a backing controller class that holds your Controlling C#
Once you have a list of type object containing your data points represented as lists, you can make it into JSON pretty easily using Newtonsoft.Json's JSonConvert.SerializeObject() Method as such:
public ActionResult GetChartData_All_Week()
{
var dataPointsList = this.myDataSource.GetMyDataPointList();
var convertedJson = JsonConvert.SerializeObject(dataPointsList, new JsonSerializerSettings()
{
//Not Needed, I just like to throw out any values that are null.
NullValueHandling = NullValueHandling.Ignore
});
return Content(convertedJson);
IMPORTANT We'll be using ajax in the next step, so we need the magical [Route] Attribute above this action result method as such:
Route("Index/Path/To/Post/To")]
public ActionResult GetChartData_All_Week()
All the hard stuff is done now. If you launch your App and visit the route you defined above (For me it is /Index/Charts/All/Week) You should see your JSON data there similar to this:
[["07/04/2020",25.5,44.0],["07/05/2020",25.600000381469727,45.0],["07/06/2020",25.5,44.0],...["07/08/2020",25.5,43.0]]
If You don't then this next part isn't going to work out. Always remember that it is a List of Lists we will need!
The .cshtml, AJAX, and jQuery magic
Most of your chart is already there. If It's working with the sample data as you posted, this will be super ez. inside your drawChart() method, you'll add the following before the data.AddRows() call.
var jsonData = $.ajax({
url:'Index/Path/To/Post/To',
dataType:"json",
async:false,
type:"GET"
}).responseText;
var asJson = JSON.parse(jsonData);
data.AddRows(asJson);
And now you should have it! The page and datasource will require a refresh to chart any new data that is added, but this should give you a dynamically sized list of points. The hardest part that I had was formatting my data as a List of Lists. I would recommend adding a CS List<object> ToList() method to whatever your equivalent to my Weather_Entry class is to put all of the important Data points into a list in order*. That makes it nice and easy to do something like:
public List<object> GetMyDataPointList(){
var myDataPointList = new List<MyDataPointType>();
myDataPointList = this.GetMyListOfDataPoints();
List<object> turnMeIntoJSON = new List<object>();
myDataPointList.ForEach(dp => turnMeIntoJSON.Add(dp.ToList));
return turnMeIntoJSON;
}
Best of Luck!

Google Script Services: Charts without UiApp [duplicate]

I'm new to Google Apps Script so am just exploring if what I want to achieve is possible.
From a Google form, I need to retrieve and display on a separate document the chart created from data on each individual form submission. I know this can be done.
The problem I have is that the chart type I want does not seem to be available here.
The chart needs to show a category and two values. This could be done with a bar chart, height is one value and colour the other value - this looks as though it might be possible but I am not sure if the colour of the whole bar can be changed.
An alternative is the bubble chart, X axis for category, Y axis for one value and size for the other value - but this type of chart does not seem to be supported.
You can display any of the 25+ chart types provided by the Google Visualization API within the Google Apps Script HTML Service.
Below is a modified version of the Bubble Chart example. Instead of fixed data, we'll pull data from a spreadsheet. The chart will be displayed in a modal dialog, as an add-on within that spreadsheet.
The source data:
A B C D E
ID Life Expectancy Fertility Rate Region Population
CAN 80.66 1.67 North America 33739900
DEU 79.84 1.36 Europe 81902307
DNK 78.6 1.84 Europe 5523095
EGY 72.73 2.78 Middle East 79716203
GBR 80.05 2 Europe 61801570
IRN 72.49 1.7 Middle East 73137148
IRQ 68.09 4.77 Middle East 31090763
ISR 81.55 2.96 Middle East 7485600
RUS 68.6 1.54 Europe 141850000
USA 78.09 2.05 North America 307007000
Client Side
The rest of the design is pretty straight-forward, but for Apps Script programmers who aren't used to javascript use in the HTML service, especially the behaviour of asynchronous function calls & call-backs, it's what's happening in the client side code that's most interesting. Here's the basic flow.
Present html page with a placeholder for the visualization.
Load external JavaScript libraries. We'll be using jQuery (for easy manipulation of DOM) and of course Google's JavaScript API, aka jsapi, for the visualization objects.
When the page loads, request a callback. We'll call that sendQuery(), as it will retrieve our spreadsheet data. This is a different approach than the original example that simply displayed a chart, because we're not just using hard-coded data.
When the jsapi finishes loading, sendQuery() is called. It requests our data, and passes the asynchronous response to another callback, drawSeriesChart().
Once data is received by drawSeriesChart(), draw the chart.
Options for retrieving data from spreadsheet
Since our visualization will be run in a browser (aka client-side), we need to get the info from the spreadsheet (aka server-side). Depending upon your specific needs, there are a few ways to retrieve that data.
Query via visualization API.
For a published spreadsheet, this is a very flexible way to retrieve data. Your client-side js can specify the range of data you're interested in, and you can utilize the Query Language to manipulate the data you'll display without modifying the source spreadsheet.
function sendQuery() {
var opts = {sendMethod: 'auto'};
var sheetId = "--- your sheet ID ---";
var dataSourceUrl = 'https://spreadsheets.google.com/tq?key=%KEY%&pub=1'
.replace("%KEY%",sheetId);
var query = new google.visualization.Query(dataSourceUrl, opts);
// Specify query string, if desired.
// Send the query with a callback function.
query.send(drawSeriesChart);
}
Handy for situations where you don't own the source data, for example
Create a web service that will feed the spreadsheet data. This approach keeps the spreadsheet itself private.
Use direct communication between the server & client side scripts, via google.script.run. This way, the spreadsheet remains private. This example is very simple, as it gleans the entire spreadsheet, but you could extend it to manipulate your data by filtering, sorting, or adding further metadata for formatting.
function sendQuery() {
// Send the query with a callback function.
google.script.run
.withSuccessHandler(drawSeriesChart)
.getSpreadsheetData();
}
This requires that function getSpreadsheetData() be implemented on the server side to return the desired data. That's shown in the actual code that follows.
Code.gs
Other than the usual yada-yada for menu creation, this file implements a getSpreadsheetData() function that we'll use to retrieve all the data from a sheet.
/**
* Adds a custom menu with items to show the sidebar and dialog.
*
* #param {Object} e The event parameter for a simple onOpen trigger.
*/
function onOpen(e) {
SpreadsheetApp.getUi()
.createAddonMenu()
.addItem('Bubble Chart Example', 'showBubbleEx')
.addToUi();
}
/**
* Runs when the add-on is installed; calls onOpen() to ensure menu creation and
* any other initializion work is done immediately.
*
* #param {Object} e The event parameter for a simple onInstall trigger.
*/
function onInstall(e) {
onOpen(e);
}
/**
* Opens a dialog for a visualization.
*/
function showBubbleEx() {
var ui = HtmlService.createTemplateFromFile('BubbleEx')
.evaluate()
.setSandboxMode(HtmlService.SandboxMode.IFRAME)
.setWidth(450)
.setHeight(350);
SpreadsheetApp.getUi().showModalDialog(ui, "Bubble Chart Example");
}
/**
* Return all data from first spreadsheet as an array. Can be used
* via google.script.run to get data without requiring publication
* of spreadsheet.
*
* Returns null if spreadsheet does not contain more than one row.
*/
function getSpreadsheetData() {
var data = SpreadsheetApp.getActive().getSheets()[0].getDataRange().getValues();
return (data.length > 1) ? data : null;
}
BubbleEx.html
This was adapted from the "Sheets add-on" template, and refers to the Stylesheet.html file included there.
<!-- Use a templated HTML printing scriptlet to import common stylesheet. -->
<?!= HtmlService.createHtmlOutputFromFile('Stylesheet').getContent(); ?>
<!-- Below is the HTML code that defines the dialog element structure. -->
<div>
<div id="series_chart_div" style="width: 400px; height: 300px;"></div>
<div class="block" id="dialog-button-bar">
<button id="dialog-cancel-button" onclick="google.script.host.close()">Cancel</button>
</div>
</div>
<!-- Use a templated HTML printing scriptlet to import JavaScript. -->
<?!= HtmlService.createHtmlOutputFromFile('BubbleExJavaScript').getContent(); ?>
BubbleExJavaScript.html
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script>
// Load the Visualization API and desired package(s).
google.load('visualization', '1.0', {'packages':['corechart']});
/**
* Run initializations on dialog load.
*/
$(function() {
// Set a callback to run when the Google Visualization API is loaded.
google.setOnLoadCallback(sendQuery);
// Assign handler functions to dialog elements here, if needed.
// Call the server here to retrieve any information needed to build
// the dialog, if necessary.
});
/**
* Issue asynchronous request for spreadsheet data.
*/
function sendQuery() {
google.script.run
.withSuccessHandler(drawSeriesChart)
.getSpreadsheetData();
}
/**
* Callback function to generate visualization using data in response parameter.
*/
function drawSeriesChart(response) {
if (response == null) {
alert('Error: Invalid source data.')
return;
}
else {
var data = google.visualization.arrayToDataTable(response,false);
var options = {
title: 'Correlation between life expectancy, fertility rate and population of some world countries (2010)',
hAxis: {title: data.getColumnLabel(1)}, // 'Life Expectancy'
vAxis: {title: data.getColumnLabel(2)}, // 'Fertility Rate'
bubble: {textStyle: {fontSize: 11}}
};
var chart = new google.visualization.BubbleChart(document.getElementById('series_chart_div'));
chart.draw(data, options);
}
}
</script>

Breeze EntityManager.executeQuery with expand - httpResponse data does not match result data?

I'm working on a web app that uses Breeze and Knockout. I have the following function:
function getArticle(id, articleObservable) {
var query = EntityQuery.from('KbArticles')
.where("articleId", "==", id)
.expand("KbArticleType, KbSubject, KbArticleTags");
return manager.executeQuery(query)
.then(querySucceeded)
.fail(queryFailed);
function querySucceeded(data) {
if (articleObservable) {
articleObservable(data.results[0]);
}
log('Retrieved [Article] from remote data source', data.results.length, true);
}
}
A 1 to many relationship exists between the KbArticles entity and the KbArticleTags entity. The goal of this function is to fetch a specific article and the list of tags associated with the article. The function executes successfully (and I DO get data for the other 2 expanded entities - they are 1 to 1), however, I get an empty array for the KbArticleTags in data.results. Interestingly, the tags are populated in data.httpResponse:
So, it appears that the data is coming over the wire, but it's not making it to the results in the querySucceeded function. I tried to step through the breeze code to determine how the httpResponse is mapped to the result, but got lost fairly quickly (I'm a javascript newb). Does anyone have any troubleshooting tips for figuring out why the expanded entity doesn't show in the results, but is returned in the httpResponse? Or am I trying to do something that isn't supported?
Ok, so for whatever reason (I probably deleted it one day while testing and didn't add it back), the navigation property (in my Entity Framework diagram) was missing on the KbArticleTag entity:
All I had to do was add that back and everything is working as expected.

Using Shield Chart in ASP.NET MVC to bind to web service data

For a new project I'm working on, I am considering using Shield Chart for ASP.NET MVC to display some user stats. I have successfully rendered a shield javascript chart from my razor view using the Html.ShieldChart() wrapper methods. The actual data for the chart is coming from a local rest service in JSON format. The thing is, I can't quite manage to make the chart display the JSON data. The Shield UI demos show one approach for binding the MVC chart to remote web service, but my scenario is quite different.
In our web portal, we have implemented a REST service under url /api/users/12652/stats that will return some JSON stats for a user with the given ID. The responsone contains the sessions property that lists the user's sessions for the current month:
{
sessions: [{ start: 1379624400000, end: 1377023690271 }, { ... }]
}
The difference between start and end times gives the duration of the session.I need to display a bar chart that will show the duration of all sessions in a line on the Y axis, while the X axis will contain all session dates (taken from the start value).
Something like this should get you going:
<div id="chart"></div>
<script type="text/javascript">
$(function () {
$.get("/api/users/12652/stats", function (data) {
var sessions = sessions;
#(Html.ShieldChart()
.Name("chart")
.PrimaryHeader(header => header.Text("User session duration (in minutes)"))
.DataSeries(series => series.Bar()
.Data(#<text>
(function () {
return $.map(sessions, function (item) {
//return the difference between the end and start time in minutes
return (item.end - item.start) / 1000 / 60;
});
})()
</text>))
.GetScript())
});
});
</script>
Note how the Shield Chart is defined using a Razor server expression inside the javascript callback from the service request. We do this, because we need the session variable to contain the actual data returned from the service. Then we can use a self-calling function in a <text></text> template as a parameter to the series' .Data() method in MVC.This has the effect of rendering a self-calling function expression in the javascript initialization options that helps us map the service response to series data options.
Note the last .GetScript() method call. We use it to render only the initialization script of the chart widget and not the entire widget markup and scripts. This allows the widget to be initialized in javascript code in your HTML page.
For binding the X axis categorical values to the service response, however, you do not have a similar approach with the #<text></text> template available. For this case, it is best to use pure javascript initialization:
$(function() {
$("#chart").shieldChart({
primaryHeader: {
text: "User session duration (in minutes)"
},
dataSeries: [{
seriesType: 'bar',
data: $.map(sessions, function(item) {
return (item.end - item.start) / 1000 / 60;
})
}],
axisX: {
axisType: "datetime",
dataStart: sessions[0].start,
categoricalValues: $.map(sessions, function(item) {
return new Date(item.start);
})
}
});
});
Here is a JSBin of the above scenario with some hard-coded data just to concentrate on the chart initialization.

Categories

Resources