I have some data that looks like this:
[{
a: 15,
b: 30,
c: 25,
d: 12
},
{
a: 15,
c: 25,
d: 12
}]
I want to render a barchart that skips the space in between a and c if b is undefined, but will still render b if it is defined.
Basically like the two bar chart groups in this image where the orange bar is skipped because there is no data for it
Related
I have a list which consists of [A, B, C, D, E] and A has a list of values [1, 2, 3, 4, 5] similarly B has a list of values [1, 2, 3, 4, 5]
Date,SKU,Unit Price,Quantity,Total Price
2019-01-01,Death by Chocolate,180,5,900
2019-01-01,Cake Fudge,150,1,150
2019-01-01,Cake Fudge,150,1,150
2019-01-01,Cake Fudge,150,3,450
2019-01-01,Death by Chocolate,180,1,180
2019-01-01,Vanilla Double Scoop,80,3,240
2019-01-01,Butterscotch Single Scoop,60,5,300
2019-01-01,Vanilla Single Scoop,50,5,250
2019-01-01,Cake Fudge,150,5,750
Something like this but what I want is to create a map where the header is equal to values corresponding to it.
The expected output looks something like this:-
[%{date: '2019-01-01',SKU: 'Death by Chocolate', price: 50, quantity: 3},
%{date: '2019-01-01',SKU: 'Cake Fudge', price: 150, quantity: 3}]
I'm having a difficulty converting something like this.
For your specific use case a CSV parser will do what you're looking for, even if your file extension isn't .csv.
If you're just looking to use one list as keys for other lists, you can combine Enum.zip/2 with Map.new/1 to zip your header list with a row list and create a map (depending on file size you may want to work with streams instead of lists).
iex> [headers | rows] = do_some_parsing(text)
iex> headers
["Date", "SKU", "Unit Price", "Quantity", "Total Price"]
iex> rows
[["2019-01-01", "Death by Chocolate", 180, 5, 900],
["2019-01-01", "Cake Fudge", 150, 1, 150],
...]
iex> Enum.map(rows, fn row -> headers |> Enum.zip(row) |> Map.new() end)
[%{"Date" => "2019-01-01", "SKU" => "Death by Chocolate", "Unit Price" => 180, "Quantity" => 5, "Total Price" => 900},
%{"Date" => "2019-01-01", "SKU" => "Cake Fudge", "Unit Price" => 150, "Quantity" => 1, "Total Price" => 150},
...]
Something like this, but without legend and with labels on y.
Here is what I've used to make a horizontal bar with pygal:
bar_chart = pygal.HorizontalBar(show_legend=False)
bar_chart.title = "Title"
bar_chart.add("", [1, 4, 6, 7, 2, 3])
bar_chart.x_labels = ("the", "quick", "brown", "fox", "jumps", "over")
It produced a graph like this:
I have a complex data structure (multiple levels of arrays of hashes). I want to find and update a specific value. However, detect does not seem to pass the reference to the location in the data structure that I want to update. I can code this using each or each_with_object but that would iterate over ALL the data when I want to stop # the first match. In my actual program, "mymouse" and 485 are variables representing those values.
What single line command can update this entry?
Why does detect not work like each{} in terms of being able to modify the data? I would expect this to work since Ruby is pass-by-reference.
mynew = [{:mouse=>{:cat=>[485, 2, 10, 10, 10, 10, 7], :dog=>[1, 2, 3, 4, 5, 6, 7]}, :name=>"mymouse"}, {:name=>"mymouse", :mouse=>{:cat=>[485, 11, 10], :dog=>[45, 54, 65]}}]
# Finds the value I want to update to 12
puts mynew.detect{|f| f[:name] == "mymouse"}[:mouse][:cat].detect{|x| x==485}
# results in an error
mynew.detect{|f| f[:name] == "mymouse"}[:mouse][:cat].detect{|x| x==485} = 12
# Does not update the value to 12
location = mynew.detect{|f| f[:name] == "mymouse"}[:mouse][:cat].detect{|x| x==485}
location = 12
puts mynew # Value unchanged
Here is one way to do it:
data = [
{
:name=>"mymouse",
:mouse=>{
:cat=>[485, 2, 10, 10, 10, 10, 7],
:dog=>[1, 2, 3, 4, 5, 6, 7]
},
},
{
:name=>"othermouse",
:mouse=>{
:cat=>[485, 11, 10],
:dog=>[45, 54, 65]
}
}
]
entry = data.find { |f| f[:name] == "mymouse" }
array = entry[:mouse][:cat]
modified_array = array.map { |n| n == 485 ? 12 : n }
entry[:mouse][:cat] = modified_array
require 'pp'
pp data
This will work; I tested it.
Alternatively, once you have the array you could just use:
array[array.index(485)] = 12
This modifies the original array, so it could have a different effect than the main solution I posted, which does not modify the original array.
I have a Kendo UI line chart.
This has x axis intervals of 28 days and data plotted against this every 28 days.
I want to know if its possible to add a second line but with data plotted daily rather than every 28 days.
Thanks
Yes, you can! This type of series are called scatterLines and basically for each series you have to provide an array of pairs with the x and y values.
If for the first series you provide values 0, 28, 56... and for the second 0, 1, 2... You get what you want.
Example:
$("#chart").kendoChart({
series: [
{ type: "scatterLine", data: [[0, 4], [28, 2], [56, 3]] },
{ type: "scatterLine", data: [[1, 2], [2, 3]] }
]
});
Check it here: http://jsfiddle.net/U7SvD/
Let us consider this simple data:
var data = [
{
"id": "A",
"geometry": [ [0, 0], [10, 10], [10, 20], [0, 20] ]
},
{
"id": "B",
"geometry": [ [10, 10], [25, 10], [25, 30], [10, 20] ]
},
];
I'd like to display "A" and "B" using a distinct area for each, as doing so will let me apply a class to them (useful because I want them to use different background colors and to react separately to clicks and mouse hovers.)
I'm able to use d3.svg.area() to draw a continuous graph however it assumes that "the input data is a two-element array of numbers" (not my case) and it does not seem to support the drawing of distinct areas.
What is the pattern for it?
UPDATE
I'm using polygons in the sample data for simplicity. Overall, the goal however is to produce a stream that be composed of several areas instead of just a single one. Best illustrated with the picture below:
I'll update the post if more details are needed.
Hard to understand what exactly you mean by wanting to draw distinct areas. Do you mean that you want to end up with 2 path elements –– one for the geometry of the object with id:"A" and the other for id: "B"? If so:
var pathGenerator = d3.svg.area()
var paths = d3.select("svg").selectAll("path").data(data);
paths.enter()
.append("path")
.attr("class", function(d) {
if(d.id == "A") { return 'class-A'; }
else if(d.id == "B") { return 'class-B'; }
})
.attr("d", function(d) {
return pathGenerator(d.geometry);
});