Draw line with d3.js using separate, fixed x & y input arrays - svg

I have separate x and y arrays and want to connect the dots using a line path. This seems to be about the simplest possible example but I don't quite grok the writing the function. Here is my code:
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src = "http://d3js.org/d3.v3.min.js"> </script>
<script>
var margin = {top: 20, right: 20, bottom: 20, left: 20},
width = 600 - margin.left - margin.right,
height = 270 - margin.top - margin.bottom;
var xdata = d3.range(20);
var ydata = [1, 4, 5, 9, 10, 14, 15, 15, 11, 10, 5, 5, 4, 8, 7, 5, 5, 5, 8, 10];
var xscl = d3.scale.linear()
.domain(d3.extent(xdata))
.range([0, width])
var yscl = d3.scale.linear()
.domain(d3.extent(ydata))
.range([height, 0])
var slice = d3.svg.line()
.x(function(d) { return xscl(xdata[d]);})
.y(function(d) { return yscl(ydata[d]);})
var svg = d3.select("body")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
svg.append("path")
.attr("class", "line")
.attr("d", slice)
</script>
</body>
But it returns an error Uncaught TypeError: Cannot read property 'length' of undefined, so clearly the function returned by d3.svg.line() doesn't have the right form. What's wrong? I pray not a typo!

I know it has been more than a year, but I had to deal with this problem also.
Storing path data (x, y) in 2 separate arrays is much more memory efficient than the 2D array d3.svg.line expects. For a very large number of points, the accepted answer is also inefficient by looping through all elements to create the 2D array.
The solution I found without adding any loops is write a wrapper function for d3.svg.line as follows:
var line = function(x, y){
return d3.svg.line()
.x(function(d,i) { return x[i]; })
.y(function(d,i) { return y[i]; })
(Array(x.length));
}
and then set the path attributes:
svg.append("path")
.attr("d", line(x_array, y_array))
See the updated fiddle here

Based on Elijah's spot on remark about d3.svg.line, I think it is hard to go about this without putting the array as expected by this function. So:
var xy = [];
for(var i=0;i<xdata.length;i++){
xy.push({x:xdata[i],y:ydata[i]});
}
I made other changes regarding .domain and the slice function per se. Here is a FIDDLE with the results of my effort.

d3.svg.line can only take one data source. However, you can feed it your two data sources by putting them into an object:
newData = {x: xdata, y: ydata};
var slice = d3.svg.line()
.x(function(d,i) { return xscl(d.xdata[i]);})
.y(function(d,i) { return yscl(d.ydata[i]);})
Then point your line function at newData and you should be set:
svg.append("path")
.attr("class", "line")
.attr("d", slice(newData))
Typically, though, you're better off building an array of coordinate pairs, since that's what it's expecting.

Related

Why subscripts are missing in the labels?

I want to display the subscript in the labels in the bar plot. Labels are the keys from the dictionary data in the following. I know how to use latex to do so, but I need to display it as it is from the keys in the dictionary. When I use the following script, it just displays the empty box, instead of the subscript.
import numpy as np
data = {'CO₆': 15,
'DO₄': 144,
'EO₈': 3,
'FaO₉': 1,
'GO₅': 7,
'Ha₆': 5}
f, ax = plt.subplots(figsize = (40, 4))
bin = np.arange(len(data.keys()))
ax.bar(data.keys(), data.values(), color='brown', align = "center", width = 0.3);
plt.xticks(rotation='vertical');
ax.xaxis.set_tick_params(labelsize = 32);
ax.yaxis.set_tick_params(labelsize = 32);
plt.xlim(-0.5, bin.size-0.5);
The font that you are using must not have those unicode characters.
Try changing the font, this one works for me:
plt.rcParams['font.sans-serif'] = ['DejaVu Sans']
To use a Serif font:
plt.rcParams['font.family'] = 'serif'
plt.rcParams['font.serif'] = ['DejaVu Serif']

Controlling which elements receive hover tooltip in Bokeh

