How to match a position in an array to a scale in d3 - d3.js

Horrific title, I apologise.
Can someone please help me understand how to achieve the following.
I have a lovely routine that plots a scale, on a map, which is quite customisable in terms of it's orientation, number of colours, etc, the core of which is as follows:
var heatmapColour = d3.scale.linear().domain(d3.range(0, colours.length, 1.0 / (colours.length - 1))).range(colours);
var c = d3.scale.linear().domain(d3.extent(legendDomain)).range([0, 1]);
And if I have an array of colours as the following:
var colours = ["#6363FF", "#6373FF", "#63A3FF", "#63E3FF", "#63FFFB", "#63FFCB", "#63FF9B", "#63FF6B", "#7BFF63", "#BBFF63", "#DBFF63", "#FBFF63", "#FFD363", "#FFB363", "#FF8363", "#FF7363", "#FF6364"];
My routine can generate a legend of Red, Yellow, Green, Cyan and Blue if I set the legendDomain to have 5 entities, or if I set it to 3, would be simply Red, Green, and Blue, etc, etc.
It works perfectly.
However I'm now trying to match some countries to his legend which are based on their order in an array.
So for example, and for simplicity, if I have 50 countries and my legend set to draw 5 colours, I want the first 10 to be Red, the next 10 Yellow, the next 10 Green, etc, etc.
Using the same method to create the legend simply doesn't produce the same results.
Where my legend creates a range of colours within a domain, I now want to kind of go into this backwards and return a colour if 'something' (in this case it's order in the array) falls between the colour values.
Can someone please explain on how to achieve this.

I did something like this:
var colors = ['red', 'green', 'blue', 'brown'];
var countries = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M"];
var heatmapColour = d3.scale.ordinal().range(colors);//i used ordinals instead of linear
countries.forEach(function(d, i){
console.log(d,heatmapColour(Math.floor((i)/colors.length)))
});
working code here

A bit long for a comment, but is this what you are trying to achieve?
// Example arrays
var cols = ['c1', 'c2', 'c3'];
var ctry = [1, 2, 3, 4, 5, 6, 7, 8, 9];
function getCol(cols, i) {
return cols[Math.floor(i / cols.length)];
}
ctry.map(function(d,i) { console.log(getCol(cols, i)); });
(essentially divide index by length of color array and floor).
Fiddle

Related

seaborn countplot add xtick this is sum of all other xtick values

I'm trying to plot a seaborn countplot with parameter x and hue:
data = {"group1":[1, 2, 3, 1, 2, 3, 1, 1, 2, 2], "group2":["A", "B", "C", "A", "A", "B", "C", "B", "A", "C"]}
df = pd.DataFrame(data=data)
sns.countplot(data=df, x="group1", hue="group2")
plt.show()
Output:
I want to add another X ticks in the same graph, summerizng values acorss all other xticks (A value would be 4, B value would be 3, C value would be 3).
How can I do it?
I was trying to find an elegantly looking solution to your request, but have only come to this yet:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
data = {"group1":[1, 2, 3, 1, 2, 3, 1, 1, 2, 2],
"group2":["A", "B", "C", "A", "A", "B", "C", "B", "A", "C"]}
df = pd.DataFrame(data=data)
g1 = sns.countplot(data=df, x="group1", hue="group2")
count_labels = np.repeat(df["group2"].value_counts().values, # repeat group2 category counts
3) # for number of group1 categories/x-ticks
g2 = g1.twiny() # add twin axes with shared y-axis
g2.set_xticks([p.get_x() for p in g1.patches]) # place ticks at where g1 bars are
g2.set_xticklabels(count_labels) # assign tick labels
g2.set_xlabel("group2 category count")
g2.xaxis.set_ticks_position("bottom")
g2.xaxis.set_label_position("bottom")
g2.spines["bottom"].set_position(("axes", -0.2))
g2.spines["bottom"].set_visible(False)
plt.tick_params(which="both", top=False)
This is what it looks like:
So I thought you might rather want to annotate the bars:
for p, label in zip(g1.patches, count_labels):
g1.annotate(label, (p.get_x()+0.1, 0.1))
And it looks like this:
In case you want to use subplots:
fig, axes = plt.subplots(2, 1)
g1 = sns.countplot(data=df, x="group1", hue="group2", ax=axes[0])
g2 = sns.countplot(data=df, x="group2", ax=axes[1])
This would look this way:

How do I add numbers to each subset in Wolfram mathematica?

Say I have a deck of 52 cards. I now remove two cards from the deck, say it is Diamond 2 and 4. I now create a subset {5} meaning I print every 5 card combination of the 50 cards I have left.
How do I now add back both the diamond 2 and 4 into each subset i.e. each set of 5 card combinations?
Update Use resource function PlayingCardGraphic to generate graphic
Converting to the right format is a bit messy, would have been easier if the ranks were generated in a different way.
newHands =
Subsets[deckPart, {5}] // Map[Join[#, cardsToRemove] & /* RandomSample];
hand = newHands // RandomChoice
(hand //
Map[StringSplit[#,
x : DigitCharacter .. | {"J", "Q", "K", "A"} :> x] &]) /. {v_,
s_} :> {If[MemberQ[{"J", "Q", "K", "A"}, v], v, ToExpression#v],
s} //
ResourceFunction["PlayingCardGraphic"][#, "CardSpreadAngle" -> .8] &
The number of 5 card subsets is
50!/(5! 45! = 2118760
it takes ~2.8s to compute and ~10s to display in the notebook on my machine.
suits = ToString /# {\[SpadeSuit], \[HeartSuit], \[DiamondSuit], \[ClubSuit]}
ranks = CharacterRange["2", "9"]~Join~{"10", "J", "Q", "K", "A"}
deck = Outer[StringJoin, ranks, suits] // Flatten // RandomSample
cardsToRemove = {"2\[DiamondSuit]", "4\[DiamondSuit]"}
deckPart = deck // DeleteCases[Alternatives ## cardsToRemove]
Subsets[deckPart, {5}] // Map[Join[#, cardsToRemove] & /* RandomSample]

How to make Horizontal Bar in pygal with labels on y?

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:

How to change jqplot series display order/logic

Can someone please advise how can I make jqplot charts display series a little bit differently (I am referring to the logic / order not the design).
For example lets say I have something like this:
var series1 = [1, 2, 3];
var series2 = [4, 5, 6];
var series3 = [7, 8, 9];
var ticks = ['JAN','FEB','MAR'];
The standard plotting will place the first value of every series array in 'JAN', the second in 'FEB' and the third in 'MAR'.
I want to display the entire series1 in 'JAN', series2 in 'FEB' and series3 in 'MAR'.
The arrays may not even be of the same size (series2 and series3 may have more or less elements than series1).
Any advice is apreciated,
Thank you!

Creating multiple distinct path elements in D3JS

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);
});

Resources