Almagest – Polar plotting the stars – R

Final code:

library(ggplot2)

dataset <- read.csv('Almagest.csv')

summary(dataset)
head(dataset)
nrow(dataset)

dataset$Longitudes <- (dataset$Longitude.degree * 60 + dataset$Longitude.minute) / 60
dataset$Latitudes <- (dataset$Latitude.degree * 60 + dataset$Latitude.minute) / 60
head(dataset)

dataset$Longitudes <- dataset$Longitudes * pi / 180
dataset$Latitudes <- 90 - dataset$Latitudes

constellation <- 'Ursa Major'
dataset_highlight <- dataset[dataset$Constellation == constellation,]

longitude_ticks <- seq(0, 2, 0.25) * pi
longitude_labels <- c('0', '45', '90', '135', '180', '225', '270', '315', '360')

ggplot(dataset, aes(x = dataset$Longitudes, y = dataset$Latitudes))+
  geom_point(size = 0.7)+
  geom_point(data = dataset_highlight,
             aes(dataset_highlight$Longitudes, dataset_highlight$Latitudes),
             size = 1.3, colour = 'red',
             shape = 17)+
  ggtitle('Ptolemy star chart')+
  theme(plot.title = element_text(hjust = 0.5),
        panel.background = element_rect(fill = 'white', color = 'grey'),
        panel.grid.major = element_line(color = 'lightgrey'),
        panel.grid.minor = element_line(color = 'lightgrey'))+
  scale_x_continuous(breaks = longitude_ticks, labels = longitude_labels)+
  scale_y_continuous(limits = c(0,91))+
  xlab('Longitudes: 0 - 360 degrees')+
  ylab('Latitudes: 0 - 90 degrees')+
  coord_polar(start = -0.3, direction = -1)+
  ggsave('starchart.jpg')

starchart6 - R


Ptolemy’s Almagest is one of the most important scientific works of all time. It gives us the stars. Well… it shows us where to find them.

It is quite certain that us humans gazed at the stars long before written history. They drew constellations. When they learnt geometry and mathematics they noted their coordinates.

Then came Claudius Ptolemy, a Greek astronomer-mathematician who lived in Alexandria, Egypt in the second century. He decided to map the sky and collect the data into one book which can be used by future generations. He spent night after night measuring the positions of the stars and collected the coordinates into a book which we now call The Almagest. This book was used for centuries, astronomers had a record which helped them to find stars and constellations quickly.

The Almagest slowly lost its importance in the Renaissance. Its geocentric model was proved wrong, the astronomers of the time found errors in the star charts and created new, more precise charts.

However the coordinates of stars change very little over two thousand years and even though some of those coordinates are wrong (after all he wrote those down at night, out in the open) we can use it to map the stars. Let’s do some plotting and see how this almost 2 millennia old data looks on computer.

You can find the first printed edition in Latin on Wikipedia however for this exercise I’ll use data from the 1915 revision.

But first here is an illustration of the star chart made by Albrecht Dürer in 1515, (The Metropolitan Museum of Art). Mine won’t be anything near this beautiful but hopefully the distribution and position of the constellations will be similar.

Durer

In the Almagest there are 1028 stars grouped into 48 constellations. The modern edition has 3 catalogues, each catalogue has all the coordinates. I am going to use Catalogue II which starts at page 51 and contains the original data from Ptolemy. It shows the name of the constellation then the star coordinates in the constellation.

The copied the coordinates into a CSV file, you can download it from here: https://github.com/zmraz/data-science/tree/master/datasets

I start with the imports, load the dataset and print out a few details.


library(ggplot2)

dataset <- read.csv('Almagest.csv')
summary(dataset)
head(dataset)
nrow(dataset)
> summary(dataset)
    Constellation Longitude.degree Longitude.minute Latitude.degree Latitude.minute
 Aquarius  : 45   Min.   :  0.0    Min.   : 0.00    Min.   : 0.00   Min.   : 0.00
 Argo Navis: 45   1st Qu.: 64.0    1st Qu.:10.00    1st Qu.: 8.00   1st Qu.:10.00
 Taurus    : 44   Median :170.0    Median :20.00    Median :21.00   Median :20.00
 Orion     : 38   Mean   :166.6    Mean   :22.41    Mean   :25.93   Mean   :22.57
 Pisces    : 38   3rd Qu.:257.2    3rd Qu.:40.00    3rd Qu.:41.00   3rd Qu.:40.00
 Centaurus : 37   Max.   :359.0    Max.   :50.00    Max.   :87.00   Max.   :50.00
 (Other)   :781
> head(dataset)
  Constellation Longitude.degree Longitude.minute Latitude.degree Latitude.minute
1    Ursa Minor               60               10              66               0
2    Ursa Minor               62               30              70               0
3    Ursa Minor               70               10              74              20
4    Ursa Minor               89               40              75              40
5    Ursa Minor               93               40              77              40
6    Ursa Minor              107               10              72              50
> nrow(dataset)
[1] 1028