I'm currently trying to find a way to use an boolean array in order to decide which elements recive HoverTooltips in bokeh while only using one dictonary for the plot.
I allready tryed to use the bokeh rendering function but this didn't quite work.
source.data = dict(
x=data_source.loc[:, 'x_col_name'],
y=data_source.loc[:, 'y_col_name'],
color=color_selection(selected), # Translates bool to color
alpha=alpha_selection(selected), # Translates bool to transparency
active=selection # boolean array of selected elements
)
Only active datapoints should recieve a HoverTooltip
As a temporary work-around you could hide the tooltips in a callback like this (works for Bokeh v1.3.0):
from bokeh.plotting import figure, show
from bokeh.models import CustomJS
data = dict(
x=[1, 2, 3, 4, 5],
y=[1, 2, 3, 4, 5],
color=['red', 'green', 'red', 'green', 'red'],
active=[False, True, False, True, False],
)
p = figure(tooltips=[('x','#x'),('y', '#y'), ('active', '#active')])
p.circle('x', 'y', color='color', size=10, source = data)
code_hover = '''
if (cb_data.index.indices.length > 0) {
var active_index = cb_data.index.indices[0]
var data = cb_data.renderer.data_source.data
var show_tooltip = data['active'][active_index]
var tooltip_index = 0
if (show_tooltip) {
document.getElementsByClassName('bk-tooltip')[tooltip_index].style.display = 'block';
}
else {
document.getElementsByClassName('bk-tooltip')[tooltip_index].style.display = 'none';
}
}
'''
p.hover.callback = CustomJS(code = code_hover)
show(p)
Please note the tooltip_index in the callback. If you have more tooltips you need to change that index. See also this post
Result:
As of Bokeh 1.x there is no built-in capability to filter hover results. That feature is planned for the 2.0 release, you can follow this issue here: https://github.com/bokeh/bokeh/issues/9087

Fit.Polynomial Show func

