How to find min and max of multiple y-axes in FLOT - flot

I am using FLOT to plot charts, and I am not providing max or min value for Y-axis. It is getting auto-scaled. Now I want to get the min and max value of Y-axes. The following code works for only the first y-axis, but I want it for multiple axes.
var min = plot.getAxes().yaxis.min;

Loop through the yaxes array in the options:
var yaxes = plot.getOptions().yaxes;
var min = yaxes[0].min;
var max = yaxes[0].max;
for (var i = 1; i < yaxes.length; i++) {
if (yaxes[i].min < min) {
min = yaxes[i].min;
}
if (yaxes[i].max > max) {
max = yaxes[i].max;
}
}

Related

Color interpolation with a set of 2D points

I am trying to modelize a physical problem of photoelasticity on a surface. I succeed to get an array of X,Y - coordinates of the surface and for each points I have a corresponding color in a RGB format. I used Python scatter to plot and the result is already great but there is still some discontinuities because of the lack of resolution that I can not improve :( I just wanted to ask how I can generate the same surface plot in a continuous way (with new "in-between" points for which the color of them have been interpolated with respect to the neighborhood points). I am not necessarily looking for coding it in python, every software is welcome. Thanks!
I wrote this in javascript: https://jsfiddle.net/87nw05kz/
The important part is calculateColor. It finds the inverse square of the distance to each color from the pixel being shaded and it uses that to decide how much that pixel should be effected by each color.
function calculateColor(x, y) {
let total = 0;
for (let i = 0; i < colors.length; i++) {
let c = colors[i];
let d = distance(c.x, c.y, x, y);
if (d === 0) {
return c;
}
d = 1 / (d * d);
c.d = d;
total += d;
}
let r = 0, g = 0, b = 0;
for (let i = 0; i < colors.length; i++) {
let c = colors[i];
let ratio = c.d / total;
r += ratio * c.r;
g += ratio * c.g;
b += ratio * c.b;
}
r = Math.floor(r);
g = Math.floor(g);
b = Math.floor(b);
return {r:r,g:g,b:b};
}

Creating a Bubble Chart of text columns

I have two text columns which look like this:
and now I need to make a bubble chart that looks like this:
Any idea how I can achieve this using excel 2016?
There is a way to do this by using Javascript. This langage has a lot of powerful libraries for data visualization and data processing. And there is a way to use it in Excel by using an Excel Add-in called funfun.
I have written a working code for you:
https://www.funfun.io/1/#/edit/5a7c4d5db8b2864030f9de15
I used an online editor with an embedded spreadsheet to build this chart. I use a Json file(short/full underneath Settings) to get the data from the spreadsheet to my javascript code:
{
"data": "=A1:B18"
}
I then store it in local variables in the script.js so I can use them correctly in the chart I will create:
var Approaches = []; // list of Approaches
var Contribution = []; // list of contribution
var tmpC = [];
/*
* Parse your spreadsheet to count how much approaches and contribution there are
*/
for (var x = 1; x < $internal.data.length; x++) {
if (Approaches.indexOf($internal.data[x][0]) <= -1)
Approaches.push($internal.data[x][0]);
if (tmpC.indexOf($internal.data[x][1]) <= -1)
tmpC.push($internal.data[x][1]);
}
/*
* sort the array so that other is at the end
* (remove if you want you don't care about the order, replace 'tmpC' by 'Contribution' above)
*/
for (var t = tmpC.length - 1; t >= 0; t--)
Contribution.push(tmpC[t]);
var techniquesIndex = new Array(Contribution.length); // how much of one contribution is made per approach
var total = 0; // total of contribution
var totalPerApproaches = new Array(Approaches.length); //total of contributions for one Approach
for (var z = 0; z < totalPerApproaches.length; z++) {
totalPerApproaches[z] = 0;
}
var data = []; // data for the chart
/*
* Parse your every approach
*/
for (var x = 0; x < Approaches.length; x++) {
for (var z = 0; z < techniquesIndex.length; z++) {
techniquesIndex[z] = 0;
}
/*
* Parse your spreadsheet to count the number of contribution in this approach
*/
for (var y = 0; y < $internal.data.length; y++) {
if (Approaches.indexOf($internal.data[y][0]) == x) {
total += 1;
techniquesIndex[Contribution.indexOf($internal.data[y][1])] += 1;
}
}
for (var c = 0; c < Contribution.length; c++) {
/*
* calculate the total of contribution on this approach
*/
totalPerApproaches[x] += techniquesIndex[c];
/*
* removes the values equals to zero off the chart
* (remove this condition if you want to show the zeros)
*/
if (techniquesIndex[c] == 0)
continue;
/*
* adds a bubble to the charts with the number of Contribution per Approach
*/
data.push(
{
x: x, // -> index of array Approach[x]
y: c, // -> index of array Contribution[c]
z: techniquesIndex[c], // number of contribution[c] in Approach[x]
name: techniquesIndex[c] // ..
});
}
}
The $Internal.data is the data from the spreadsheet accessible thanks to the Json file. The array data (at the end) will be used to create all the bubbles of the charts.
Once I have my data stored in the right format I create the chart in index.html using a data visualization library called Highcharts, it has lots of examples and good documentation for beginners. You can choose to add many options for your chart and at the end you pass your data to the chart as such:
series: [{
data: data // use the data from script.js
}]
Once you've build your chart you can open it in Excel by pasting the URL in the Funfun excel add-in. Here is how it looks like with my example:
You can as much lines as you want you just need to make sure that the range of data in the Json file is what you need.
you can then save the chart in many formats:
Hope this helps !
Disclosure : I’m a developer of funfun

How can I replace automatically-generated grand total values with different ones (Aspose Cells)?

My spreadsheet automatically generates a "Grand Totals" column as the rightmost column:
This is nice, in general. But in specific, I've got a couple of problems with it: The last two values (with the unfortunate labels "Sum of Avg Price" and "Sum of Percentage") provide just that - a sum of the previous columns. In those cases, I don't want a simple sum, but an average in the first case and a percentage in the second case.
For the AvgPrice, what I need is a calculation of "Sum of Total Price" / "Sum of Total Quty" in the Grand Total column. For instance, the first AvgPrice Grand Total value should be "33.14" rather than "66.26"
For the Percentage, I need the percentage of Total Price for the item/Description (such as "25151.75" seen in the first item above) as compared to the "Total Price" value in the "Total Sum of Total Price" grand total row/column ("1529802.82"). That value is seen here:
So the "Percentage" value for that first item ("ASPARAGUS, LARGE 11/1#") should be approximately 1.6 (as 25151.75 is about 1/60th of 1529802.82), rather than 1.36.
Is there a way to set this up to automatically generate those values in the Grand Total Column, or do I need to prevent the Grand Total column from being generated like so:
pivotTable.ColumnGrand = false;
...and then add that column to the sheet manually, doing the calculations in code, and adding those values that way?
In order to look into this issue in detail, please post your query in Aspose.Cells forum with your sample excel files. You can provide us source excel file, actual output excel file and the expected excel file and sample code. And the screenshot like you provided will also be helpful. Thanks for your cooperation in this regard.
Aspose.Cells Forum Link:
https://www.aspose.com/community/forums/aspose.cells-product-family/19/showforum.aspx
Note: I am working as Developer Evangelist at Aspose
It's easiest, I think, to just add that column manually, calculating the necessary values; here's how I'm doing it now (basically the same idea as in Excel Interop - manually adding the Grand Total column):
After the PivotTable code, I call AddManualGrandTotalColumn(), which is:
private void AddManualGrandTotalColumn()
{
var pivot = pivotTableSheet.PivotTables[0];
var dataBodyRange = pivot.DataBodyRange;
int rowsUsed = dataBodyRange.EndRow;
int FIRST_DATA_ROW = 7;
int currentQtyRow = FIRST_DATA_ROW;
int ROWS_IN_A_RANGE = 4;
// Needed?
pivot.RefreshData();
pivot.CalculateData();
// Get Total Sales value, which will be needed for computing the % val
Cell totalTotalPurchasesCell = pivotTableSheet.Cells[rowsUsed - 2, _grandTotalsColumnPivotTable + 1];
decimal totalTotalPurchases = Convert.ToDecimal(totalTotalPurchasesCell.Value);
Cell gtLabelCell = pivotTableSheet.Cells[6, _grandTotalsColumnPivotTable + 2];
gtLabelCell.Value = "Grand Total";
Cell QtyCell = null;
Cell PriceCell = null;
Cell AvgPriceCell = null;
Cell PercentageCell = null;
while (currentQtyRow < rowsUsed)
{
// SumTotalQty
int qty = GetSumTotalQty(currentQtyRow);
QtyCell = pivotTableSheet.Cells[currentQtyRow, _grandTotalsColumnPivotTable + 2];
QtyCell.Value = qty;
// SumTotalPrice
decimal price = GetSumTotalPrice(currentQtyRow+1);
PriceCell = pivotTableSheet.Cells[currentQtyRow+1, _grandTotalsColumnPivotTable + 2];
PriceCell.Value = price;
// Calculate Avg Price (SumTotalPrice / SumTotalQty)
decimal avg = 0.0M;
if ((price > 0) && (qty > 0))
{
avg = price / qty;
}
AvgPriceCell = pivotTableSheet.Cells[currentQtyRow+2, _grandTotalsColumnPivotTable + 2];
AvgPriceCell.Value = avg;
// Calculate Percentage (totalTotalPurchases / SumTotalPrice?)
decimal prcntg = 0.0M;
if ((totalTotalPurchases > 0) && (price > 0)) // ? Right calculation?
{
prcntg = totalTotalPurchases / price;
}
PercentageCell = pivotTableSheet.Cells[currentQtyRow+3, _grandTotalsColumnPivotTable + 2];
PercentageCell.Value = prcntg;
currentQtyRow = currentQtyRow + ROWS_IN_A_RANGE;
}
}
private int GetSumTotalQty(int currentQtyRow)
{
int FIRST_MONTH_COL = 2;
int LAST_MONTH_COL = _grandTotalsColumnPivotTable; // - 1;
int cumulativeQty = 0;
Cell qtyCell = null;
for (int i = FIRST_MONTH_COL; i <= LAST_MONTH_COL; i++)
{
qtyCell = pivotTableSheet.Cells[currentQtyRow, i];
cumulativeQty = cumulativeQty + Convert.ToInt32(qtyCell.Value);
}
return cumulativeQty;
}
. . . (etc. for GetSumTotalPrice())

Read inner and outer radius of arc - d3.js

I'm working on a project which deals with visual representation of large relational data. We are using pie chart to display the data components(In order). Due to lack of space we are displaying only 10 at a time.
Consider the following example:
Assume that I have 100 data components, out of which I'll display only 10 at a given point of time. The logic i'm using is, I'm setting start and end angle to 0(Zero) for other 90 components. Where in for those 10 components i'm calculation the start and end angle as below-
var angle = 360;
var count = 10;
if(data.length > count) angle = angle/count; //data is array of data component names
else angle = angle/data.length;
//Initially I'll be displaying first ten components
for(var i=0; i<data.length; i++){
var startAngle = i * angle;
var endAngle = startAngle + angle;
var pi = = Math.PI/180;
var arc = d3.svg.arc()
.innerRadius(innerRadius) //dynamic value, calculated based on available space
.outerRadius(outerRadius) //dynamic value, calculated based on available space
.startAngle((startAngle)*pi)
.endAngle((endAngle)*pi);
//Hiding rest of the data components
if(i >= count){
arc.startAngle(0);
arc.endAngle(0);
}
arcGroup.append("path")
.attr("d", arc)
.attr("stroke", "#2E2E2E")
.attr("stroke-width", "1")
.attr("fill","gold");
var text = arcGroup.append("text")
.attr("transform", "translate(" + arc.centroid() + ")")
.attr("text-anchor", "middle")
.attr("font-family","noto_sansregular")
.attr("font-size", 40)
.attr("font-weight","Bold")
.attr("fill", "#000000")
.attr("y",0)
.style("visibility", "visible")
.text(data[i]);
//Hiding text of hidden arcs
if(i >= count) text.style("visibility", "hidden");
}
Then if user wants to see the rest of the components, i'm providing two buttons to rotate (clock or anti-clock) the content.
If current view is -> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
On rotate by one cell clockwise, resulting view should be -> 100, 1, 2, 3, 4, 5, 6, 7, 8, 9
In this case I need to hide component '10' and display component '100', and shift rest of the cells. To achieve this i just need to change the start and end angles of the arcs. I can create new arc object with calculated angles.
The problem here is I don't know how to get the inner and outer radius of the arc, which are dynamically created.
Just like that,
...
arcGroup.append("path")
.filter(function(d) {
// You're Not restricted to the "filter" function
var innerRadius = d.innerRadius()(d);
var outerRadius = d.outerRadius()(d);
})
.attr("d", arc)
...
Technically, it is possible to retrieve the innerRadius and outerRadius from the d attribute of the path elements, but it will require parsing the DSL and will be tedious. These values are not stored nicely on the elements itself by d3.
Hence, it would be better if you recompute the innerRadius and outerRadius while updating the elements:
function showFromIdx(firstIndex) {
argGroup.selectAll('path')
.data( d3.range(data.length)
.map(function (d) {
return (d - firstIndex + data.length) % data.length;
})
)
.attr('d', function (d) {
// You will have to calculate the radii again here.
var innerRadius = foo(d), outerRadius = bar(d);
return d3.svg.arc()
.startAngle(i < count ? i * angle : 0)
.endAngle(i < count ? (i + 1) * angle : 0)
.innerRadius(innerRadius)
.outerRadius(outerRadius)(d);
});
}
Here are several functions that I wrote to get inner and outer radiuses of arcs created using d3. Please tell me if you find mistakes in code.
function getInnerRadiusFromArc(arc) {
var numbersInPattern = _getArcNumbers(arc);
// Possibly, that's sector, so it starts from 0.
// Or maybe that's something else.
if (numbersInPattern.length < 4) {
return 0;
}
// Getting minimum from the array.
var innerRadius = Math.min.apply(null, numbersInPattern);
return innerRadius;
}
function getOuterRadiusFromArc(arc) {
var numbersInPattern = _getArcNumbers(arc);
// Getting maximum from the array.
var outerRadius = Math.max.apply(null, numbersInPattern);
return outerRadius;
}
function _getArcNumbers(arc) {
// Path description parameter, containing necessary data.
var pathDescription = arc.getAttribute("d");
// We need to get all patterns like A<number>,<number>.
// RegExp source:
// http://www.regular-expressions.info/floatingpoint.html
const numberRegExp = /[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/g;
var arcPattern = new RegExp("A" + numberRegExp.source + "," + numberRegExp.source, "g");
var arcParameters = pathDescription.match(arcPattern);
var numbersInPattern = [];
// We get all the numbers from array ["A<number>,<number>", "A<number>,<number>", ...].
for (let parameterIndex = 0; parameterIndex < arcParameters.length; parameterIndex++) {
let parameter = arcParameters[parameterIndex];
let numbers = parameter.match(numberRegExp);
if (numbers !== null) {
numbersInPattern = numbersInPattern.concat(numbers);
}
}
// Transform strings in our array to numbers.
numbersInPattern = numbersInPattern.map(function (numberString) {
return parseFloat(numberString);
});
return numbersInPattern;
}

How to draw SVG lines inside HighCharts barcharts?

I have a grouped bar chart just like in http://www.highcharts.com/demo/column-basic. I would like to draw horizontal lines with averages for each group (for example, historical world avg rainfall in Jan, Feb etc?) Is there a easy way to do it ? Ofcourse, each group would have different horizontal lines - but I couldn't figure out if there is a way to get handle to individual bars and do SVG lines or any other way. Much appreciate any pointers.
You can use loop to calculate average in each group and then translate position. Obviously you should need also information about tick width.
http://jsfiddle.net/rfwd9/2/
var i = 0,
avg,
yAxis = chart.yAxis[0],
r = chart.renderer,
tickWidth = chart.plotWidth / chart.series[0].data.length,
startX = chart.plotLeft,
len = chart.series[0].data.length,
seriesCount = chart.series.length;
for (i = 0; i < len; i++) {
avg = 0;
$.each(chart.series, function (j, serie) {
avg += serie.data[i].y;
});
avg = Math.floor(avg / seriesCount);
r.path(['M', startX, chart.plotHeight - yAxis.translate(avg), 'L', startX + tickWidth, chart.plotHeight - yAxis.translate(avg)])
.attr({
'stroke-width': 2,
stroke: 'red'
})
.add();
startX = startX + tickWidth;
}

Resources