Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TimestampedGeoJson only works if using times that all have the same number of digits in their Unix epoch time #1268

Closed
bharrisotcd opened this issue Mar 5, 2020 · 17 comments
Labels
bug An issue describing unexpected or malicious behaviour

Comments

@bharrisotcd
Copy link

data = pd.DataFrame({
'Latitude': [2, 7, 2, 2, -4.03, 2, 36.82, 2],
'Longitude': [49, 66, 49, 49, 5.33, 49, -1.29, 49],
'Count': [40, 12, 22, 3, 23, 30, 100, 200],
'Year': ["1997", "1998", "1998", "1999", "1999", "2002", "2003", "2004"]
})

Since this uses dates both before and after ~2002, it doesn't work. It works if using only dates before 2002 or after 2002 but not both

I assume this is because the number of digits in a Unix epoch time goes up from 12 to 13 around 2002

Is there anything I can do to get it working for all dates?

@Conengmo
Copy link
Member

Conengmo commented Mar 6, 2020

I haven't tried your data, but it doesn't seem to match the specification in the docstring of TimestampedGeoJson. Furthermore the docstring says to pass your timestamps as ISO timestamps or as unix epoch timestamps in ms. Currently you pass only a year, if you change that does that fix your issue?

@bharrisotcd
Copy link
Author

bharrisotcd commented Mar 6, 2020

I haven't tried your data, but it doesn't seem to match the specification in the docstring of TimestampedGeoJson. Furthermore the docstring says to pass your timestamps as ISO timestamps or as unix epoch timestamps in ms. Currently you pass only a year, if you change that does that fix your issue?

I've tried passing in all formats I could think of including unix epoch timestamps in ms and ISO timestamps but it only ever works if all dates are either before or after 2002.

My theory is that dates are converted to unix epoch timestamps and when it's dealing with timestamps that aren't the same number of digits it doesn't work

@Conengmo
Copy link
Member

Conengmo commented Mar 6, 2020

Alright, good to know. I'm quickly looking at the code in TimestampedGeoJson but don't see something truncating a timestamp string or something.

What would be helpful if you could provide a small, self-contained code snippet, including a bit of data, that produces your error.

@bharrisotcd
Copy link
Author

bharrisotcd commented Mar 6, 2020

Alright, good to know. I'm quickly looking at the code in TimestampedGeoJson but don't see something truncating a timestamp string or something.

What would be helpful if you could provide a small, self-contained code snippet, including a bit of data, that produces your error.

The code below works fine, but if I change any of these years to 2002 or later it doesn't work. However if all years are 2002 or later it works fine

import pandas as pd
from folium.plugins import TimestampedGeoJson
data = pd.DataFrame({
              'Latitude': [2, 7, 2, 2, -4.03, 2, 36.82, 2],
              'Longitude': [49, 66, 49, 49, 5.33, 49, -1.29, 49],
              'Count': [40, 12, 22, 3, 23, 30, 100, 200],
              'Year': ['1985', '1990', '1993', '1995', '1998', '2000', '2001', '2001']
       })
features = create_geojson_features(data)
myMap = make_map(features, data)
myMap .save('locations.html')

def create_geojson_features(data):
    features = []
    for _, row in data.iterrows():

        feature = {
            'type': 'Feature',
            'geometry': {
                'type':'Point',
                'coordinates':[row['Longitude'],row['Latitude']]
            },
            'properties': {
                'time': row["Year"],
                'style': {'color': "crimson"},
                'icon': 'circle',
                'iconstyle':{
                    'fillColor': "crimson",
                    'fillOpacity': 1,
                    'stroke': 'true',
                    'radius': row["Count"]/5
                }
            }
        }     
        features.append(feature)

    return features

def make_map(features, data):   
    myMap = folium.Map(location=[20, 0], tiles="OpenStreetMap", zoom_start=2)
    TimestampedGeoJson(
        {'type': 'FeatureCollection',
        'features': features}
        , period='P1M'
        , add_last_point=True
        , transition_time=200
        , auto_play=True
        , max_speed=1
        , loop=True
        , loop_button=True
        , time_slider_drag_update=True
    ).add_to(myMap)
  
    return myMap

@taylordouglasr
Copy link

For what it's worth, I was having the same issue until I stumbled on this discussion. I'd love to see how it worked out. I have the same issues, with sample data and real data. It all works fine if my years are all before 2002, or after 2002, but it crashes if the years span 2002.

@Conengmo
Copy link
Member

This issue is still open. We need someone to figure out what’s causing it. And then someone making a PR with a fix.

