layer2img.py (4136B) - Raw
1 #!/usr/bin/python3 2 """ 3 Convert PostGIS geometries to an image. To scale. 4 5 Accepts a few geometry fine-tuning parameters. 6 """ 7 8 import argparse 9 import geopandas 10 import psycopg2 11 from matplotlib import rc 12 import matplotlib.pyplot as plt 13 14 CMAP = 'tab20c' # 'Set3' # is nice too 15 PSQL_CREDS = "host=127.0.0.1 dbname=osm user=osm password=osm" 16 COLORS = { 17 'black': '#000000', 18 'green': '#1b9e77', 19 'orange': '#d95f02', 20 'purple': '#7570b3', 21 } 22 # see `NOTICE` in the LaTeX document; this is the width of the main text block. 23 TEXTWIDTH_CM = 12.12364 24 25 QUADRANTS = {'tr':1, 'tl':2, 'bl':3, 'br':4} 26 27 def color(string): 28 return COLORS[string if string else 'black'] 29 30 31 def inch(cm): 32 return cm / 2.54 33 34 35 def parse_args(): 36 kwcolor = {'type': color, 'default': 'black'} 37 parser = argparse.ArgumentParser(description=__doc__) 38 parser.add_argument('--g1-select') 39 parser.add_argument('--g1-linestyle') 40 parser.add_argument('--g1-label') 41 parser.add_argument('--g1-color', **kwcolor) 42 parser.add_argument('--g2-select') 43 parser.add_argument('--g2-linestyle') 44 parser.add_argument('--g2-label') 45 parser.add_argument('--g2-color', **kwcolor) 46 parser.add_argument('--g3-select') 47 parser.add_argument('--g3-linestyle') 48 parser.add_argument('--g3-label') 49 parser.add_argument('--g3-color', **kwcolor) 50 parser.add_argument('--legend', 51 help="Legend location, following matplotlib rules", default='best') 52 parser.add_argument('--widthdiv', default=1, type=float, 53 help="Divide the width by this number " 54 "(useful when two images are laid horizontally " 55 "in the resulting file") 56 parser.add_argument('--quadrant', choices=QUADRANTS.keys(), 57 help="Image is comprised of 4 quadrants. This variable, " 58 "when non-empty, will clip and return the requested quadrant") 59 parser.add_argument('--outfile', metavar='<file>', 60 help="If unset, displayed on the screen") 61 return parser.parse_args() 62 63 64 def read_layer(select, width, maybe_quadrant): 65 if not select: 66 return 67 way = "way" 68 if maybe_quadrant: 69 way = "wm_quadrant(way, {})".format(QUADRANTS[maybe_quadrant]) 70 71 conn = psycopg2.connect(PSQL_CREDS) 72 sql = "SELECT {way} as way1 FROM {select}".format(way=way, select=select) 73 74 return geopandas.read_postgis(sql, con=conn, geom_col='way1') 75 76 77 def plot_args(geom, color, maybe_linestyle, maybe_label): 78 if geom is None: 79 return 80 81 # polygons either have fillings or lines 82 if geom.geom_type[0] == 'Polygon': 83 if maybe_linestyle: 84 return { 85 'edgecolor': 'black', 86 'linestyle': maybe_linestyle, 87 'color': (0, 0, 0, 0), 88 } 89 else: 90 return {'cmap': CMAP, 'alpha': .25} 91 92 r = {'color': color} 93 if maybe_linestyle == 'invisible': 94 r['color'] = (0, 0, 0, 0) 95 elif maybe_linestyle: 96 r['linestyle'] = maybe_linestyle 97 98 if maybe_label: 99 r['label'] = '\\normalfont %s' % maybe_label 100 101 return r 102 103 104 def main(): 105 args = parse_args() 106 width = TEXTWIDTH_CM / args.widthdiv 107 g1 = read_layer(args.g1_select, width, args.quadrant) 108 g2 = read_layer(args.g2_select, width, args.quadrant) 109 g3 = read_layer(args.g3_select, width, args.quadrant) 110 c1 = plot_args(g1, args.g1_color, args.g1_linestyle, args.g1_label) 111 c2 = plot_args(g2, args.g2_color, args.g2_linestyle, args.g2_label) 112 c3 = plot_args(g3, args.g3_color, args.g3_linestyle, args.g3_label) 113 114 rc('text', usetex=True) 115 rc('text.latex', preamble='\\usepackage{numprint}\n') 116 fig, ax = plt.subplots(constrained_layout=True) 117 fig.set_figwidth(inch(width)) 118 119 g1 is not None and g1.plot(ax=ax, linewidth=.75, **c1) 120 g2 is not None and g2.plot(ax=ax, linewidth=.75, **c2) 121 g3 is not None and g3.plot(ax=ax, linewidth=.75, **c3) 122 123 ax.legend(loc=args.legend, frameon=False) 124 ax.axis('off') 125 ax.margins(0, 0) 126 if args.outfile: 127 fig.savefig(args.outfile, bbox_inches='tight', dpi=600) 128 else: 129 plt.show() 130 131 132 if __name__ == '__main__': 133 main()