I'm using Fit.Polynomial to fit my data and show by graph, and all works great, but I couldn't find way to present my Y-function to any order. If the function is order 2 so I want it to be presents as y=ax^2+bx+c, and if the order is 3 so function would be y=ax^3+bx^2+cx+d.
Is there any way to do it?
Use Polynomial.Fit which returns Polynomial instead of Fit.Polynomial which returns double[].
var x = new double[] { 1, 2, 3 };
var y = new double[] { 2, 5, 9 };
Console.WriteLine("Fit.Polynomial");
double[] #double = Fit.Polynomial(x, y, 2);
Console.WriteLine(#double);
Console.WriteLine(string.Join(", ", #double));
Console.WriteLine("\nPolynomial.Fit");
Polynomial polynomial = Polynomial.Fit(x, y, 2);
Console.WriteLine(polynomial);
Console.WriteLine("\nPolynomial.Fit");
Polynomial polynomial = Polynomial.Fit(x, y, 2);
Console.WriteLine(polynomial);
Gives
Fit.Polynomial
System.Double[]
0, 1.5, 0.500000000000001
Polynomial.Fit
1.5x + 0.500000000000001x^2

Remove Tick marks in Line chart, APACHE POI

I've generated a line chart using Apache poi. There are 400 values in the X axis and the tick marks make some values unclear as there is lot of tick marks there. Therefore, I need to remove the tick marks in X axis. Is there any way to remove them?
My code is as follows.
Drawing drawing = sheet4.createDrawingPatriarch();
ClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 1, 1, 17, 22);
Chart chart = drawing.createChart(anchor);
ChartLegend legend = chart.getOrCreateLegend();
legend.setPosition(LegendPosition.RIGHT);
LineChartData data = chart.getChartDataFactory().createLineChartData();
ChartAxis bottomAxis = chart.getChartAxisFactory().createCategoryAxis(AxisPosition.BOTTOM);
ValueAxis leftAxis = chart.getChartAxisFactory().createValueAxis(AxisPosition.LEFT);
leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
ChartDataSource<Number> xs = DataSources.fromNumericCellRange(sheet1, new CellRangeAddress(1, 380, 0, 0));
ChartDataSource<Number> ys1 = DataSources.fromNumericCellRange(sheet1, new CellRangeAddress(1, 380, 1, 1));
ChartDataSource<Number> ys2 = DataSources.fromNumericCellRange(sheet1, new CellRangeAddress(1, 380, 3, 3));
ChartDataSource<Number> ys3 = DataSources.fromNumericCellRange(sheet1, new CellRangeAddress(1, 380, 4, 4));
ChartDataSource<Number> ys4 = DataSources.fromNumericCellRange(sheet1, new CellRangeAddress(1, 380, 8, 8));
LineChartSeries series1 = data.addSeries(xs, ys1);
series1.setTitle("Value 1");
LineChartSeries series2 = data.addSeries(xs, ys2);
series2.setTitle("Value 2");
LineChartSeries series3 = data.addSeries(xs, ys3);
series3.setTitle("Value 3");
LineChartSeries series4 = data.addSeries(xs, ys4);
series4.setTitle("Value 4");
chart.plot(data, bottomAxis, leftAxis);
XSSFChart xssfChart = (XSSFChart) chart;
CTPlotArea plotArea = xssfChart.getCTChart().getPlotArea();
plotArea.getLineChartArray()[0].getSmooth();
CTBoolean ctBool = CTBoolean.Factory.newInstance();
ctBool.setVal(false);
plotArea.getLineChartArray()[0].setSmooth(ctBool);
for (CTLineSer ser : plotArea.getLineChartArray()[0].getSerArray()) {
ser.setSmooth(ctBool);
}
For newer POI versions , we could remove the marker style using:
series1.setMarkerStyle(MarkerStyle.NONE);
Additional Info:
In addition to that it support different marker styles:
MarkerStyle.CIRCLE
MarkerStyle.DASH
MarkerStyle.DIAMOND
MarkerStyle.DOT
MarkerStyle.PICTURE
MarkerStyle.PLUS
MarkerStyle.SQUARE
MarkerStyle.STAR
MarkerStyle.TRIANGLE
I'm using the library version : 4.1.2.

Displaying totals above stacked bars in barchart: matplotlib.pyplot

I am just starting out with matplotlib.pyplot and am a little stuck.
Using the example in the matpltlib.pyplot documentation, I have created a stacked bar chart using the following code:
import numpy as np
import matplotlib.pyplot as plt
N = 7
OECD = (242, 244, 255, 263, 269, 276, 285)
NonOECD = (282, 328, 375, 417, 460, 501, 535)
Sum = ('524', '572', '630', '680', '729', '777', '820')
ind = np.arange(N)
width = 0.5
p1 = plt.bar(ind, NonOECD, width, color = 'r')
p2 = plt.bar(ind, OECD, width, color = 'b', bottom = NonOECD)
plt.ylabel('Quadrillion Btu')
plt.title('World Total Energy Consumption 2010 - 2040')
plt.xticks(ind+width/2., ('2010', '2015', '2020', '2025', '2030', '2035', '2040'))
plt.yticks(np.arange(0, 1001, 200))
plt.legend((p1[0], p2[0]), ('Non - OECD', 'OECD'), loc = 2, frameon = 'false')
plt.tick_params(top = 'off', bottom = 'off', right = 'off')
plt.grid(axis = 'y', linestyle = '-')
plt.show()
However I want to display the totals on top of the bars and I cannot quite work out how. I have seen this post but am having issues:
for ii,rect in enumerate(p1):
h1 = rect.get_height()
for ii,rect in enumerate(p2):
h2 = rect.get_height()
height =
plt.text(rect.get_x()+rect.get_width()/2., height, '%s'% (Sum[ii]), ha = 'center', va='bottom')
If I use height = h1 I get ; if I use height = h2 I get ; if I use height = h1 + h2 I get .
What I want is these numbers sitting directly on above the second (blue) bar [like the 524 on the 2010 bar in my 1st attempt]. Am I missing something really obvious?
As always, any help would be much appreciated!
Cheers
Try this:
for r1,r2 in zip(p1,p2):
h1 = r1.get_height()
h2 = r2.get_height()
plt.text(r1.get_x()+r1.get_width()/2., h1+h2, '%s'% (h1+h2), ha = 'center', va='bottom')

Resources