@Conengmo Conengmo added the bug An issue describing unexpected or malicious behaviour label Jun 16, 2020
@davecao
Copy link

davecao commented Jul 6, 2022

I recently use TimestampedGeoJson plugin to show changes of data varying with time. I found this bug from the internally used leaflet-timedimension. The function sort_and_deduplicate in the minified version from cdn.jsdeliver.net caused the problem when sort the available time since it sorts time as strings.

Problem:
sort_and_deduplicate: function(arr) {
arr = arr.slice(0).sort();<--- Here is problem.
var result = [];
var last = null;
for (var i = 0, l = arr.length; i < l; i++) {
if (arr[i] !== last){
result.push(arr[i]);
last = arr[i];
}
}
return result;
}

Solution:
It can be solved by adding an anonymous function. It works as a local file along with the html.

arr = arr.slice(0).sort(function(a, b){return a-b;});

The source code of leaflet.timeddimension on GitHub had been used as this. It maybe some unknown reason that
the function lost the argument( I am not sure!).
It seems to be not solved yet.

I hope it helps.

@panditadata
Copy link

myMap = make_map(features, data)
myMap .save('locations.html')

when I try to run the above code, the plug shows "Time not available"...i have written the code for data that has 1 time per year for each country for 30 years and i get the same message and no simulation. I have tried converting the time format several times but didnt fix the issue
time not available
message

@BlueCrabsLover
Copy link

hi, anyone have a solution for this? I'm using the same code but for me the problem is with before and after 9/9/2001, i tried other libraries (but went back to folium because of the aesthetic) and they don't have a similar issue, can't figure this out for a week :(

@hansthen
Copy link
Collaborator

@davecao Thanks for the debugging information. That was really helpful. Since it seems the issue is in the underlying socib/timedimension package, I will open an issue there.

@hansthen
Copy link
Collaborator

hansthen commented Apr 14, 2024

Apparently it was already fixed in the source code of the underlying javascript package, but the new version was never released.

@panditadata
Copy link

panditadata commented Apr 15, 2024 via email

@BlueCrabsLover
Copy link

thanks I'll check it out today, because it looks like I'll have to find another way to do this

@panditadata
Copy link

panditadata commented Apr 16, 2024 via email

@cafawo
Copy link

cafawo commented Nov 22, 2024

Any update on this?

This MWE also results in the aforementioned error:

image
import pandas as pd
import geopandas as gpd
import folium
from folium.plugins import TimestampedGeoJson

data = {
    'time': ['1995', '2020', '2022'],  # Only years
    'latitude': [46.5164, 46.5296, 46.5413],
    'longitude': [14.7701, 13.7241, 14.7727]
}
df = pd.DataFrame(data)

# Convert 'time' to ISO-8601 format (only the year is meaningful)
df['time'] = pd.to_datetime(df['time'], format='%Y').dt.strftime('%Y-01-01T00:00:00Z')

gdf = gpd.GeoDataFrame(df, geometry=gpd.points_from_xy(df.longitude, df.latitude))

m = folium.Map(
    location=[47.5162, 14.5501],
    zoom_start=7,
)

tgj = TimestampedGeoJson({
    'type': 'FeatureCollection',
    'features': [
        {
            'type': 'Feature',
            'geometry': {
                'type': 'Point',
                'coordinates': [row['longitude'], row['latitude']]
            },
            'properties': {
                'time': row['time'],  # Valid ISO-8601 format
                'popup': f'Year: {row["time"][:4]}',  # Extract year for popup
                'id': 'house',
                'icon': 'circle',
                'iconstyle': {
                    'fillColor': '#ff0000',
                    'fillOpacity': 0.8,
                    'stroke': 'true',
                    'radius': 7
                }
            }
        } for idx, row in gdf.iterrows()
    ]
}, period="P1Y", add_last_point=True).add_to(m)

m.save('map.html')

@hansthen
Copy link
Collaborator

@cafawo Folium is just a thin wrapper around Leaflet and its plugins. It seems that the issue is in the Leaflet plugin socib/Leaflet.TimeDimension. There is an open issue for that package which we created. Since Folium is maintained by volunteers, we do not have the time (or the expertise) to also fix issues in the underlying packages.

You could have a look at the Timeline plugin. It works differently than TimestampedGeoJson, but it may suit your use case.

If you have to use TimestampedGeoJson please chase the maintainers of socib/Leaflet.TimeDimension here: socib/Leaflet.TimeDimension#228.

@hansthen
Copy link
Collaborator

We should close this issue, since it should be handled upstream

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug An issue describing unexpected or malicious behaviour
Projects
None yet
Development

No branches or pull requests

8 participants