Rendering ['vis']['mergertree_sublink'] (pngs) instead of ['supplementary_data']['stellar_mocks']['image_subhalo']

André Barbosa
  • 1
  • 14 Dec '22

Hi All,

wondering if you could help me solving this conundrum -> Code A) works ok and renders ['supplementary_data']['stellar_mocks']['image_subhalo'] however Code B) doesn't run while trying to render ['vis']['mergertree_sublink'], may you please check? The error happens on this line: file_object = BytesIO(response.content)

Code A) plotting the sub_halos is OK

ids = [41092,338375,257378,110568,260067]
sub_count = 1
plt.figure(figsize=[12,12])

for id in ids:
    url = "http://www.tng-project.org/api/Illustris-1/snapshots/135/subhalos/" + str(id)
    sub = get(url)
    print(sub['supplementary_data']['stellar_mocks']['image_subhalo'])    

    if 'stellar_mocks' in sub['supplementary_data']:
      png_url = sub['supplementary_data']['stellar_mocks']['image_subhalo']
      response = get(png_url)

      # make plot a bit nicer
      plt.subplot(1,len(ids),sub_count)
      plt.text(0,-20,"ID="+str(id),color='blue')
      plt.gca().axes.get_xaxis().set_ticks([])
      plt.gca().axes.get_yaxis().set_ticks([])
      sub_count += 1

      # plot the PNG binary data directly, without actually saving a .png file
      file_object = BytesIO(response.content)
      plt.imshow(mpimg.imread(file_object))

Code B) trying to plot the corresponding merger trees....

ids = [41092,338375,257378,110568,260067]
sub_count = 1
plt.figure(figsize=[12,12])

for id in ids:
    url = "http://www.tng-project.org/api/Illustris-1/snapshots/135/subhalos/" + str(id)
    sub = get(url)
    print(sub['vis']['mergertree_sublink'])

    if 'mergertree_sublink' in sub['vis']: 
      png_url = sub['vis']['mergertree_sublink']
      response = get(png_url)

      # make plot a bit nicer
      plt.subplot(1,len(ids),sub_count)
      plt.text(0,-20,"ID="+str(id),color='blue')
      plt.gca().axes.get_xaxis().set_ticks([])
      plt.gca().axes.get_yaxis().set_ticks([])
      sub_count += 1

      # plot the PNG binary data directly, without actually saving a .png file
      file_object = BytesIO(response.content)
      plt.imshow(mpimg.imread(file_object))
Dylan Nelson
  • 14 Dec '22

Hi Andre,

What is the actual error you get on the line file_object = BytesIO(response.content)?

It looks OK to me, those 5 subhalos all return valid PNGs for the merger tree vis.

André Barbosa
  • 1
  • 14 Dec '22

Thanks Dylan,

The error I am getting is:

AttributeError                            Traceback (most recent call last)
<ipython-input-8-3425770c5f8c> in <module>
     51 
     52       # plot the PNG binary data directly, without actually saving a .png file
---> 53       file_object = BytesIO(response.content)
     54       plt.imshow(mpimg.imread(file_object))

AttributeError: 'str' object has no attribute 'content'
Dylan Nelson
  • 14 Dec '22

Perhaps try print(response) and see what it is

André Barbosa
  • 1
  • 14 Dec '22

Thanks Dylan,

on Code A) print(response) = <Response [200]>

on Code B) print(response) = vis_Illustris-1_Sublink_135_41092.png (for each subhalo Id, ...)

Maybe the helper def get(path, params=None) method needs to be changed:

def get(path, params=None):
    # make HTTP GET request to path
    r = requests.get(path, params=params, headers=headers)
    # raise exception if response code is not HTTP SUCCESS (200)
    r.raise_for_status()

    if r.headers['content-type'] == 'application/json':
        return r.json() # parse json responses automatically
    return r
Dylan Nelson
  • 15 Dec '22

Yes that's correct, the full get() method is:

>>> def get(path, params=None):
>>>     # make HTTP GET request to path
>>>     headers = {"api-key":"10d143a0ef27c6461f94b50275d45d6f"}
>>>     r = requests.get(path, params=params, headers=headers)
>>>
>>>     # raise exception if response code is not HTTP SUCCESS (200)
>>>     r.raise_for_status()
>>>
>>>     if r.headers['content-type'] == 'application/json':
>>>         return r.json() # parse json responses automatically
>>>
>>>     if 'content-disposition' in r.headers:
>>>         filename = r.headers['content-disposition'].split("filename=")[1]
>>>         with open(filename, 'wb') as f:
>>>             f.write(r.content)
>>>         return filename # return the filename string
>>>
>>>     return r

this last part, looking for content-disposition, saves the response to a file and returns the filename as a string, which is what is happening in (B). If you don't want this behavior, you can turn it off.

André Barbosa
  • 15 Dec '22

Thanks Dylan.

  • Page 1 of 1