There are 1028 rows of data and the coordinates are in four columns, similarly what you can see in the book but I need only two columns of data to plot them.

I am working with degrees and arc minutes here and 1 degree equals to 60 arc minutes. This makes the calculation simple: I multiply the degrees by 60, add the corresponding columns, divide the sums by 60 and assign the value to two new columns. I print out the first 5 rows to see the results.


dataset$Longitudes <- (dataset$Longitude.degree * 60 + dataset$Longitude.minute) / 60
dataset$Latitudes <- (dataset$Latitude.degree * 60 + dataset$Latitude.minute) / 60
head(dataset)
> head(dataset)
  Constellation Longitude.degree Longitude.minute Latitude.degree Latitude.minute Longitudes Latitudes
1    Ursa Minor               60               10              66               0   60.16667  66.00000
2    Ursa Minor               62               30              70               0   62.50000  70.00000
3    Ursa Minor               70               10              74              20   70.16667  74.33333
4    Ursa Minor               89               40              75              40   89.66667  75.66667
5    Ursa Minor               93               40              77              40   93.66667  77.66667
6    Ursa Minor              107               10              72              50  107.16667  72.83333

Now I draw a scatterplot.


longitude_ticks <- seq(0, 2, 0.25) * pi
longitude_labels <- c('0', '45', '90', '135', '180', '225', '270', '315', '360')

ggplot(dataset, aes(x = dataset$Longitudes, y = dataset$Latitudes))+
  geom_point(size = 0.7)+
  ggtitle('Ptolemy star chart')+
  theme(plot.title = element_text(hjust = 0.5),
        panel.background = element_rect(fill = 'white', color = 'grey'),
        panel.grid.major = element_line(color = 'lightgrey'),
        panel.grid.minor = element_line(color = 'lightgrey'))+
  scale_x_continuous(breaks = longitude_ticks, labels = longitude_labels)+
  scale_y_continuous(limits = c(0,91))+
  xlab('Longitudes: 0 - 360 degrees')+
  ylab('Latitudes: 0 - 90 degrees')+
  ggsave('starchart.jpg')

starchart1 - R


Ouch. It doesn’t look like the drawing above at all! The problem is that I need a polar chart to effectively plot the coordinates. In this plot the origo is at left bottom corner but in the polar chart the origo will be the top middle point and the whole scatterplot will be stretched and skewed around it. Before plotting the polar chart I need to do some additional work: convert the longitude into radians.

There is a tutorial about polar charts here: http://mathinsight.org/polar_coordinates

Here is the code for the conversion and the polar plot.


dataset$Longitudes <- dataset$Longitudes * pi / 180

longitude_ticks <- seq(0, 2, 0.25) * pi
longitude_labels <- c('0', '45', '90', '135', '180', '225', '270', '315', '360')

ggplot(dataset, aes(x = dataset$Longitudes, y = dataset$Latitudes))+
  geom_point(size = 0.7)+
  ggtitle('Ptolemy star chart')+
  theme(plot.title = element_text(hjust = 0.5),
        panel.background = element_rect(fill = 'white', color = 'grey'),
        panel.grid.major = element_line(color = 'lightgrey'),
        panel.grid.minor = element_line(color = 'lightgrey'))+
  scale_x_continuous(breaks = longitude_ticks, labels = longitude_labels)+
  scale_y_continuous(limits = c(0,91))+
  xlab('Longitudes: 0 - 360 degrees')+
  ylab('Latitudes: 0 - 90 degrees')+
  coord_polar()+
  ggsave('starchart.jpg')

starchart2 - R


It is certainly a polar plot now and yet I cannot see the same distribution and form like in the illustration above. It is because when Ptolemy charted the stars he measured the latitudes upwards from the horizon (i.e. his 0 degree was at the horizon and the zenith was at 90 degrees) while the polar plot is showing 0 degree in the middle (the zenith). I need to invert the latitude values.

I simply subtract each latitude value from 90 and replot with the new latitudes.


dataset$Latitudes <- 90 - dataset$Latitudes

longitude_ticks <- seq(0, 2, 0.25) * pi
longitude_labels <- c('0', '45', '90', '135', '180', '225', '270', '315', '360')

ggplot(dataset, aes(x = dataset$Longitudes, y = dataset$Latitudes))+
  geom_point(size = 0.7)+
  ggtitle('Ptolemy star chart')+
  theme(plot.title = element_text(hjust = 0.5),
        panel.background = element_rect(fill = 'white', color = 'grey'),
        panel.grid.major = element_line(color = 'lightgrey'),
        panel.grid.minor = element_line(color = 'lightgrey'))+
  scale_x_continuous(breaks = longitude_ticks, labels = longitude_labels)+
  scale_y_continuous(limits = c(0,91))+
  xlab('Longitudes: 0 - 360 degrees')+
  ylab('Latitudes: 0 - 90 degrees')+
  coord_polar()+
  ggsave('starchart.jpg')

