Skip to content

Commit

Permalink
Completely reworked to make use of matplotlib.
Browse files Browse the repository at this point in the history
  • Loading branch information
tcld committed Nov 19, 2015
1 parent 76e2622 commit 496e3cb
Show file tree
Hide file tree
Showing 8 changed files with 63 additions and 75 deletions.
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ pypng==0.0.18
PyPlatec==1.4.0
protobuf==3.0.0a3
six==1.10.0
matplotlib
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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'
}

Expand Down
1 change: 1 addition & 0 deletions tests/blessed_images/generated_blessed_images.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down
11 changes: 4 additions & 7 deletions tests/draw_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
import numpy
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_hypsographic_plot, \
draw_satellite
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
Expand Down Expand Up @@ -156,12 +156,9 @@ def test_draw_scatter_plot(self):
self._assert_img_equal("scatter_28070", target)

def test_draw_hypsographic_plot(self):
x_bins = 800
y_bins = 600
w = World.open_protobuf("%s/seed_28070.world" % self.tests_data_dir)
target = PNGWriter.grayscale_from_dimensions(x_bins, y_bins, channel_bitdepth=8)
draw_hypsographic_plot(w, target, x_bins, y_bins)
self._assert_img_equal("hypsographic_28070", target)
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)
Expand Down
1 change: 1 addition & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ deps =
six
pypng
h5py
matplotlib

[testenv]
deps =
Expand Down
3 changes: 2 additions & 1 deletion worldengine/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
from worldengine.draw import draw_ancientmap_on_file, draw_biome_on_file, draw_ocean_on_file, \
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_hypsographic_plot_on_file, draw_satellite_on_file, draw_icecaps_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
Expand Down
66 changes: 0 additions & 66 deletions worldengine/draw.py
Original file line number Diff line number Diff line change
Expand Up @@ -734,64 +734,6 @@ def draw_scatter_plot(world, size, target):
target.set_pixel(int(nx), (size - 1) - int(ny), (r, 128, b, 255))


def draw_hypsographic_plot(world, target, x_bins, y_bins):
# 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

assert int(x_bins) > 0 and int(y_bins) > 0, "Hypsographic curve needs more than 0 bins."

# set colors
color_none = target.get_max_colors() # white
color_full = int(color_none / 2) # gray
color_line = 0 # black
color_percent_sep = int(color_none * 0.8) # light-gray

# Prepare a list of available elevations. Scale them to the y-axis and put them into a sorted list,
# smallest point to highest.
e = world.elevation['data']
e_min = e.min()
e_max = e.max()
e = (e - e_min) / (e_max - e_min) # normalize to [0, 1]
e *= int(y_bins) - 0.01 # instead of "- 1", small trick to make the last bin contain more than one point
e = numpy.sort(e, axis=None) # flatten the array and order values by height
e = e.astype(dtype=numpy.uint16) # do not round (the graph wouldn't change, just shift)

# Fill the plot.
# Start by calculating how many points of the heightmap have to be represented by a single bin (n).
# Then step through the bins and fill in points from highest to lowest. Every bin is set to the average height of
# the n points it represents.
# Instead of drawing to [y, x] draw to [y_bins - y - 1, x_bins - x - 1] to flip the output in x- and y-direction.
n = e.size / float(x_bins)
for x in range(x_bins):
avg = sum(e[int(x * n):int((x + 1) * n)])
avg = int(avg / float(n)) # average height of n height-points
for y in range(y_bins):
target[y_bins - y - 1, x_bins - x - 1] = color_none if y > avg else color_full

# Draw a vertical line every ten percent.
step = x_bins / 10.0
for i in range(1, 10): # no lines at 0 and (x_bins - 1)
x = int(step * i)
for y in range(y_bins):
target[y, x_bins - x - 1] = color_percent_sep

# Map sea-level etc. to appropriate y-positions in the graph.
lines = []
for threshold in world.elevation['thresholds']: # see generation.py->initialize_ocean_and_thresholds() for details
if threshold[1] is None:
continue # TODO: remove if the thresholds are ever guaranteed to be numbers
lines.append(int(numpy.interp(threshold[1], [e_min, e_max], [0, y_bins])))

# Draw lines for sea-level, hill-level etc. The lines will get lighter with increasing height.
for i in range(len(lines)):
color = numpy.interp(i, [0, len(lines)], [color_line, color_none])
for x in range(x_bins):
target[y_bins - lines[i] - 1, x] = color


# -------------
# Draw on files
# -------------
Expand Down Expand Up @@ -869,14 +811,6 @@ def draw_scatter_plot_on_file(world, filename):
img.complete()


def draw_hypsographic_plot_on_file(world, filename):
x_bins = 800
y_bins = 600
img = PNGWriter.grayscale_from_dimensions(x_bins, y_bins, filename, channel_bitdepth=8)
draw_hypsographic_plot(world, img, x_bins, y_bins)
img.complete()


def draw_satellite_on_file(world, filename):
img = PNGWriter.rgba_from_dimensions(world.width, world.height, filename)
draw_satellite(world, img)
Expand Down
52 changes: 52 additions & 0 deletions worldengine/draw_plots.py
Original file line number Diff line number Diff line change
@@ -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 Worlds'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)

0 comments on commit 496e3cb

Please sign in to comment.