I am trying to recreate in QGIS a few diferent sets of constellations. I already have a layer with all the stars I need, with ID and coordinates (downloaded from here astronomyData.zip), and I also have a table with a line for each constellation, and the pairs of stars that need to be connected by ID (link here)

What I need is for some way to have the software look at each pair of IDs, find the coordinate for each star with the same ID the stars layer, and connect each pair with a line.

I feel like this should be easy, but I can't figure out a way.


There doesn't seem to be a simple way to do this with the GUI, because of the (paired) data structure your data have.

However, I found the use case interesting and had attempted a script before the other answer published (although, I didn't published it waiting for other answers using the GUI).

This is the result with an azimuthal projection:

enter image description here

And this is the script I ended up with:

stars = QgsProject.instance().mapLayersByName("stars6")[0]
stars_dict = {str(feature["HIP"]):feature.geometry() for feature in stars.getFeatures()}

# Prepare constellation layer
layer = QgsVectorLayer("MultiLineString?crs={}".format(stars.crs().authid()), "constellations", "memory")
layer.dataProvider().addAttributes([QgsField("name", QVariant.String)])
new_features = list()

constellations_file = open('/path/to/constellationship.fab', 'r') 
for line in constellations_file:
    constellation_name, hip_part = line.split("  ")
    constellation_name = constellation_name.split(" ")[0]
    hip_list = hip_part.strip().split(" ")

    # Build constellation lines
    mls = QgsMultiLineString()
    for start, end in zip(hip_list[::2], hip_list[1::2]):
        if not (start in stars_dict and end in stars_dict):
            print("Pair {}-{} not found in stars layer! Skipping...".format(start, end))
        g = QgsGeometry.fromPolyline([stars_dict[start].get(), stars_dict[end].get()])

    new_feature = QgsFeature()


It creates a segment per each pair of stars; it doesn't create segments with length 0; and, the resulting layer has the corresponding constellation name.

Issues with the data

  • In constellationship.fab, the line CMa 17... doesn't have two spaces after number of points (CMa 17 33160 34045...). I had to adjust it manually (find the modified file here).
  • Star 33165 does not exist!


  1. Load the stars6.shp file into QGIS.
  2. Adjust the /path/to/constellationship.fab to reflect your local path. (Use the modified file mentioned above when talking about issues with the data.)
  3. Run the script from the QGIS Python console.
  • This works great! I tried it with other .fab constellation files, and after a thorough clean up of the files to remove extra spaces it worked like a charm. One small issue I had was that as you say, it doesnt create segments with length 0. Could it be modified to create these segments? Some cultures had 1 star constelations (for ex chinese) Aug 10 '20 at 23:48
  • 1
    Well, what I meant was that, for instance, for a constellation like Aps 2 72370 81065 81065 81852, the script creates a line with 2 segments: [72370-81065, 81065-81852], instead of 3 segments: [72370-81065, 81065-81065, 81065-81852]. So, if a constellation has a definition like 044 1 101772 101772, the script actually generates a line with this segment: [101772-101772]. To visualize it (as a point, of course), you can add a symbol layer and use Geometry Generator to show the end point. Aug 11 '20 at 3:13
  • Great! By the way, I just want to share the way another person did the same thing, but only in Python (no QGIS) link . Is this code usable in QGIS? She didnt use star data from the same origin, but she did use the same .fab files. Aug 11 '20 at 10:15
  • Of course, you can use Python in QGIS to parse text files. Aug 11 '20 at 14:01

I dont think this is 100 % correct but maybe you can fix it or understand whats causing it? Some constellations look a bit weird with line going across the map.

import csv

pointlyr = QgsProject.instance().mapLayersByName('StarsNamed2')[0]
pointdict = {f['Stars_Named_HIP']:QgsPoint(f.geometry().asPoint()) for f in pointlyr.getFeatures()} # Create a dictionary with star_id (?) as key and QgsPoint as value
orderfile = '/home/bera/Downloads/Linespoints/constellationship.fab'

#Create a line layer in memory
vl = QgsVectorLayer("LineString?crs='EPSG:4326'&index=yes", "constellations_temp", "memory")
provider = vl.dataProvider()

errorlist = []

with open(orderfile, newline='') as csvfile: #For each line in the text file find the matching point in the dictionary, store in a list and create a line
    spamreader = csv.reader(csvfile, delimiter=' ', quotechar='|')
    for row in spamreader:
        gLine = []
        for star in row[3:]:
                if float(star) in pointdict:
        gLine = QgsGeometry.fromPolyline(gLine)
        f = QgsFeature()
print(errorlist) #The text file isnt perfect, one error line

enter image description here

  • Thanks! This kind of works. The lines going across the map are not a problem, as I will be using a Azimuthal_Equidistant projection that eliminates this issue, but the constellations still have extra lines. The issue is that the .fab file has for each constellation pairs of points. For example line 3 "Scl 3 116231 4577 4577 115102 115102 116231" has 3 pairs of points representing 3 lines, but I think the script is making 5 lines. In this case it is not a big issue, because the 2 extra lines are connecting a point to itself, but in other more complex constellations it creates weird extra lines Aug 10 '20 at 10:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.