2

I wonder how to return the right information needed from this df. Currently I get an empty return. I think the problem is my selection because the coordinates are correct and all variables are as well. If I take away just one & from the selection it seems to work, The code is running like this, you can try your best. I really think it's just a little thing missing here.

Who can help?

import os, requests
import pandas as pd
pd.set_option('display.float_format', lambda x: '%.11f' % x)

#example bounds
xmax, ymax, xmin, ymin = 3845447.52241509, 8560465.238354621, -2057434.3252381992, 4031530.0276551154

direc = os.getcwd().replace('\\', '/')
#wd
url = 'https://modis-land.gsfc.nasa.gov/pdf/sn_bound_10deg.txt'
tiles_txt = requests.get(url, allow_redirects=True)

open(direc+'/tiles_bounds.txt', 'wb').write(tiles_txt.content)
text = open(direc+'/tiles_bounds.txt', 'r').read()
text = text.splitlines()
del text[0:7] 
del text[-2:]

v,h,hv = [],[],[]
for iv in range(len(text)):
    v.append('v' + text[iv][1:3].replace(' ', '0'))
for ih in range(len(text)):
    h.append('h' + text[ih][5:7].replace(' ', '0'))
for VH in range(len(text)):
    hv.append( h[VH] + v[VH] )

df_bounds = pd.DataFrame(columns=['tile','horizontal', 'vertical','xmin_m','xmax_m', 'ymin_m', 'ymax_m'])
df_bounds['tile'] = hv

hor, ver, xmin_m, xmax_m, ymin_m, ymax_m=[], [], [], [],[], []
for h in range(len(df_bounds['tile'])):
    hor.append(df_bounds['tile'][h][1:3])
    ver.append(df_bounds['tile'][h][4:6])
df_bounds['horizontal'] = hor
df_bounds['vertical'] = ver
df_bounds['horizontal'] = df_bounds['horizontal'].astype(int)
df_bounds['vertical'] = df_bounds['vertical'].astype(int)

tile_width = 1111950.5196666666
tile_height = 1111950.5196666666

for i in range(len(df_bounds['tile'])):
    xmin_m.append(-20015109.354 + df_bounds['horizontal'][i] * tile_width)
    ymin_m.append(-10007554.677 + (17 - df_bounds['vertical'][i]) * tile_height)
df_bounds['xmin_m'] = xmin_m
df_bounds['ymin_m'] = ymin_m

for i in range(len(df_bounds['tile'])):
    xmax_m.append(df_bounds['xmin_m'][i] + tile_width)
    ymax_m.append(df_bounds['ymin_m'][i] + tile_height)

df_bounds['xmax_m'] = xmax_m
df_bounds['ymax_m'] = ymax_m
#####here its's broken HERE
################################################################################################
tile_names = df_bounds['tile'][(df_bounds['xmin_m'] >= xmin) & (df_bounds['xmax_m'] <= xmax) & (df_bounds['ymax_m'] <= ymax) & df_bounds['ymin_m'] >= ymin]
####################################################################################################
tile_names = [i + ',' for i  in tile_names]
tile_names = list(tile_names)
tile_names = ''.join(tile_names)
tile_names = tile_names[:-1]
os.remove(direc + '/tiles_bounds.txt')

print(df_bounds, '\n', '\n')
print(tile_names)
5
  • have you consider using geopandas ? Commented Feb 27, 2021 at 17:15
  • Yes, geopandas is not very compatible with QGIS plugins. I will not use it. Commented Feb 27, 2021 at 17:18
  • and so on the line you higlight, the commented conditions are making the code bug right ? Commented Feb 27, 2021 at 17:53
  • Yes the commented line returns the bug. Commented Feb 27, 2021 at 18:21
  • Okay, there was one condition commented, so it shouldn't return anything now. Commented Feb 27, 2021 at 18:25

2 Answers 2

1

