How do I manipulate the axis of a svg chart? - d3.js

I am drawing a scatter chart using d3.js and epoch. The values that becomes the circles in the chart are based on log values, which makes my both axis go below zero.
var chart = $('#scatterchart').epoch({ type: 'scatter', data: scatterData, axes: ['bottom', 'left'], ticks: { right: 4, bottom: 4}, domain: [-1.4, 2], range: [-2,4], margins: { top: 10, right: 80, bottom: 60, left: 80 }, });
I would like to keep the position of the circles but manipulate the axis so that:
x(horisontal):
-1 -> 0.5
0 -> 1
1 -> 2
2 -> 4
y(vertical):
-2 -> 0.25
-1 -> 0.5
0 -> 1
1 -> 2
2 -> 4
3 -> 8
4 -> 16
Anyone that has any suggestion on how to do this?

I have no experience with epoch.js, and I don't know if you can tweak the axes it creates.
But you could try to transform your data before feeding it to your scatterplot generator.
If scatterData is an array, you could use array.map():
newData = scatterData.map(function(d){return someTransformFuntion(d);});
And adapt the input domain of your axis (actually, your scale) accordingly.

I have no experience with epoch.
But assuming it works on top of d3js, all you need to do is change the domain of both of your scales.
When you visualise your data, you work with a domain (for data) and a range (pixels on your screen). So to support negative values, you would need to adjust the domain to support [-2, 4] (for the y axis example).
As a bonus some reading about domains and negative values

Related

what is output format of Utils? (using chartjs in vanillajs, not react/angular)

I'm trying to load data for a bubbles chart from datafiles, the examples use a chartjs function to generate data.
Working through some of the examples, want to load csv/json files via d3.js as will be using data files from an api and front end not in react/angular.
examples so far.
https://github.com/aspiringguru/chartjs_3.7.1_vanilla
I can't see the output format of Utils.* used in the examples.
expecting will need x,y,radius for each point. just need to work out what format chartjs expects the data in.
https://www.chartjs.org/docs/next/samples/other-charts/bubble.html
uses
data: Utils.bubbles(NUMBER_CFG)
dataset.data = Utils.bubbles({count: chart.data.labels.length, rmin: 5, rmax: 15, min: 0, max: 100});
had a look at
https://github.com/chartjs/Chart.js/blob/master/docs/scripts/utils.js
and I can't understand the output generated from
function bubbles(config)
As can be read here in the documentation. The datastructure for bubble charts consists out of an array containing objects where each object has an x key for the x value, an y key for the y value and a r key for the radius.
{
// X Value
x: number,
// Y Value
y: number,
// Bubble radius in pixels (not scaled).
r: number
}
const data = [{x: 5, y: 7, r: 9}, {x: 6, y: 3, r: 1}];

How to display the axis to the right?

I have 3 axes (velue-axis)
Can one axis be displayed on the left
Other two axes to display on the right?
http://demos.telerik.com/kendo-ui/line-charts/multiple-axes
(In this example, the axis is located on the right, but I do not know how to configure it)
Thanks.
Granted this isn't entirely clear when you first look at the demo. The important thing to look at is this section:
categoryAxis: {
categories: [],
axisCrossingValues:[]//This is the fella you are looking for.
}
I have tweaked the demo slightly to show you one of the axis in the middle of the chart. http://dojo.telerik.com/ASidu
The number is simply the position column on the chart that the axis should be rendered. By default if this in't set then all axis should be on the left hand side as normal. but if we start applying a number greater than 0 then the axis will shift. So in the example we have 3 value axis set up:
valueAxes: [{
name: "rain",
color: "#007eff",
min: 0,
max: 60
}, {
name: "wind",
color: "#73c100",
min: 0,
max: 60
}, {
name: "temp",
min: -30,
max: 30
}],
so if we look at them from crossing the y-axis (i.e. the bottom axis) we have 31 columns available to us 1- 31 so in my tweak I have applied this to the crossingAxis:
axisCrossingValues: [32, 15, 0]
This is effectively telling each of the value axes where they should be positioned:
so:
"rain" should be at position 32
"wind" should be at position 15
"temp" should be at position 0
So the order in which you add your value axes will determine which setting they take based on the order you include them.
Hopefully that helps clear things up for you. If you need any more info let me know and I will update accordingly

