Having a hard time understanding why some objects won't return properly:
If I run console.log(obj.R) it returns "different", as expected. If I run console.log(obj.g) it just returns undefined. My goal is to return the first value of the g object, so something like console.log(obj.g[0]) and have the value "0.04600" returned.
Full function as requested:
function buildCandleStickChart_() {
CurrencyDataService.getChartData('BTC', vm_.selectedMarket).
then(function(data) {
// Set a default theme for the entire chart.
anychart.theme({
'defaultFontSettings': {
'fontSize': 12,
'fontFamily': 'Roboto'
}
});
var table = anychart.data.table();
// Map API data to table data.
dataArray = data.response.map(function(obj) {
// Format Date
var formatedDate = moment(obj.time * 1000).format('M-D HH:mm');
return [formatedDate, obj.open, obj.high, obj.low, obj.close, obj.volumeto];
});
// Add API data to table.
table.addData(dataArray);
// Map data to candlesticks.
var mapping = table.mapAs();
mapping.addField('open', 1, 'first');
mapping.addField('high', 2, 'max');
mapping.addField('low', 3, 'min');
mapping.addField('close', 4, 'last');
// Map data to volume bars.
var volMapping = table.mapAs();
volMapping.addField('value', 5);
// Get current lowest price.
var getLowestValue = _.minBy(data.response, 'low');
lowestLow = getLowestValue.low;
// Get current highest price.
var getHighestValue = _.maxBy(data.response, 'high');
highestHigh = getHighestValue.high;
// Scale down the volume bars.
var getHighestVolume = _.maxBy(data.response, 'volumeto');
var highestVolume = getHighestVolume.volumeto;
var getLowestVolume = _.minBy(data.response, 'volumeto');
var lowestVolume = getLowestVolume.volumeto;
// Initialize the chart.
var chart = anychart.stock();
candleStickChartRef = chart;
candleStickPlotRef = chart.plot(0);
// Initialize the candlesticks.
var candleSticks = chart.plot(0).candlestick(mapping);
candleSticks.name(vm_.selectedMarket);
// Toggle chart tooltip
chart.tooltip(false);
// Chart Padding
var padding = chart.padding();
padding.bottom(0);
padding.left(0);
padding.right(88);
padding.top(0);
// Chart Margins
var margin = chart.margin();
margin.bottom(-1);
margin.left(0);
margin.top(-1);
margin.right(0);
// Create custom date time scale.
var dateTimeScale = anychart.scales.dateTime();
var dateTimeTicks = dateTimeScale.ticks();
dateTimeTicks.interval(0, 0, 0, 1);
// Style the X-Axis.
var xAxis = chart.plot(0).xAxis();
xAxis.background('#FFFFFF');
xAxis.height(24);
xAxis.enabled(true);
// Adjust axis labels.
var labels = xAxis.labels();
labels.format(function(value) {
var date = new Date(value.tickValue);
var formattedDate = moment(date).format('MMM DD, HH:mm');
return formattedDate;
});
labels.width(118);
// Apply date time scale.
var scale = chart.xScale();
scale.ticks([{major: {unit: 'minute', count: 15}, minor: {unit: 'second', count: 1}}]);
// Declare the Y-Axis scale.
var yScale = chart.plot(0).yScale();
// Set the position of the Y-Axis values.
var yAxis = chart.plot(0).yAxis(0);
yAxis.orientation('right');
yAxis.drawFirstLabel(true);
yAxis.drawLastLabel(false);
// Set the position of the Y-Axis labels.
var yLabels = chart.plot(0).yAxis().labels();
yLabels.offsetX(0);
yLabels.format(function() {
return this.value.toFixed(vm_.currencySettings[vm_.selectedMarket].decimal);
});
console.log(chart.plot(0).yAxis().labels());
// Horizontal Grid Lines.
chart.plot(0).yGrid().enabled(true);
chart.plot(0).yGrid().stroke('#ced4da', 1);
// Enable current price indicator.
var indicator = chart.plot(0).priceIndicator();
// Set line settings.
indicator.value('last-visible');
indicator.fallingStroke('#ff6b6b');
indicator.fallingLabel({background: '#ff6b6b'});
indicator.risingStroke('#20c997');
indicator.risingLabel({background: '#20c997'});
indicator.label().fontColor('White');
indicator.label().fontFamily('Roboto');
// Initialize the volume bars.
var volumeBars = chart.plot(0);
var volume = volumeBars.column(volMapping).name('Volume');
volume.zIndex(1);
// Create and tune Y-Scale for volume bars.
var extraYScale = anychart.scales.linear();
extraYScale.maximum(highestVolume + (highestVolume * 4));
extraYScale.minimum(lowestVolume);
volume.yScale(extraYScale);
// Enable Legend.
var legend = chart.plot(0).legend();
legend.enabled(false);
// Set legend position.
legend.positionMode('inside');
// Style legend.
legend.position('top');
legend.align('left');
legend.background().enabled(true);
legend.background().fill('#fff', 0.87);
legend.background().stroke('#ced4da', 1);
legend.padding(8);
legend.margin(8);
legend.drag(true);
// Set listener on the chart container.
document.getElementById('chart-left').onclick = function(event) {
mouseHoverHandler_(event);
};
// Event handler to get Y-Axis value on click.
function mouseHoverHandler_(event) {
// X click coordinate on plot.
var y = event.offsetY;
// Plot bounds related to chart container.
var plotHeight = chart.plot(0).yAxis().getPixelBounds().height;
// Plot left margin
var plotTopoffset = chart.plot(0).yAxis().getPixelBounds().top;
// Click on data area.
if (y < plotTopoffset || y > plotTopoffset + plotHeight) {
return;
}
// Get value of click related to yScale.
var ratio = (y - plotTopoffset) / plotHeight;
var value = (yScale.inverseTransform(1 - ratio)).toFixed(8);
// Setting this value triggers watch which will build line.
vm_.chartSelectedSwapRate = parseFloat(value);
}
// Customize the crosshair and yLabel.
chart.crosshair(true);
chart.crosshair().xLabel(false);
chart.crosshair().yLabel().format(function() {
return Number(this.value).toFixed(8);
});
chart.crosshair().xStroke(null);
chart.crosshair().yStroke('#212529', 1);
chart.crosshair().yLabel().fontColor('#fff');
chart.crosshair().yLabel().fontSize(12);
chart.crosshair().yLabel().padding(2);
chart.crosshair().yLabel().hAlign('center');
chart.crosshair().yLabel().width(78);
chart.crosshair().yLabel().fontFamily('Roboto');
chart.crosshair().yLabel().background({
fill: '#212529',
stroke: '#212529'
});
// Toggle the timeline scroller.
chart.scroller().enabled(false);
// Configure the visual settings of the falling candlesticks.
candleSticks.fallingFill('#ff6b6b');
candleSticks.fallingStroke('#ff6b6b', 1, '0', 'round');
// Configure the visual settings of the rising candlesticks.
candleSticks.risingFill('#20c997');
candleSticks.risingStroke('#20c997', 1, '0', 'round');
// Configure the visual settings of the volume bars.
volume.normal().fill('#e9ecef');
// Set the width of candlesticks and volume bars.
chart.plot(0).pointWidth(6);
// Toggle the default contextual menu.
chart.contextMenu(false);
// Enable the custom contextual menu.
// var customContextMenu = anychart.ui.contextMenu();
// Build the custom contextual menu.
// (TODO)jberthelot: Connect these menu actions with the Go Long and Go Short sidebar
// functions.
// customContextMenu.attach(chart);
// customContextMenu.itemsFormatter(function(items) {
// items = {
// 'menu-item-1': {
// 'text': 'Create a Long Cryptoswap',
// 'action': function() {
// alert('You are going Long!');
// }
// },
// 'menu-item-2': {
// 'text': 'Create a Short Cryptoswap',
// 'action': function() {
// alert('You are going Short!');
// }
// }
// };
// return items;
// });
// Add a custom class name to the contextual menu for easier styling.
// customContextMenu.addClassName('custom-context-menu');
// Set the candlestick chart container element.
chart.container('chart-left');
// Initiate the candlestick chart display.
if (vm_.chart) {
vm_.chart.dispose();
}
vm_.chart = chart;
chart.draw();
});
}
Related
I need to perform a PCA per image over a image collection. Then, I want to only keep Principle component axis 1, and add this as a band to every image within my image collection. Ultimately, I want to export a .csv file with GPS sampling locations at row headers and image ID as column headers with mean Principle component axis 1 as values. The idea behind doing this, is that I want a proxy (spectral heterogeneity) to use in further statistical analysis in R.
Here is the code I have thus far:
//Create an test image to extract information to be used during PCA
var testImage =ee.Image('LANDSAT/LC08/C01/T1_SR/LC08_168080_20130407')
.select(['B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['Blue', 'Green', 'Red', 'NIR', 'SWIR1', 'SWIR2']);
// Define variables for PCA
var region = Extent;
var scale = testImage.projection().nominalScale();
var bandNames = testImage.bandNames();
Map.centerObject(region);
// Function for performing PCA
function doPCA(image){
// This code is from https://code.earthengine.google.com/7249153a8a0f5c79eaf562ed45a7adad
var meanDict = image.reduceRegion({
reducer: ee.Reducer.mean(),
geometry: region,
scale: scale,
maxPixels: 1e9
});
var means = ee.Image.constant(meanDict.values(bandNames));
var centered = image.subtract(means);
// This helper function returns a list of new band names.
var getNewBandNames = function(prefix) {
var seq = ee.List.sequence(1, bandNames.length());
return seq.map(function(b) {
return ee.String(prefix).cat(ee.Number(b).int());
});
};
// [START principal_components]
var getPrincipalComponents = function(centered, scale, region) {
var arrays = centered.toArray();
var covar = arrays.reduceRegion({
reducer: ee.Reducer.centeredCovariance(),
geometry: region,
scale: scale,
maxPixels: 1e9
});
var covarArray = ee.Array(covar.get('array'));
var eigens = covarArray.eigen();
var eigenValues = eigens.slice(1, 0, 1);
var eigenVectors = eigens.slice(1, 1);
var arrayImage = arrays.toArray(1);
var principalComponents = ee.Image(eigenVectors).matrixMultiply(arrayImage);
var sdImage = ee.Image(eigenValues.sqrt())
.arrayProject([0]).arrayFlatten([getNewBandNames('sd')]);
return principalComponents
.arrayProject([0])
.arrayFlatten([getNewBandNames('pc')])
.divide(sdImage);
};
var pcImage = getPrincipalComponents(centered, scale, region);
return (pcImage);
}
// map PCA function over collection
var PCA = LandsatCol.map(function(image){return doPCA(image)});
print('pca', PCA);
Extent is my ROI, whereas LandsatCol is a preproccessed image collection. The code here produces an Error when trying to map the PCA over the image collection (second last line of code). The error reads: "Array: Parameter 'values' is required".
Any suggestions on how to deal with this? And how to add Principle component axis 1 as a band per image over the image collection?
I figured it out. The error "Array: Parameter 'values' is required" had to do with sparse matrices, which was a product of filtering, clipping and spesifying regions within to perform PCA. Earth Engine can not work with sparse matrices.
Here is the working code. LandsatCol is my preproccessed image collection.
// Display AOI
var point = ee.Geometry.Point([30.2261, -29.458])
Map.centerObject(point,10);
// Prepairing imagery for PCA
var Preped = LandsatCol.map(function(image){
var orig = image;
var region = image.geometry();
var scale = 30;
var bandNames = ['Blue', 'Green', 'Red', 'NIR', 'SWIR1', 'SWIR2'];
var meanDict = image.reduceRegion({
reducer: ee.Reducer.mean(),
geometry: region,
scale: scale,
maxPixels: 1e9
});
var means = ee.Image.constant(meanDict.values(bandNames));
var centered = image.subtract(means);
var getNewBandNames = function(prefix) {
var seq = ee.List.sequence(1, 6);
return seq.map(function(b) {
return ee.String(prefix).cat(ee.Number(b).int());
});
};
// PCA function
var getPrincipalComponents = function(centered, scale, region) {
var arrays = centered.toArray();
var covar = arrays.reduceRegion({
reducer: ee.Reducer.centeredCovariance(),
geometry: region,
scale: scale,
maxPixels: 1e9
});
var covarArray = ee.Array(covar.get('array'));
var eigens = covarArray.eigen();
var eigenValues = eigens.slice(1, 0, 1);
var eigenVectors = eigens.slice(1, 1);
var arrayImage = arrays.toArray(1);
var principalComponents = ee.Image(eigenVectors).matrixMultiply(arrayImage);
var sdImage = ee.Image(eigenValues.sqrt())
.arrayProject([0]).arrayFlatten([getNewBandNames('sd')]);
return principalComponents.arrayProject([0])
.arrayFlatten([getNewBandNames('pc')])
.divide(sdImage);
};
var pcImage = getPrincipalComponents(centered, scale, region);
return ee.Image(image.addBands(pcImage));
});
print("PCA imagery: ",Preped);
I have been trying to spread the pie chart I have to cover most of the 'card' I on the page, but no matter how much margin I cut, it either start disappearing behind another border within the card. I noticed that amcharts lib creates a bunch of layers that the developer doesn't have much control over. Anyway, this is what I'm talking about:
Here is the generated HTML code snippet:
Here is my javascript:
am4core.ready(function () {
//Themes
var chartType = am4charts.PieChart3D;
var seriesType = new am4charts.PieSeries3D();
//Create Chart and Series
var chart = createChart(thisWidget.id, chartType);
var pieSeries = chart.series.push(seriesType); // 3D Pie Chart
//Set properties
chart.hiddenState.properties.opacity = 0; // 3D Pie Chart: this creates initial fade-in
pieSeries.slices.template.cornerRadius = 6; //Pie Chart with varying Radius + 3D
pieSeries.colors.step = 3; //Pie Chart with varying Radius + 3D
pieSeries.angle = 45;
//color
if (colorTheme) {
pieSeries.colors.list = getAmchartCustomTheme(colorTheme);
}
//data types
pieSeries.dataFields.value = "count";
pieSeries.dataFields.category = "tag";
chart.paddingTop = 0;
chart.marginTop = 0;
// Put a thick white border around each Slice
pieSeries.slices.template.stroke = am4core.color("#fff");
pieSeries.slices.template
// change the cursor on hover to make it apparent the object can be interacted with
.cursorOverStyle = [
{
"property": "cursor",
"value": "pointer"
}
];
//Make the slice move on hover
var slice = pieSeries.slices.template;
slice.states.getKey("active").properties.shiftRadius = 0;
slice.states.getKey("hover").properties.scale = 1;
slice.states.getKey("hover").properties.shiftRadius = 0.2;
//increase size of Chart
chart.svgContainer.htmlElement.style.height = targetHeight;
chart.svgContainer.autoresize = true;
//disable Ticks and labels to save space
pieSeries.labels.template.disabled = true;
//registering events
pieSeries.slices.template.events.on("hit", function (ev) {
var category = ev.target.slice._dataItem.properties.category;
addInput(category);
});
pieSeries.alignLabels = false;
// Create a base filter effect (as if it's not there) for the hover to return to
var shadow = pieSeries.slices.template.filters.push(new am4core.DropShadowFilter);
shadow.opacity = 0;
// Create hover state
var hoverState = pieSeries.slices.template.states.getKey("hover"); // normally we have to create the hover state, in this case it already exists
// Slightly shift the shadow and make it more prominent on hover
var hoverShadow = hoverState.filters.push(new am4core.DropShadowFilter);
hoverShadow.opacity = 0.7;
hoverShadow.blur = 5;
//Add Data
chart.data = displayItems;
})
strokeOpacity = 0 or strokeWidth = 0 should do the trick.
I have a globe with datamaps, and I would like to implement a little zoom feature into it. Not zooming to specific countries, just a normal zoom feature.
Where should I look for it? I'm new to d3 as well as datamaps. I managed to customize it, more or less, but this zoom function is still missing.
Here's the codepen:
https://codepen.io/simii/pen/yZvQmv
And my javascript:
//basic map config with custom fills, mercator projection
var series = [
["USA",36.2],["GBR",7.4],["CAN",6.2],["DEU",5.7],["FRA", 4.1],["ESP",4.1],["ITA",3.3],["MEX",3.0],["AUS",2.5],["NLD",2.4],
["IND",2.1],["BRA",2.0],["GRC",1.4],["AUT",1.2],["ROU",1.2],["SRB",1.0],["COL",0.8],["POL",0.8],["ZAF",0.7],["SWE",0.7],
["DNK",0.6],["VEN",0.6],["JPN",0.6],["KOR",0.6],["BEL",0.5],["RUS",0.5],["PRT",0.5]
];
var dataset = {};
// We need to colorize every country based on "percent"
// colors should be uniq for every value.
// For this purpose we create palette(using min/max series-value)
var onlyValues = series.map(function(obj){ return obj[1]; });
var minValue = Math.min.apply(null, onlyValues),
maxValue = Math.max.apply(null, onlyValues);
// create color palette function
// color can be whatever you wish
var paletteScale = d3.scale.linear()
.domain([minValue,maxValue])
.range(["rgb(0,0,0)","rgb(219,219,219)"]); // color
// fill dataset in appropriate format
series.forEach(function(item){ //
// item example value ["USA", 36.2]
var iso = item[0],
value = item[1];
dataset[iso] = { percent: value, fillColor: paletteScale(value) };
});
var map;
var globalRotation = [90,-30];
function redraw() {
d3.select("#world").html('');
init();
}// redraw
function init() {
map = new Datamap({//need global var
scope: 'world',
element: document.getElementById('world'),
projection: 'orthographic',
projectionConfig: {
rotation: globalRotation
},
fills: {defaultFill: 'rgba(30,30,30,0.1)'},
data: dataset,
geographyConfig: {
responsive: true,
borderColor: 'rgba(222,222,222,0.2)',
highlightBorderWidth: 1,
// don't change color on mouse hover
highlightFillColor: function(geo) {
return geo['fillColor'] || 'rgba(30,30,30,0.5)';
},
// only change border
highlightBorderColor: 'rgba(222,222,222,0.5)',
// show desired information in tooltip
popupTemplate: function(geo, data) {
// don't show tooltip if country don't present in dataset
if (!data) { return ; }
// tooltip content
return ['',
'<div style="opacity:0.7;" class="hoverinfo">% of visitors in ' + geo.properties.name,
': ' + data.percent,
''].join('');
}
}
});
//draw a legend for this map
map.legend();
map.graticule();
var drag = d3.behavior.drag().on('drag', function() {
var dx = d3.event.dx;
var dy = d3.event.dy;
// var rotation = livemapScope.rotation;
var rotation = map.projection.rotate();
var radius = map.projection.scale();
var scale = d3.scale.linear()
.domain([-1 * radius, radius])
.range([-90, 90]);
var degX = scale(dx);
var degY = scale(dy);
rotation[0] += degX;
rotation[1] -= degY;
if (rotation[1] > 90) rotation[1] = 90;
if (rotation[1] < -90) rotation[1] = -90;
if (rotation[0] >= 180) rotation[0] -= 360;
globalRotation = rotation;
redraw();
})
d3.select("#world").select("svg").call(drag);
}// init
redraw();
I'm using the Chart.js fork by Quince (leighquince/Chart.js) and was wondering is there any way to offset the line graph dots like I have illustrated on the first two dots here:
I think I would need a second x-axis.
Just swap your the draw function of the Overlay chart type to add your offset, like so
Chart.types.Overlay.extend({
// Passing in a name registers this chart in the Chart namespace in the same way
name: "OverlayAlt",
draw: function(ease) {
// most of this is from Quince's draw function
var easingDecimal = ease || 1;
this.clear();
this.scale.draw(easingDecimal);
Chart.types.Bar.prototype.drawDatasets.call(this, this.barDatasets, easingDecimal);
// here we just swap out the calculateX function after we draw the scale
var originalScaleDraw = this.scale.draw;
var originalCalculateX = this.scale.calculateX;
var scale = this.scale;
var offset = (scale.calculateX(2) - scale.calculateX(1)) / 2;
scale.draw = function() {
originalScaleDraw.apply(this, arguments);
scale.calculateX = function() {
return originalCalculateX.apply(this, arguments) + offset;
}
}
Chart.types.Line.prototype.drawDatasets.call(this, this.lineDatasets, easingDecimal);
this.scale.draw = originalScaleDraw;
this.scale.calculateX = originalCalculateX;
},
});
Fiddle (updated version of the one in your comment) - http://fiddle.jshell.net/4tk3aa9e/
I created an amchart for plotting time based area. I need to add an export to image option to this graph. Below shows my amchart code. What are the lines needed to add the export to image option to this graph
AmCharts.ready(function () {
// first we generate some random data
generateChartData();
// SERIAL CHART
chart = new AmCharts.AmSerialChart();
chart.pathToImages = "../amcharts/images/";
chart.dataProvider = chartData;
chart.categoryField = "date";
// data updated event will be fired when chart is first displayed,
// also when data will be updated. We'll use it to set some
// initial zoom
chart.addListener("dataUpdated", zoomChart);
// AXES
// Category
var categoryAxis = chart.categoryAxis;
categoryAxis.parseDates = true; // in order char to understand dates, we should set parseDates to true
categoryAxis.minPeriod = "mm"; // as we have data with minute interval, we have to set "mm" here.
categoryAxis.gridAlpha = 0.07;
categoryAxis.axisColor = "#DADADA";
// Value
var valueAxis = new AmCharts.ValueAxis();
valueAxis.gridAlpha = 0.07;
valueAxis.title = "Unique visitors";
chart.addValueAxis(valueAxis);
// GRAPH
var graph = new AmCharts.AmGraph();
graph.type = "line"; // try to change it to "column"
graph.title = "red line";
graph.valueField = "visits";
graph.lineAlpha = 1;
graph.lineColor = "#d1cf2a";
graph.fillAlphas = 0.3; // setting fillAlphas to > 0 value makes it area graph
chart.addGraph(graph);
// CURSOR
var chartCursor = new AmCharts.ChartCursor();
chartCursor.cursorPosition = "mouse";
chartCursor.categoryBalloonDateFormat = "JJ:NN, DD MMMM";
chart.addChartCursor(chartCursor);
// SCROLLBAR
var chartScrollbar = new AmCharts.ChartScrollbar();
chart.addChartScrollbar(chartScrollbar);
// WRITE
chart.write("chartdiv");
});
You should just be able to add the following before you write the chart to the DIV.
"exportConfig":{
"menuTop": 0,
menuItems: [{
textAlign: 'center',
icon: 'images/graph_export.png',
iconTitle: 'Save chart as an image',
onclick:function(){},
items: [
{title:'JPG', format:'jpg'},
{title:'PNG', format:'png'},
{title:'SVG', format:'svg'}
]
}]
}
This will give you a download icon on the graph to download in either JPG, PNG or SVG formats.
Try this code :
chart.export = {
enabled: true,
position: "bottom-right"
}
chart.initHC = false;
chart.validateNow();
And don't forget to include the needed export plugin!