So I tested your code. df_boundsis a file composed of [648 rows x 7 columns]. So it seems to work. so the problem comes from the way you create the tile_names variable.

I tested individually each one of you're condition and they should work, but written as you written it it can't because you forgot a paranthese at the last condition:

tile_names = df_bounds['tile'][(df_bounds['xmin_m'] >= xmin) & (df_bounds['xmax_m'] <= xmax) & (df_bounds['ymax_m'] <= ymax) & (df_bounds['ymin_m'] >= ymin)]

To debug it I needed to sanythise your code so there is no reason to keep it for myself.

  • You should stop using os.path and use pathlib.path object instead as suggested in this article (https://treyhunner.com/2018/12/why-you-should-be-using-pathlib/).
  • You should look into the map method when you want to create a new DataFrame column from an existing one it's way more efficient (and easier to read) and try to avoid multiple for loop it makes simple things look complicated.
  • Always open files with a withstatement it will ensure that you never forget to close them
  • you can directly use the join function on pd.Series
import requests 
from pathlib import Path

##########################
##      parameters      ##
##########################
tile_width = 1111950.5196666666
tile_height = 1111950.5196666666

# example bounds 
xmax, ymax, xmin, ymin = 3845447.52241509, 8560465.238354621, -2057434.3252381992, 4031530.0276551154

# todo : to name in parameters 
toto = -20015109.354
tutu = -10007554.677
##########################


# use the pathlib lib it's easyer to manipulate files and folder and I helps you get rid of compatibility problems
direc = Path().cwd()

#wd
url = 'https://modis-land.gsfc.nasa.gov/pdf/sn_bound_10deg.txt'
tiles_txt = requests.get(url, allow_redirects=True)

tile_bounds = direc.joinpath('tiles_bounds.txt') 
tile_bounds.write_bytes(tiles_txt.content)

# always open files with a with statement to avoid unclosed files
with tile_bounds.open() as f:
    text = f.read()
    text = text.splitlines()

    del text[0:7] 
    del text[-2:]
    
# the file is now useless unlink it 
tile_bounds.unlink()
    
df_bounds = pd.DataFrame(columns=['tile','horizontal', 'vertical','xmin_m','xmax_m', 'ymin_m', 'ymax_m'])
#df_bounds.tile = hv

hor, ver, xmin_m, xmax_m, ymin_m, ymax_m=[], [], [], [],[], []

# use the map function to add extra column to a dataframe, it's easier and faster 
df_bounds.tile = [f"h{text[i][5:7].replace(' ', '0')}v{text[i][1:3].replace(' ', '0')}" for i in range(len(text))]
df_bounds.horizontal = df_bounds.tile.map(lambda row: row[1:3]).astype(int)
df_bounds.vertical = df_bounds.tile.map(lambda row: row[4:6]).astype(int)
df_bounds.xmin_m = df_bounds.horizontal.map(lambda r: toto + r*tile_width)
df_bounds.ymin_m = df_bounds.vertical.map(lambda r: tutu + (17 - r)*tile_height)
df_bounds.xmax_m = df_bounds.xmin_m.map(lambda r: r + tile_width)
df_bounds.ymax_m = df_bounds.ymin_m.map(lambda r: r + tile_height)

#filter the names of the tiiles inside the box
tile_names = df_bounds[(df_bounds['xmin_m'] >= xmin) & (df_bounds['xmax_m'] <= xmax) & (df_bounds['ymax_m'] <= ymax) & (df_bounds['ymin_m'] >= ymin)]

# improvement for the print 
tile_names = ','.join(tile_names.tile)

print(tile_names)

which returns :

h17v02,h18v02,h19v02,h20v02,h17v03,h18v03,h19v03,h20v03,h17v04,h18v04,h19v04,h20v04
5
  • Thank you very much! You really helped me learn something useful about good style. Commented Mar 2, 2021 at 12:12
  • if it's solving your problem don't forget to validate the answer Commented Mar 2, 2021 at 14:54
  • 1
    I did, but because I have less then 15 reputation it's recorded nbut not visible in public... Commented Mar 2, 2021 at 18:08
  • I upvoted your question that should be all right now ;-) + when someone provide a long answer and you want to add minor change (which is the case with your answer), just edit the existing answer instead of providing a new one Commented Mar 3, 2021 at 12:28
  • @JonasApelt, you actually upvoted the answer (which is very nice thanks) but you didn't accepted it (stackoverflow.com/help/accepted-answer). It will improve the referencing of your question and reward me for the time I spend debugging your code ;-) Commented Apr 1, 2021 at 8:11
