Primeiro de tudo, obrigado por todas as respostas e comentários. Infelizmente, as ferramentas existentes não eram totalmente compatíveis com as versões mais recentes do QGIS e ArcGIS. Portanto, criei minha própria solução usando a ferramenta indicada por @polygeo, o plug-in QGIS de @Alexandre e o nome do algoritmo (mapa de quatro cores) de @Jens.
Aqui está o meu código para os interessados (para o ArcGIS, mas a segunda parte também pode ser usada no QGIS).
arcpy.MakeFeatureLayer_management(fc, fc[:-4]+ "_lyr" )
try:
arcpy.AddField_management(fc[:-4] + "_lyr", "color", "SHORT")
except:
print "field alread exists"
arcpy.CalculateField_management(fc[:-4] + "_lyr", "color", "10" , "PYTHON")
arcpy.PolygonNeighbors_analysis(fc[:-4] + "_lyr", fc[:-4] + "_tb.dbf" )
graph = []
cursor=arcpy.da.SearchCursor( fc[:-4] + "_tb.dbf" , ("src_FID","nbr_FID") )
for row in cursor:
graph.append(row)
pols = arcpy.da.UpdateCursor(fc[:-4] + "_lyr", ("OID@","color"))
colored = []
for pol in pols:
nbrs = [ second for first, second in graph if first == pol[0]]
usedcolors = []
for nbr in nbrs:
usedcolors += [second for first, second in colored if first == nbr]
pol[1]=[color for color in range(10) if color not in usedcolors][0]
colored.append(pol)
pols.updateRow(pol)
Observe que o algoritmo não garante que apenas 4 cores sejam usadas: embora tenha sido comprovado que a solução existe, a "força bruta" é necessária para alcançá-la. No meu caso, eu tenho 7 cores que são pequenas o suficiente. O script pode ter um loop adicional até que a solução seja encontrada, mas eu preciso fazer isso por centenas de mapas e 7 cores.