1

---- Update with what I got so far and what's left to resolve can be found in point 3 below ----

Using Octave I want to create 30 horizontal box and whisker plots without spread (x-axis) from 30 different GeoTIFF's. This is a sketch of how I would like the plot to look like: enter image description here

Ideally the best solution for me would be an Octave code (workflow) that would allow me to place multiple GeoTIFFs in one directory and then with one click create a box and whisker plot for all GeotIFFs at once - just like the sketch above.

A GeoTIFF-sample with 3 GeoTIFF's can be downloaded here. The file looks like this in QGIS: enter image description here

It holds elevation values on band 1 (the ones that each box and whisker plot should be based on, and no data values (-999), the no-data values should be excluded from the plot.

Right now this is what I got:

  1. Using img = imread ("filname.tif") gets the file into Octave. Using hist (img(:), 200); shows that all cells are concentrated around 65300. imagesc (img, [65100 65600]) follwed by colorbar displays the image extent but's it's clear that this way simply doesn't import the real cell values. I can't find a working solution to import GeoTIFF's with cell values, therefor my current work-around is exporting the GeoTIFF from QGIS with gdal_translate -of aaigrid which creates a .asc-file that I manually edit to remove header rows, rename to .csv and load into Octave. That .csv can be found here.
  2. To load it and create a box plot I'm currently using this code (thanks to @Andy and @Cris Luengo):

    pkg load statistics
    
    s = urlread ("https://drive.google.com/uc?export=download&id=1RzJ-EO0OXgfMmMRG8wiCBz-51RcwSM5h");
    o = str2double (strsplit (s, ";"));
    o(isnan (o)) = [];
    
    boxplot (o)
    set(gca,"xtick",[])
    view([-90 90])
    
    print out.png
    
  3. The results is pretty close but I'm still failing to: A) load GeoTIFF's directly from a folder. If this is not possible I'm gonna have to modify the code to load all *.csv in a directory to the same box plot and label each plot by filename (which I'm unsure how to accomplish. B) to get the x-axis reversed (going from 200-450, not the other way around). This is caused by the view([-90 90]) that I use to make the box plot horizontal instead of vertical which is needed for layout reasons. enter image description here

Anyone with any ideas on how to resolve the last adjustments?

---- Background info ----

I have 30 GeoTIFFs containing results from a viewshed analysis, for every 2x2 meter square there is a value the tells me how high a building can be (in meters) before it's visible from the viewshed point. The results cover the whole city of Stockholm but the above mentioned 30 GeoTIFFs are smaller clips of an area where new development is planned. The results help planners to understand how new development might effect each of the 30 places (that are important for cultural heritage management).

As part of a bigger PDF-report (where these results are visualized with different maps in different scales) I'm trying to produce a box and whisker plot (as a compliment to the maps) the gives the reader an overview over how much space is there is left at the planned development area, based on each of the 30 viewshed (GeoTIFF) results (one box and whisker for each of the 30 locations). Below is an example of how a map in the report can look like: enter image description here