starchart3 - R


It looks really promising. Let’s highlight the constellation Aries, which is on the top in Dürer’s illustration. If you want to check another constellation just change the value of the ‘constellation’ variable.


dataset$Latitudes <- 90 - dataset$Latitudes

constellation <- 'Aries'
dataset_highlight <- dataset[dataset$Constellation == constellation,]

longitude_ticks <- seq(0, 2, 0.25) * pi
longitude_labels <- c('0', '45', '90', '135', '180', '225', '270', '315', '360')

ggplot(dataset, aes(x = dataset$Longitudes, y = dataset$Latitudes))+
  geom_point(size = 0.7)+
  geom_point(data = dataset_highlight,
             aes(dataset_highlight$Longitudes, dataset_highlight$Latitudes),
             size = 1.3, colour = 'red',
             shape = 17)+
  ggtitle('Ptolemy star chart')+
  theme(plot.title = element_text(hjust = 0.5),
        panel.background = element_rect(fill = 'white', color = 'grey'),
        panel.grid.major = element_line(color = 'lightgrey'),
        panel.grid.minor = element_line(color = 'lightgrey'))+
  scale_x_continuous(breaks = longitude_ticks, labels = longitude_labels)+
  scale_y_continuous(limits = c(0,91))+
  xlab('Longitudes: 0 - 360 degrees')+
  ylab('Latitudes: 0 - 90 degrees')+
  coord_polar()+
  ggsave('starchart.jpg')

starchart4 - R


I am almost there but actually there is a problem. It is hard to see but if you zoom into Dürer’s illustration you can see that all the stars and thus all the constellations are drawn backwards here. If you highlight Ursa Major you will see what I am talking about.

It can be fixed easily, I simply invert the direction of ‘coord_polar’.


dataset$Latitudes <- 90 - dataset$Latitudes

constellation <- 'Aries'
dataset_highlight <- dataset[dataset$Constellation == constellation,]

longitude_ticks <- seq(0, 2, 0.25) * pi
longitude_labels <- c('0', '45', '90', '135', '180', '225', '270', '315', '360')

ggplot(dataset, aes(x = dataset$Longitudes, y = dataset$Latitudes))+
  geom_point(size = 0.7)+
  geom_point(data = dataset_highlight,
             aes(dataset_highlight$Longitudes, dataset_highlight$Latitudes),
             size = 1.3, colour = 'red',
             shape = 17)+
  ggtitle('Ptolemy star chart')+
  theme(plot.title = element_text(hjust = 0.5),
        panel.background = element_rect(fill = 'white', color = 'grey'),
        panel.grid.major = element_line(color = 'lightgrey'),
        panel.grid.minor = element_line(color = 'lightgrey'))+
  scale_x_continuous(breaks = longitude_ticks, labels = longitude_labels)+
  scale_y_continuous(limits = c(0,91))+
  xlab('Longitudes: 0 - 360 degrees')+
  ylab('Latitudes: 0 - 90 degrees')+
  coord_polar(direction = -1)+
  ggsave('starchart.jpg')

starchart5 - R


One last thing, Aries is a bit left from the top, I need to adjust the starting point of the drawing in ‘coord_polar’.

I also switch to highlight Ursa Major, as it keeps a slight distance from all the other constellations so it is easier to see it.


dataset$Latitudes <- 90 - dataset$Latitudes

constellation <- 'Ursa Major'
dataset_highlight <- dataset[dataset$Constellation == constellation,]

longitude_ticks <- seq(0, 2, 0.25) * pi
longitude_labels <- c('0', '45', '90', '135', '180', '225', '270', '315', '360')

ggplot(dataset, aes(x = dataset$Longitudes, y = dataset$Latitudes))+
  geom_point(size = 0.7)+
  geom_point(data = dataset_highlight,
             aes(dataset_highlight$Longitudes, dataset_highlight$Latitudes),
             size = 1.3, colour = 'red',
             shape = 17)+
  ggtitle('Ptolemy star chart')+
  theme(plot.title = element_text(hjust = 0.5),
        panel.background = element_rect(fill = 'white', color = 'grey'),
        panel.grid.major = element_line(color = 'lightgrey'),
        panel.grid.minor = element_line(color = 'lightgrey'))+
  scale_x_continuous(breaks = longitude_ticks, labels = longitude_labels)+
  scale_y_continuous(limits = c(0,91))+
  xlab('Longitudes: 0 - 360 degrees')+
  ylab('Latitudes: 0 - 90 degrees')+
  coord_polar(start = -0.3, direction = -1)+
  ggsave('starchart.jpg')

starchart6 - R


And here it is in all its glory! Ptolemy’s data which he collected two thousand years ago is now on my screen. All the constellations of the Zodiac are at the perimeter of the chart, and you can see the denser vertical are where the stars of the Milky Way are.

In the second part I’ll use the k-means machine learning algorithm to see if it can locate the same clusters of stars.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s