A map of the sky that uses an azimuthal equidistant projection with star data. Longitudes and latitudes for the geo projection are obtained from declination and right ascension respectively (longitude is also inverted, because, unlike the earth globe, the celestial sphere is seen from the inside).
The boreal (northern) sky is shown at left, while the austral (southern) at right. Because right ascension is given in hours, both maps are divided in 24 slices. A circle is shown every 10 degrees of declination.
Star size indicates magnitude. Bigger circles depict brighter stars.
(function() {
var graticule, height, magnitude, map_austral, map_boreal, maps, path_generator_austral, path_generator_boreal, projection_austral, projection_boreal, svg, width, zoom;
svg = d3.select('svg');
width = svg[0][0].getBoundingClientRect().width;
height = svg[0][0].getBoundingClientRect().height;
projection_boreal = d3.geo.azimuthalEquidistant().scale(150).rotate([180, -90, 0]).center([0, 0]).translate([width / 4 + 4.35, height / 2]).precision(.1).clipAngle(90 + 1e-3);
projection_austral = d3.geo.azimuthalEquidistant().scale(150).rotate([0, 90, 0]).center([0, 0]).translate([3 * width / 4 - 4.35, height / 2]).precision(.1).clipAngle(90 + 1e-3);
graticule = d3.geo.graticule().minorStep([15, 10]).majorStep([90, 10]);
path_generator_boreal = d3.geo.path().projection(projection_boreal);
path_generator_austral = d3.geo.path().projection(projection_austral);
/* create maps groups
*/
maps = svg.append('g');
map_boreal = maps.append('g').attr('id', 'map_boreal');
map_austral = maps.append('g').attr('id', 'map_austral');
/* draw the graticules
*/
map_boreal.append('path').datum(graticule).attr('class', 'graticule').attr('d', path_generator_boreal);
map_austral.append('path').datum(graticule).attr('class', 'graticule').attr('d', path_generator_austral);
/* define a zoom behavior
*/
zoom = d3.behavior.zoom().scaleExtent([1, 20]).on('zoom', function() {
return maps.attr('transform', "translate(" + (zoom.translate()) + ")scale(" + (zoom.scale()) + ")");
});
/* bind the zoom behavior to the main SVG
*/
svg.call(zoom);
/* define a scale for magnitude
*/
magnitude = d3.scale.quantize().domain([-1, 5]).range([7, 6, 5, 4, 3, 2, 1]);
d3.csv('stars.csv', function(data) {
map_boreal.selectAll('.star').data(data.filter(function(d) {
return +d.dec_deg > 0;
})).enter().append('circle').attr('class', 'star').attr('r', function(d) {
return magnitude(+d.magnitude) / 2;
}).attr('transform', function(d) {
var lat, lon, x, y, _ref;
lat = +d.dec_deg + +d.dec_min / 60 + +d.dec_sec / 3600;
lon = (+d.RA_hour + +d.RA_min / 60 + +d.RA_sec / 3600) * (360 / 24);
_ref = projection_boreal([-lon, lat]), x = _ref[0], y = _ref[1];
return "translate(" + x + "," + y + ")";
});
return map_austral.selectAll('.star').data(data.filter(function(d) {
return +d.dec_deg <= 0;
})).enter().append('circle').attr('class', 'star').attr('r', function(d) {
return magnitude(+d.magnitude) / 2;
}).attr('transform', function(d) {
var lat, lon, x, y, _ref;
lat = +d.dec_deg + +d.dec_min / 60 + +d.dec_sec / 3600;
lon = (+d.RA_hour + +d.RA_min / 60 + +d.RA_sec / 3600) * (360 / 24);
_ref = projection_austral([-lon, lat]), x = _ref[0], y = _ref[1];
return "translate(" + x + "," + y + ")";
});
});
}).call(this);
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Sky</title>
<link type="text/css" href="index.css" rel="stylesheet"/>
<script src="//d3js.org/d3.v3.min.js"></script>
</head>
<body>
<svg width="960" height="500">
</svg>
</body>
<script src="index.js"></script>
</html>
svg = d3.select('svg')
width = svg[0][0].getBoundingClientRect().width
height = svg[0][0].getBoundingClientRect().height
# projection = d3.geo.mercator()
# .scale(2800)
# .translate([50, 2620])
# .precision(0.1)
# projection = d3.geo.albers()
# .center([14, 34])
# .rotate([-14, 0])
# .parallels([38, 61])
# .scale(2100)
projection_boreal = d3.geo.azimuthalEquidistant()
.scale(150)
.rotate([180,-90,0])
.center([0, 0])
.translate([width / 4 + 4.35, height / 2])
.precision(.1)
.clipAngle(90 + 1e-3)
projection_austral = d3.geo.azimuthalEquidistant()
.scale(150)
.rotate([0,90,0])
.center([0, 0])
.translate([3*width / 4 - 4.35, height / 2])
.precision(.1)
.clipAngle(90 + 1e-3)
# sky_projection = (lambda, phi) ->
# [x, y] = geo_projection(lambda, phi)
# return [x, -y]
graticule = d3.geo.graticule()
.minorStep([15,10])
.majorStep([90,10])
path_generator_boreal = d3.geo.path()
.projection(projection_boreal)
path_generator_austral = d3.geo.path()
.projection(projection_austral)
### create maps groups ###
maps = svg.append('g')
map_boreal = maps.append('g')
.attr('id', 'map_boreal')
map_austral = maps.append('g')
.attr('id', 'map_austral')
### draw the graticules ###
map_boreal.append('path')
.datum(graticule)
.attr('class', 'graticule')
.attr('d', path_generator_boreal)
map_austral.append('path')
.datum(graticule)
.attr('class', 'graticule')
.attr('d', path_generator_austral)
### define a zoom behavior ###
zoom = d3.behavior.zoom()
.scaleExtent([1,20]) # min-max zoom
.on 'zoom', () ->
# whenever the user zooms,
# modify translation and scale of the zoom group accordingly
maps.attr('transform', "translate(#{zoom.translate()})scale(#{zoom.scale()})")
### bind the zoom behavior to the main SVG ###
svg.call(zoom)
### define a scale for magnitude ###
magnitude = d3.scale.quantize()
.domain([-1,5])
.range([7,6,5,4,3,2,1])
d3.csv 'stars.csv', (data) ->
map_boreal.selectAll('.star')
.data(data.filter((d) -> +d.dec_deg > 0))
.enter().append('circle')
.attr('class', 'star')
.attr('r', (d) -> magnitude(+d.magnitude)/2)
.attr 'transform', (d) ->
lat = +d.dec_deg + +d.dec_min/60 + +d.dec_sec/3600
lon = (+d.RA_hour + +d.RA_min/60 + +d.RA_sec/3600)*(360/24)
[x, y] = projection_boreal([-lon, lat])
return "translate(#{x},#{y})"
map_austral.selectAll('.star')
.data(data.filter((d) -> +d.dec_deg <= 0))
.enter().append('circle')
.attr('class', 'star')
.attr('r', (d) -> magnitude(+d.magnitude)/2)
.attr 'transform', (d) ->
lat = +d.dec_deg + +d.dec_min/60 + +d.dec_sec/3600
lon = (+d.RA_hour + +d.RA_min/60 + +d.RA_sec/3600)*(360/24)
[x, y] = projection_austral([-lon, lat])
return "translate(#{x},#{y})"
body {
background: #1a055c;
}
.star {
fill: white;
}
.graticule {
fill: none;
stroke: white;
stroke-width: 0.2px;
vector-effect: non-scaling-stroke;
}
body
background: #1A055C
.star
fill: white
.graticule
fill: none
stroke: white
stroke-width: .2px
vector-effect: non-scaling-stroke