johlund
  • 137
  • 7
  • I think there is not yet an easy way to load GeoTIFF directly into GNU Octave (I previously thought it is because it's basically a TIFF). If you were on GNU/Linux it would be easy to call gdal_translate from Octave and visualize it's output. – Andy Jan 13 '18 at 08:28
  • I've managed to load the geotiff and visualize it's extent with Octave, what I didn't manage to do was to visualize the pixel values, every singel valid pixel showed the value 253 if I recall correctly. But to get from there to a box n whisker feels lile a mountain to climb for me. Thats why I tried to export from QGIS with gdal_translate -of aaigrid and import to Octave (which you manage to use to make a box n whisker of). That was vary close to a solution except I needed it without the spread) https://stackoverflow.com/questions/48099439/box-n-whisker-from-csv-with-octave/48111477#48111477 – johlund Jan 13 '18 at 12:50
  • can you add two more geotiff images? – Andy Jan 13 '18 at 16:57
  • Here they come: https://drive.google.com/open?id=1rYVjxsurR2o43MglmQSwUHyvOGNtxgbP and https://drive.google.com/open?id=1arXJx-HyZSRuB497WYHnAylFk9ze-_RJ – johlund Jan 13 '18 at 17:43
  • @CrisLuengo I understand you reaction and updated with what I've got so far and whats missing. Thanks for your help in the linked post with the csv-work-around. – johlund Jan 14 '18 at 11:09
  • @johlund: This is a more specific question, I think it'll be easier to answer. Regarding the display of GeoTiff data: did you try `imagesc (img, [])`? Adding explicit limits there would clip the values to be within those limits. I maybe have some time tonight to download your data and see if I can answer your question. – Cris Luengo Jan 14 '18 at 14:34
  • Thanks for the encouragement! Regarding the display of GeoTiff data - se point 1 in the updated question above. I tried import using img = imread ("filname.tif") which gets the file into Octave. The using hist (img(:), 200); shows that all cells are concentrated around 65300. After that imagesc (img, [65100 65600]) follwed by colorbar displays the image extent but's it's clear that this way simply doesn't import the real cell values (which varies from 0 till around 600). Or am I missing something? – johlund Jan 14 '18 at 14:57
  • [This](https://stackoverflow.com/a/45244432/6579744) post explained how to read hyperspectral images and geotiff. – rahnema1 Jan 14 '18 at 18:04

1 Answers1

3

Does not directly read GeoTIFF but calls gdal_translate under the hood. Just place all your .tif in the same directory. Make sure gdal_translate is in your PATH:

pkg load statistics

clear all;
fns = glob ("*.tif");
for k=1:numel (fns)

  ofn = tmpnam;
  cmd = sprintf ('gdal_translate -of aaigrid "%s" "%s"', fns{k}, ofn);
  [s, out] = system (cmd);
  if (s != 0)
    error ('calling gdal_translate failed with "%s"', out);
  endif
  fid = fopen (ofn, "r");
  # read 6 headerlines
  hdr = [];
  for i=1:6
    s = strsplit (fgetl (fid), " ");
    hdr.(s{1}) = str2double (s{2});
  endfor
  d = dlmread (fid);

  # check size against header
  assert (size (d), [hdr.nrows hdr.ncols])

  # set nodata to NA
  d (d == hdr.NODATA_value) = NA;

  raw{k} = d;

  # create copy with existing values
  raw_v{k} = d(! isna (d));

  fclose (fid);

endfor

## generate plot
boxplot (raw_v)
set (gca, "xtick", 1:numel(fns),
          "xticklabel", strrep (fns, ".tif", ""));
view ([-90 90])
zoom (0.95)

print ("out.png")

gives

boxplot from three tif

Andy
  • 7,931
  • 4
  • 25
  • 45
  • This looks truly AMAZING Andy - I'm mighty impressed! Don't know how to thank you enough.. One small question: the view ([-90 90]), which I understand is necessary to get the boxes horizontal, comes with the not so logical inversion of the y axis (200-0, left-right). Is there any way to invert it to 0-200 instead? Thank you again! – johlund Jan 14 '18 at 17:50
  • 1
    I just tried playing around with the `view` command in MATLAB. `view([90,-90])` has the y-axis running horizontally from left to right, and the x-axis vertically from bottom to top. `view([90,90])` reverses the x-axis to be from top to bottom. Alternatively, `set(gca,'YDir','reverse')` changes the direction of the y-axis. Same for the x-axis with `'XDir'` property. – Cris Luengo Jan 15 '18 at 03:46
  • 1
    Also, a long time ago, I wrote [this alternative to `boxplot`](https://www.mathworks.com/matlabcentral/fileexchange/51134-boxplot). I think the look on those box plots is much better than what the builtin box plots in MATLAB or Octave. If you drop that file into your current directory, it will replace the `boxplot` command, though it has a different interface. Not tested in Octave, though I don't see why it wouldn't work there. – Cris Luengo Jan 15 '18 at 03:57
  • @CrisLuengo Do you have an alternate download location for your boxplot? Matlab File Exchange doesn't allow to use the files for anything other than using it in MATLAB – Andy Jan 15 '18 at 04:43
  • 1
    @Andy, I have copied the file here http://crisluengo.net/wp-content/uploads/boxplot.m . It doesn't come with any specific licensing, but I originally posted it online with my standard "do whatever you want with it, just don't blame me if anything goes wrong" license. – Cris Luengo Jan 15 '18 at 05:07
  • @CrisLuengo since I also share your opinion regarding the box plot look, I downloaded your version to give it a go with Andy's code above. I'm not blaming you for anything, just reporting back the error and figure I got if you're interested!? https://drive.google.com/open?id=1liPfmRnjnpBlK79KJcJTXlGQz3QblcKn – johlund Jan 15 '18 at 13:08
  • 1
    @johlund: I've updated the function to accept a cell array as input. I think it should work now with how Andy calls the function. If you want outliers as dots you'll have to call it as `boxplot (raw_v,'outlier')`. By default it stretches the whiskers to the max and min datum. – Cris Luengo Jan 15 '18 at 16:27
  • @CrisLuengo Working like a charm, and looking a lot better! Also, your boxplot kept the same height on the boxes - which Octaves didn't for some unknown reason. Thanks! Do you happen to know how to create a legend with symbols for quantiles, median and outliers? – johlund Jan 16 '18 at 07:26
  • @johlund: I've never created such a legend. I guess you could plot a box in an unused corner of your axes, add text to that, and draw a rectangle around it. I don't know much about the 'legend' object, I think it's a separate axes object. If so you could plot to that as well. – Cris Luengo Jan 16 '18 at 20:12
  • @CrisLuengo the legend is indeed a separate axes object so you can do anything, add images and so on. But I can't figure out how johlund might want the legend, perhaps he should sketch it per hand) – Andy Jan 17 '18 at 07:42
  • @Andy My hand sketches are just sketchy (pun intended). I've been fooling around with the 'legend ("show")' following this documentation https://www.gnu.org/software/octave/doc/v4.0.1/Plot-Annotations.html. But I can only get it to show too many data series so that they cover the whole plot. All I really need in the legend is the symbols "+" and "o" for the 1,5-3 and 3 x outliers. The median mark would also be useful but I'm not sure how that would work. – johlund Jan 30 '18 at 00:16
  • I'm also trying to save/export/print the plot with higher resolution, for printing on paper purposes. Any recommendations on that? Would 'print -deps -color file.eps' do the trick? Just not sure on how to use the ("") signs (not at the Octave computer right now) – johlund Jan 30 '18 at 00:20
  • If you want to add it for publication I would create a vectorgraphic, for example svg (or epsc) – Andy Jan 30 '18 at 07:48