How to adjust scale to occupy more data in d3js

I'm drawing a scatter plot with d3js. Using a simple linear scale with 1,2,3,4,5. This creates equal space like:
1 2 3 4 5
problem is, I have more data points between 2 and 3, 3 and 4. less data points between 1 and 2, 4 and 5. Is it possible to configure the scale to look like:
1 2 3 4 5
or instead of linear scale I should try some other scales? Please suggest.
First, a word of warning: distorting a scale (depending on the data you want to visualize) can maybe have "undesired" effects.
If you want to go ahead, I quickly set up a fiddle to show a possible way:
Fiddle
Basically, I am using custom domain/ranges to get the desired effect:
var x2 = d3.scale.linear()
.domain([1, 2, 3, 4, 5])
.range([0, 20, 80, 170, 200]);
Does that help?

Display different values on axis than those found by the scale function in D3

I have a d3 graph that uses a linear scale for its x axis. It looks something like this:
...
y |
|
+-------------------------------------------
0.0 0.5 1.0 1.5 2.0 2.5 3.0
Time in weeks
Beneath this axis I want to display rows of data aligned to the x axis. Like this:
23 23 22 19
Using this data:
var nums = [23, 23, 22, 19];
var times = [0, 0.5, 1.5, 3];
times are where the nums should fall on the Time in weeks x axis. So the first index of nums falls under 0.0, the second under 0.5, and so on.
The scale function looks something like this:
var x = d3.scale.linear().domain([0,3]).range([0, 600]);
So x(0.5) returns the correct range value for displaying a tick on the new axis. But what I want to display is the corresponding value from the nums array. That is, display the value of nums[times.indexOf(0.5)].
Is there a way to override scale() as used by d3.svg.axis() so that it displays nums values instead of times values while still using times as the input domain?
Edit
Here is a demo
Edit 2
I figured it out thanks to ne8il's answer. The answer was not complete, but it formed the basis for this code:
var x1Axis = d3.svg.axis()
.scale(x1)
.ticks(nums)
.tickValues(times)
.tickFormat(function(x){return nums[times.indexOf(x)];})
Working example
I believe in this case you can do
d3.svg.axis().ticks(times).tickValues(nums);
It will pass each 'time' into your scale function to map it to an x coordinate, and use the corresponding indexed value in 'nums' to output text.
Source is here

Find frequency for non-binned, weighted data

Here is a tricky problem (or at least so I think). I need to create a histogram, but instead of having the data and it's frequency, I have repeated data (i.e. not binned) and some weight for each data.
One example:
Angle | Weight
90 .... 3/10
93 .... 2/10
180 .... 2/10
180 .... 1/10
95 .... 2/10
I want to create a histogram with bin size 10. The y-values should be the sum of weighted frequencies for angles within a range. How can I do it? Preferably Mathematica or pseudocode...
In Mathematica 9, you can do it using the WeightedData function like this:
Histogram[WeightedData[{90, 93, 180, 180, 95}, {3/10, 2/10, 2/10, 1/10, 2/10}], {10}]
You should then get a graphic like this one:
Since the expected output is not forthcoming I shall adopt Verbeia's interpretation. You might use something like this:
dat = {{90, 3/10}, {93, 1/5}, {180, 1/5}, {180, 1/10}, {95, 1/5}};
bars =
Reap[
Sow[#2, Floor[#, 10]] & ### dat,
_,
{#, Tr##2} &
][[2]]
Graphics[
Rectangle[{#, 0}, {# + 10, #2}] & ### bars,
AspectRatio -> 1/GoldenRatio,
Axes -> True,
AxesOrigin -> {Min#bars[[All, 1]], 0}
]
I did something similar for a different kind of question recently (weighting by balance sheet size).
Assuming your data is in an N * 2 matrix list, I would do something like:
{numbers,weights} = {data[[All,1]], data[[All,2]]*10};
weightednumbers = Flatten# MapThread[
Table[#1, {#2}] &, {numbers, Ceiling[weights]}];
And then use Histogram to draw the histogram on this transformed data.
There might be other ways but this works.
An important point is to make sure the weights are integers, so the Table as the correct iterator. This might require defining weights as data[[All,2]]*Min[data[[All,2]].

Resources