diff --git a/requirements.txt b/requirements.txt index 47f81745..32d564e5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,3 +5,4 @@ pypng==0.0.18 PyPlatec==1.4.0 protobuf==3.0.0a3 six==1.10.0 +matplotlib \ No newline at end of file diff --git a/setup.py b/setup.py index 22866c32..da0cc8e7 100644 --- a/setup.py +++ b/setup.py @@ -26,7 +26,8 @@ 'console_scripts': ['worldengine=worldengine.cli.main:main'], }, 'install_requires': ['PyPlatec==1.4.0', 'pypng>=0.0.18', 'numpy>=1.9.2, <= 1.10.0.post2', - 'argparse==1.2.1', 'noise==1.2.2', 'protobuf==3.0.0a3'], + 'argparse==1.2.1', 'noise==1.2.2', 'protobuf==3.0.0a3', + 'matplotlib'], 'license': 'MIT License' } diff --git a/tests/blessed_images/generated_blessed_images.py b/tests/blessed_images/generated_blessed_images.py index cb35ce03..d3083329 100644 --- a/tests/blessed_images/generated_blessed_images.py +++ b/tests/blessed_images/generated_blessed_images.py @@ -10,6 +10,7 @@ import os from worldengine.world import * from worldengine.draw import * +from worldengine.draw_plots import * from worldengine.image_io import PNGWriter @@ -27,8 +28,9 @@ def main(blessed_images_dir, tests_data_dir): draw_temperature_levels_on_file(w, "%s/temperature_28070.png" % blessed_images_dir) draw_biome_on_file(w, "%s/biome_28070.png" % blessed_images_dir) draw_scatter_plot_on_file(w, "%s/scatter_28070.png" % blessed_images_dir) + draw_hypsographic_plot_on_file(w, "%s/hypsographic_28070.png" % blessed_images_dir) draw_satellite_on_file(w, "%s/satellite_28070.png" % blessed_images_dir) - draw_ancientmap_on_file(w, "%s/ancientmap_28070_factor3.png" % blessed_images_dir, resize_factor=3) + draw_ancientmap_on_file(w, "%s/ancientmap_28070_factor2.png" % blessed_images_dir, resize_factor=2) img = PNGWriter.rgba_from_dimensions(w.width * 2, w.height * 2, "%s/rivers_28070_factor2.png" % blessed_images_dir) draw_rivers_on_image(w, img, factor=2) diff --git a/tests/draw_test.py b/tests/draw_test.py index 610029be..d45f27b9 100644 --- a/tests/draw_test.py +++ b/tests/draw_test.py @@ -4,6 +4,7 @@ from worldengine.draw import _biome_colors, draw_simple_elevation, elevation_color, \ draw_elevation, draw_riversmap, draw_grayscale_heightmap, draw_ocean, draw_precipitation, \ draw_world, draw_temperature_levels, draw_biome, draw_scatter_plot, draw_satellite +from worldengine.draw_plots import draw_hypsographic_plot from worldengine.biome import Biome from worldengine.world import World from worldengine.image_io import PNGWriter, PNGReader @@ -154,6 +155,11 @@ def test_draw_scatter_plot(self): draw_scatter_plot(w, 512, target) self._assert_img_equal("scatter_28070", target) + def test_draw_hypsographic_plot(self): + w = World.open_protobuf("%s/seed_28070.world" % self.tests_data_dir) + plot = draw_hypsographic_plot(w) + # self._assert_img_equal("hypsographic_28070", target) # TODO: find way to compare these + def test_draw_satellite(self): w = World.open_protobuf("%s/seed_28070.world" % self.tests_data_dir) target = PNGWriter.rgba_from_dimensions(w.width, w.height) diff --git a/tests/drawing_functions_test.py b/tests/drawing_functions_test.py index 67496e23..31f0e5c5 100644 --- a/tests/drawing_functions_test.py +++ b/tests/drawing_functions_test.py @@ -13,9 +13,10 @@ def setUp(self): self.w = World.open_protobuf("%s/seed_28070.world" % self.tests_data_dir) def test_draw_ancient_map(self): - target = PNGWriter.rgba_from_dimensions(self.w.width * 3, self.w.height * 3) - draw_ancientmap(self.w, target, resize_factor=3) - self._assert_img_equal("ancientmap_28070_factor3", target) + factor = int(2) + target = PNGWriter.rgba_from_dimensions(self.w.width * factor, self.w.height * factor) + draw_ancientmap(self.w, target, resize_factor=factor) + self._assert_img_equal("ancientmap_28070_factor%i" % factor, target) def test_gradient(self): self._assert_are_colors_equal((10, 20, 40), diff --git a/tox.ini b/tox.ini index b91be59e..99de69f8 100644 --- a/tox.ini +++ b/tox.ini @@ -11,6 +11,7 @@ deps = six pypng h5py + matplotlib [testenv] deps = diff --git a/worldengine/cli/main.py b/worldengine/cli/main.py index f07bd339..8ddee820 100644 --- a/worldengine/cli/main.py +++ b/worldengine/cli/main.py @@ -8,6 +8,7 @@ draw_precipitation_on_file, draw_grayscale_heightmap_on_file, draw_simple_elevation_on_file, \ draw_temperature_levels_on_file, draw_riversmap_on_file, draw_scatter_plot_on_file, \ draw_satellite_on_file, draw_icecaps_on_file +from worldengine.draw_plots import draw_hypsographic_plot_on_file from worldengine.plates import world_gen, generate_plates_simulation from worldengine.imex import export from worldengine.step import Step @@ -84,18 +85,27 @@ def generate_rivers_map(world, filename): draw_riversmap_on_file(world, filename) print("+ rivers map generated in '%s'" % filename) -def draw_scatter_plot(world, filename): - draw_scatter_plot_on_file(world, filename) - print("+ scatter plot generated in '%s'" % filename) -def draw_satellite_map(world, filename): +def generate_satellite_map(world, filename): draw_satellite_on_file(world, filename) print("+ satellite map generated in '%s'" % filename) -def draw_icecaps_map(world, filename): + +def generate_icecaps_map(world, filename): draw_icecaps_on_file(world, filename) print("+ icecap map generated in '%s'" % filename) + +def generate_scatter_plot(world, filename): + draw_scatter_plot_on_file(world, filename) + print("+ scatter plot generated in '%s'" % filename) + + +def generate_hypsographic_plot(world, filename): + draw_hypsographic_plot_on_file(world, filename) + print("+ hypsographic plot generated in '%s'" % filename) + + def generate_plates(seed, world_name, output_dir, width, height, num_plates=10): """ @@ -317,12 +327,14 @@ def main(): g_generate.add_argument('--not-fade-borders', dest='fade_borders', action="store_false", help="Not fade borders", default=True) - g_generate.add_argument('--scatter', dest='scatter_plot', - action="store_true", help="generate scatter plot") g_generate.add_argument('--sat', dest='satelite_map', action="store_true", help="generate satellite map") g_generate.add_argument('--ice', dest='icecaps_map', action="store_true", help="generate ice caps map") + g_generate.add_argument('--scatter', dest='scatter_plot', + action="store_true", help="generate scatter plot") + g_generate.add_argument('--hypsographic', dest='hypsographic_plot', + action="store_true", help="generate hypsographic curve") # ----------------------------------------------------- g_ancient_map = parser.add_argument_group( @@ -468,7 +480,9 @@ def main(): for x in range(0,len(humids)): humids[x] = 1 - float(humids[x]) if args.scatter_plot and not generation_operation: - usage(error="Scatter plot can be produced only during world generation") + usage(error="Scatter plot can be produced only during world generation.") + if args.hypsographic_plot and not generation_operation: + usage(error="Hypsograpic curve can be produced only during world generation.") print('Worldengine - a world generator (v. %s)' % VERSION) print('-----------------------') @@ -486,6 +500,7 @@ def main(): print(' icecaps heightmap : %s' % args.icecaps_map) print(' rivers map : %s' % args.rivers_map) print(' scatter plot : %s' % args.scatter_plot) + print(' hypsographic plot : %s' % args.hypsographic_plot) print(' satellite map : %s' % args.satelite_map) print(' fade borders : %s' % args.fade_borders) if args.temps: @@ -542,15 +557,18 @@ def main(): if args.rivers_map: generate_rivers_map(world, '%s/%s_rivers.png' % (args.output_dir, world_name)) - if args.scatter_plot: - draw_scatter_plot(world, - '%s/%s_scatter.png' % (args.output_dir, world_name)) if args.satelite_map: - draw_satellite_map(world, + generate_satellite_map(world, '%s/%s_satellite.png' % (args.output_dir, world_name)) if args.icecaps_map: - draw_icecaps_map(world, + generate_icecaps_map(world, '%s/%s_icecaps.png' % (args.output_dir, world_name)) + if args.scatter_plot: + generate_scatter_plot(world, + '%s/%s_scatter.png' % (args.output_dir, world_name)) + if args.hypsographic_plot: + generate_hypsographic_plot(world, + '%s/%s_hypsographic.png' % (args.output_dir, world_name)) elif operation == 'plates': print('') # empty line diff --git a/worldengine/draw.py b/worldengine/draw.py index 663c0c1a..5e3a7fe4 100644 --- a/worldengine/draw.py +++ b/worldengine/draw.py @@ -732,7 +732,7 @@ def draw_scatter_plot(world, size, target): ny = (size - 1) * ((p - min_humidity) / humidity_delta) target.set_pixel(int(nx), (size - 1) - int(ny), (r, 128, b, 255)) - + # ------------- # Draw on files diff --git a/worldengine/draw_plots.py b/worldengine/draw_plots.py new file mode 100644 index 00000000..dfc250f4 --- /dev/null +++ b/worldengine/draw_plots.py @@ -0,0 +1,52 @@ +import numpy +import matplotlib.pyplot as plot + + +def draw_hypsographic_plot(world): + # Will draw a Hypsograhpic plot that contains information about the distribution of elevations in the world. + # y-axis shows the elevation, x-axis shows how often a certain elevation occurs. + # For further details see: + # https://en.wikipedia.org/wiki/Elevation#Hypsography + # http://www.ngdc.noaa.gov/mgg/global/etopo1_surface_histogram.html + + # Set up variables. + sea_level = world.sea_level() + fig = plot.figure() + p = fig.add_subplot(111) + + # Prepare a list of available elevations by putting them into a sorted list, smallest point to highest. + # 0 will refer to sea-level. + y = world.elevation['data'] - sea_level + y = numpy.sort(y, axis=None) # flatten the array and order values by height + + # Corresponding x-values. Inverted so the highest values are left instead of right. x refers to %, hence [0, 100]. + x = numpy.arange(100, 0, -100.0 / y.size) + + # Plot the data. + p.plot(x, y) + + # Cosmetics. + p.set_ylim(y.min(), y.max()) + p.fill_between(x, y.min(), y, color='0.8') + p.set_xlabel("Cumulative Area (% of World's Surface)") + p.set_ylabel("Elevation (no units)") + p.set_title("Hypsographic Curve - %s" % world.name) + + # Draw lines for sea-level, hill-level etc. The lines will get lighter with increasing height. + th = world.elevation['thresholds'] # see generation.py->initialize_ocean_and_thresholds() for details + for i in range(len(th)): + if th[i][1] is None: + continue + color = numpy.interp(i, [0, len(th)], [0, 1.0]) # grayscale values, black to white; white will never be used + p.axhline(th[i][1] - sea_level, color=str(color), linewidth=0.5) + p.text(99, th[i][1] - sea_level, th[i][0], fontsize=8, horizontalalignment='right', verticalalignment='bottom' if th[i][1] - sea_level > 0 else 'top') + + p.set_xticks(range(0, 101, 10)) + + return fig + + +def draw_hypsographic_plot_on_file(world, filename): + fig = draw_hypsographic_plot(world) + fig.savefig(filename) + plot.close(fig)