Delete empty cells in Data Table

I suspect this has a very simple answer, but I am new to Anvil and relatively new to Python and I just can’t seem to figure it out.

I have a Data Table with five columns. The column headers are animal names. When running the app a user is presented with an image and selects the animal they see in the image, after which the filename of that image is added to the appropriate column in the table, like this:

@anvil.server.callable
def lion_classification(filename):
  app_tables.animals.add_row(
    lion=filename
  )

This works fine, except that of course whenever an ‘add_row’ is done, an entire row is added, and all columns other than the animal selected are filled with ‘None’. This results in a Table like this:

Is it possible to create the table in such a way that no ‘None’ cells are created, and each animal selection fills the next empty cell in its column? I.e. the same as the table shown but with both entries in the same row (and any subsequent entries filling the first empty row in their column).

Thanks in advance!

David

hi @david.modiano1 and welcome to the forum,

The idea to me seems like it could be reduced to the following table structure i.e. two columns

animals = [
  {
    'species': 'lion'
    'file': 'Cdy00245.JPG' 
  },
  {
    'species': 'elephant'
    'file': 'Cdy00743.JPG' 
  }
]

This way you can have no Nones without trying to do fill values
You could also make species a linked row to another table that just has the animal types you’re using

It might be a good idea that you make 2 columns, one is animals, another is file.

Hi,

Thanks for the replies! Indeed a table like that would perhaps be a better way to store the data. Unfortunately, the csv file I need to download has to be presented in this way, with one column per animal, so a table with one column indicating species and the other indicating file won’t work.

Is there no way to add a particular cell to a table, rather than an entire row?

Or would the only way be to make the table like you suggest, and then when completed, build the table I need from scratch based on the completed table?

You could use pandas.
Are these all completely unique i.e. you won’t have two elephants? :elephant: :elephant:

If this is the case you can do…

import anvil.media 
import pandas as pd

def get_animals_in_correct_format():
  animal_csv = app_tables.animals.search().to_csv()
  with anvil.media.TempFile(animal_csv) as file:
    df = pd.read_csv(file)
  
  df = df.set_index('species')
  df = df.T #Transpose
  return df.to_csv()

and the csv will look like something like:

animal      lion      elephant
file    lion.jpg  elephant.jpg

Alternatively if you just want your datatable to look like that (again assuming we don’t have multiple elephants)

@anvil.server.callable
def animal_classification(animal_dct): # something like {'lion': 'lion.jpg'}
  rows = app_tables.animals.search()
  if len(rows): # then just update the first row
    row = rows[0]
    row.update(animal_dict)
  else : # there are no rows so add one
    app_tables.animals.add_row(**animal_dict)

Be sure to check the box in the data_tables service that says add missing columns - it would be above and to the right of the screen shot you posted.

Hi, @david.modiano1.

Sorry to say, in a database table, every row has exactly the same columns. That really is why they are called tables. They had that structure when they were invented around 50 years ago. You use a table when you want every row to have the same structure.

In a row, a column may have no data (its value is NULL, in SQL terms, or None, in Python terms). But the column will always be there.

It seems you have a contradiction before you. You want something that conforms to the shape of a CSV file’s data – which is a table – but you also want something that doesn’t.

You can’t (trivially) get both in the same data structure. But you can write code to translate between two different structures, and use each structure where it fits the best.

EDIT:
Anvil provides a SimpleObject column type, which can help in cases like these. For values that are guaranteed to be in every row, use “normal” columns. For the remaining values, collect them into a list or dict, and save the resulting object in the SimpleObject column. This way, you can get something of both worlds in the same data structure.

2 Likes

Thanks! Unfortunately I don’t have access to the pandas library, although this does look like it would be a good way to present the data. Also I will actually have multiple files per animal, so the problem that p.colbert mentions will actually still persists.

Thanks @p.colbert. This helps a lot. Clearly it was a lack of understanding on my part of how the table and csv structure works, so that’s good to know. I will try out the SimpleObject method you suggest!