UNPKG

smartdown

Version:

A library for translating, rendering and interacting with Smartdown documents. Smartdown is an extension of Markdown that provides richer media support and reactive programming capability.

271 lines (209 loc) 6.45 kB
## D3 ### Streaming Financial Chart Meanwhile, a cool graphic where the *stream* is an infinitely generated series of random numbers... Adapted from [Streaming Financial Chart](https://bl.ocks.org/ColinEberhardt/ab7805a9a7af9717e86adc1656fa98d9). ```d3/playable smartdown.importCssCode( ` .bollinger .area { fill: #9cf; fill-opacity: 0.5; } .bollinger .line { stroke: #06c; } .chart { height: 200px !important; } `); // window.d3 = window.d3v4; var target = this.div; target.classList.add('chart'); // create some test data const stream = fc.randomFinancial().stream(); const data = stream.take(110); function renderChart() { if (target.style.display === 'none' && window.intervalId) { window.clearInterval(window.intervalId); return; } // add a new datapoint and remove an old one data.push(stream.next()); data.shift(); const container = d3.select(target); // Create and apply the bollinger algorithm const bollingerAlgorithm = fc.indicatorBollingerBands() .value(function(d) { return d.close; }); const bollingerData = bollingerAlgorithm(data); const mergedData = data.map(function(d, i) { return Object.assign({}, d, { bollinger: bollingerData[i] }); }); // Offset the range to include the full bar for the latest value const DAY_MS = 1000 * 60 * 60 * 24; const xTicks = 10;// $('#streaming-chart').width() >= 700 ? 10 : 5; const xExtent = fc.extentDate() .accessors([function(d) { return d.date; }]) .padUnit('domain') .pad([DAY_MS * -bollingerAlgorithm.period()(mergedData), DAY_MS]); // ensure y extent includes the bollinger bands const yExtent = fc.extentLinear() .accessors([ function(d) { return Math.max(d.bollinger.upper, d.high); }, function(d) { return Math.min(d.bollinger.lower, d.low); } ]); // create a chart const chart = fc.chartSvgCartesian( d3.scaleTime(), d3.scaleLinear() ) .xDomain(xExtent(mergedData)) .xTicks(xTicks) .yDomain(yExtent(mergedData)) .chartLabel('Streaming Candlestick'); // Create the gridlines and series const gridlines = fc.annotationSvgGridline().xTicks(xTicks); const candlestick = fc.seriesSvgCandlestick(); const bollingerBands = function() { const area = fc.seriesSvgArea() .mainValue(function(d) { return d.bollinger.upper; }) .baseValue(function(d) { return d.bollinger.lower; }); const upperLine = fc.seriesSvgLine() .mainValue(function(d) { return d.bollinger.upper; }); const averageLine = fc.seriesSvgLine() .mainValue(function(d) { return d.bollinger.average; }); const lowerLine = fc.seriesSvgLine() .mainValue(function(d) { return d.bollinger.lower; }); const crossValue = function(d) { return d.date; }; area.crossValue(crossValue); upperLine.crossValue(crossValue); averageLine.crossValue(crossValue); lowerLine.crossValue(crossValue); const bollingerMulti = fc.seriesSvgMulti() .series([area, upperLine, lowerLine, averageLine]) .decorate(function(g, datum, index) { g.enter() .attr('class', function(_, i) { return 'multi bollinger ' + ['area', 'upper', 'lower', 'average'][i]; }); }); return bollingerMulti; }; // add them to the chart via a multi-series const multi = fc.seriesSvgMulti() .series([gridlines, bollingerBands(), candlestick]); chart.plotArea(multi); container .style('margin-left', '20px') .datum(mergedData) .call(chart); } // re-render the chart every 200ms renderChart(); if (window.intervalId) { window.clearInterval(window.intervalId); } window.intervalId = setInterval(renderChart, 200); ``` ### Smelly London Line Graph One of the visualizations available via Smelly London is a [Line Chart](https://github.com/Smelly-London/Smelly-London/tree/master/charts). I made some slight changes so that it can be rendered in Smartdown: ```d3/playable var renderDiv = this.div; renderDiv.classList.add('foo'); smartdown.importCssCode( ` body .foo svg { font: 10px sans-serif; background: lightyellow; } .foo .axis path, .foo .axis line { fill: none; stroke: #000; shape-rendering: crispEdges; } .foo .x.axis path { display: none; } .foo .line { fill: none; stroke: #2091c1; stroke-width: 1.5px; } `); var margin = {top: 20, right: 20, bottom: 30, left: 50}, width = 960 - margin.left - margin.right, height = 500 - margin.top - margin.bottom; // var formatDate = d3.time.format("%d-%b-%y"); var formatDateCarto = d3.timeParse("%Y/%m/%d"); var x = d3.scaleTime() .range([0, width]); var y = d3.scaleLinear() .range([height, 0]); var xAxis = d3.axisBottom() .scale(x); var yAxis = d3.axisLeft() .scale(y); var line = d3.line() .x(function(d) { return x(d.date); }) .y(function(d) { return y(d.number_of_smells); }); var svg = d3.select(renderDiv).append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); // d3.tsv("data/all_records.tsv", type, function(error, data) { // d3.tsv("data/output/Barnet.tsv", type, function(error, data) { // d3.tsv("data/output/Barnet.tsv", type, function(error, data) { // d3.tsv("data/output/Croydon.tsv", type, function(error, data) { d3.tsv("https://rawcdn.githack.com/Smelly-London/Smelly-London/master/charts/data/output/Tower Hamlets.tsv", type, function(error, data) { if (error) throw error; x.domain(d3.extent(data, function(d) { return d.date; })); y.domain(d3.extent(data, function(d) { return d.number_of_smells; })); svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis); svg.append("g") .attr("class", "y axis") .call(yAxis) .append("text") .attr("transform", "rotate(-90)") .attr("y", 6) .attr("dy", ".71em") .style("text-anchor", "end") .text("Number of smells"); svg.append("path") .datum(data) .attr("class", "line") .attr("d", line); }); function type(d) { d.date = formatDateCarto(d.date); d.number_of_smells = +d.number_of_smells; return d; } ``` --- [Back to Home](:@Home)