0

Here is how to do it correctly. After some help by @Pierrick Rambaud I found out about the query itself. It still had an issue, that you couldn't query something from df_bounds if your bounding box was smaller than one object inside the DataFrame.

I finally added parameter dwhat equals tile_width. That allows you to actually receive correct results, even if your polygon bounds are smaller than the objects in your dataframe, you will always get at least one object returned.

import requests 
from pathlib import Path
import pandas as pd

##########################
##      parameters      ##
##########################
tile_width = 1111950.5196666666
tile_height = 1111950.5196666666
d = tile_width

# Kölle
xmax, ymax, xmin, ymin = 517293, 5677545, 445982, 5652207
# Stocki
#xmax, ymax, xmin, ymin = -552726.6281122746, 7752304.739116074, -2367333.4095007353, 6772316.822647995

# todo : to name in parameters 
toto = -20015109.354
tutu = -10007554.677
##########################


# use the pathlib lib it's easyer to manipulate files and folder and I helps you get rid of compatibility problems
direc = Path().cwd()

#wd
url = 'https://modis-land.gsfc.nasa.gov/pdf/sn_bound_10deg.txt'
tiles_txt = requests.get(url, allow_redirects=True)

tile_bounds = direc.joinpath('tiles_bounds.txt') 
tile_bounds.write_bytes(tiles_txt.content)

# always open files with a with statement to avoid unclosed files
with tile_bounds.open() as f:
    text = f.read()
    text = text.splitlines()

    del text[0:7] 
    del text[-2:]
    
# the file is now useless unlink it 
tile_bounds.unlink()
    
df_bounds = pd.DataFrame(columns=['tile','horizontal', 'vertical','xmin_m','xmax_m', 'ymin_m', 'ymax_m'])
#df_bounds.tile = hv

hor, ver, xmin_m, xmax_m, ymin_m, ymax_m=[], [], [], [],[], []

# use the map function to add extra column to a dataframe, it's easier and faster 
df_bounds.tile = [f"h{text[i][5:7].replace(' ', '0')}v{text[i][1:3].replace(' ', '0')}" for i in range(len(text))]
df_bounds.horizontal = df_bounds.tile.map(lambda row: row[1:3]).astype(int)
df_bounds.vertical = df_bounds.tile.map(lambda row: row[4:6]).astype(int)
df_bounds.xmin_m = df_bounds.horizontal.map(lambda r: toto + r*tile_width)
df_bounds.ymin_m = df_bounds.vertical.map(lambda r: tutu + (17 - r)*tile_height)
df_bounds.xmax_m = df_bounds.xmin_m.map(lambda r: r + tile_width)
df_bounds.ymax_m = df_bounds.ymin_m.map(lambda r: r + tile_height)

#filter the names of the tiiles inside the box and add tile_widt/tile_height to receive valid results
tile_names = df_bounds[(df_bounds['xmin_m'] >= xmin-d) & 
                       (df_bounds['xmax_m'] <= xmax+d) & 
                       (df_bounds['ymin_m'] >= ymin-d) &
                       (df_bounds['ymax_m'] <= ymax+d)]

# improvement for the print 
tile_names = ','.join(tile_names.tile)

print('0',tile_names)# '1',tile_names_s)


```

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.