time_slider_drag_update for TimestampedGeoJson not updating - python

This is the data
start = eartt1.pivot_table('id',
index = ['place', 'time_hour',
'latitude',
'longitude',
'mag'
],
columns = 'type',
aggfunc='count').reset_index()
start.head()
This is the function to create the features of the animation: time, location, icon
def create_geojson_features(df):
features = []
for _, row in df.iterrows():
feature = {
'type': 'Feature',
'geometry': {
'type':'Point',
'coordinates':[row['longitude'],row['latitude']]
},
'properties': {
'time': pd.to_datetime(row['time_hh'], unit='h').__str__(),
'style': {'color' : ''},
'icon': 'circle',
'iconstyle':{
'fillColor': row['fillcolor'],
'fillOpacity': 0.8,
'stroke': 'true',
'radius': row['mag']*10
}
}
}
features.append(feature)
return features
This initiates the Function
start_geojson = create_geojson_features(start)
start_geojson[0]
start_geojson[0] displays the first date on 1970 that is suspicious as the dataset contains data from 1968
this creates animated map
from folium.plugins import TimestampedGeoJson
EQ_map = folium.Map(location = [2, -2],
tiles = "CartoDB Positron",
zoom_start = 2)
TimestampedGeoJson(start_geojson,
period = 'PT1H',
duration = 'PT1H',
transition_time = 1000,
auto_play = True).add_to(EQ_map)
EQ_map
time_slider_drag_update for TimestampedGeoJson is not updating the different years when it goes through the data points. the data is from 1968 till 2021
Please help ;(
enter image description here
You can find the entire notebook in here
https://nbviewer.org/github/panditadata/Earthquakes/blob/main/theone%20%281%29.ipynb#
or https://panditadata.com/theone_(3).html

Related

Python: Adding multiple lines on a map between sets of coordinates

I have the following code which works well:
import plotly.graph_objects as go
fig = go.Figure(go.Scattermapbox(
mode = "markers+lines",
lon = [-74.164556, -73.214697],
lat = [41.515941, 41.474395],
marker = {'size': 10}))
fig.update_layout(
margin ={'l':0,'t':0,'b':0,'r':0},
mapbox = {
'center': {'lon': 10, 'lat': 10},
'style': "stamen-terrain",
'center': {'lon': -20, 'lat': -20},
'zoom': 1})
fig.show()
Result:
I am now trying to add multiple lines from my dataframe but am not having any luck. This is what I am trying (have highlighted the new areas):
import plotly.graph_objects as go
Start_Lat = data['Start_Lat'] ## New code
Start_Lng = data['Start_Lng'] ## New code
End_Lat = data['End_Lat'] ## New code
End_Lng = data['End_Lng'] ## New code
fig = go.Figure(go.Scattermapbox(
mode = "markers+lines",
lat = [Start_Lat, End_Lat], ## New code
lon = [Start_Lng, End_Lng], ## New code
marker = {'size': 10}))
fig.update_layout(
margin ={'l':0,'t':0,'b':0,'r':0},
mapbox = {
'center': {'lon': 10, 'lat': 10},
'style': "stamen-terrain",
'center': {'lon': -20, 'lat': -20},
'zoom': 1})
fig.show()
The data looks like this:
Is anybody able to tell me what I am doing wrong here?
Thank you :)
With your data format, it's best to loop over the start and end coordinate pairs. Otherwise I think it should be a list with alternating start and end coordinates.
import plotly.graph_objects as go
fig = go.Figure()
for row in data.itertuples():
fig.add_trace(go.Scattermapbox(
mode = "markers+lines",
lat = [row.Start_Lat, row.End_Lat],
lon = [row.Start_Lng, row.End_Lng],
marker = {'size': 10}))
fig.update_layout(
margin ={'l':0,'t':0,'b':0,'r':0},
mapbox = {
'center': {'lon': data['Start_Lng'].mean(), 'lat': data['Start_Lat'].mean()},
'style': "stamen-terrain",
'zoom': 5.5})
fig.show()

Bar graph with editable dash table

I'm trying to make a bar graph with editable dash table but graph changes for just once time. After changing data in table, graph be updated but not like my expectation.
Below is my sample code:
from dash_table import DataTable
from dash.dependencies import Input, Output
import dash
import dash_html_components as html
import dash_core_components as dcc
import pandas as pd
import plotly.graph_objs as go
raw_data = {'Type': ["Cash", "Credit Card"],
'Rate': [50,50]}
test_df = pd.DataFrame(raw_data)
test_df['id'] = test_df['Type']
test_df.set_index('id', inplace=True, drop=False)
app = dash.Dash(__name__)
app.layout = html.Div(children=[
dash_table.DataTable(
id='table',
data=test_df.to_dict('records'),editable=True,
columns=[
{"name": i, "id": i, "deletable": True, "selectable": True, "hideable": True}
if i == "Type" or i == "Rate"
else {"name": i, "id": i, "deletable": True, "selectable": True}
for i in test_df.columns
],
style_cell={
'minWidth': '0px',
'maxWidth': '180px',
'whiteSpace': 'no-wrap',
'overflow': 'hidden',
'textOverflow': 'ellipsis'},
style_table={'overflowX': 'scroll'},
row_deletable=True
),
dcc.Graph(
id='plot',
style={"max-width": "600px",
"margin": "auto",
"display": "inline-block"})
])
#app.callback(Output('plot', 'figure'),
[Input('table', 'data'),
Input('table', 'columns')])
def update_graph(data, cols):
df = pd.DataFrame(data, columns=[c['name'] for c in cols])
figure_2 = go.Figure(data=[
go.Bar(x=df['Type'],
y=df['Rate'],
width=0.45,
text = df['Rate'],
textposition='inside',
marker_color='indianred')])
return figure_2
if __name__ == '__main__':
app.run_server(port=1211, debug=False)
My first time change, graph looking like this:
But from the second time, graph looking like this:
What should I do to fix this problem.
Actually I read editable docs but I still not get it. The Graph in docs is generated like this:
def display_output(rows, columns):
return {
'data': [{
'type': 'heatmap',
'z': [[row.get(c['id'], None) for c in columns] for row in rows],
'x': [c['name'] for c in columns]
}]
}
I don't know how to apply it for bar graph.
Thank you.
If you put a print statement inside your callback of data you will see on initial load the data is as expected
[{'Type': 'Cash', 'Rate': 50, 'id': 'Cash'}, {'Type': 'Credit Card', 'Rate': 50, 'id': 'Credit Card'}]
Rate holds a numeric value.
But when editing values in the datatable the value could be anything so dash table treats your input as a string and not a number.
So after editing a value in the Rate column data could now look like this
[{'Type': 'Cash', 'Rate': 50, 'id': 'Cash'}, {'Type': 'Credit Card', 'Rate': '200', 'id': 'Credit Card'}]
The value I filled in 200 is now a string in data.
It seems that when both Rate values are string values plotly doesn't know how it should draw the bars anymore.
What you could do is to convert the Rate column of df to numeric.
df['Rate'] = pd.to_numeric(df['Rate'])

Return Next Pages of Results Based on Tag in API

I am trying to come up with a script that loops and returns all results from an API. The max transactions per call is 500, and there is a tag 'MoreFlag' that is 0 when there are less than or equal to 500 transactions and 1 when there are more than 500 transactions (per page). How can I write the code so that when 'MoreFlag' is 1 go to the next page until the tag changes to 0?
The API requires a license key and password, but here's a piece of the output.
r = 0
station_name = 'ORANGE'
usageSearchQuery = {
'stationName': station_name,
'startRecord': 1 + r,
'numTransactions': 500
}
trans_data = client.service.getTransactionData(usageSearchQuery)
for c in enumerate(trans_data):
print(c)
This returns the following:
(0, 'responseCode')
(1, 'responseText')
(2, 'transactions')
(3, 'MoreFlag')
Next, if I use this code:
for c in enumerate(trans_data.transactions):
print(trans_data)
# add 500 to startRecord
The API returns:
{
'responseCode': '100',
'responseText': 'API input request executed successfully.',
'transactions': {
'transactionData': [
{
'stationID': '1’,
'stationName': 'ORANGE',
'transactionID': 178543,
'Revenue': 1.38,
'companyID': ‘ABC’,
'recordNumber': 1
},
{
'stationID': '1’,
'stationName': 'ORANGE',
'transactionID': 195325,
'Revenue': 1.63,
'companyID': ‘ABC’,
'recordNumber': 2
},
{
'stationID': '1’,
'stationName': 'ORANGE',
'transactionID': 287006,
'Revenue': 8.05,
'companyID': ‘ABC’,
'recordNumber': 500
}
]
},
'MoreFlag': 1
}
The idea is to pull data from trans_data.transactions.transactionData, but I'm getting tripped up when I need more than 500 results, i.e. subsequent pages.
I figured it out. I guess my only question: is there a cleaner way to do this? It seems kind of repetitive.
i = 1
y = []
lr = 0
station_name = 'ORANGE'
usageSearchQuery = {
'stationName': station_name,
}
trans_data = client.service.getTransactionData(usageSearchQuery)
for c in enumerate(trans_data):
while trans_data.MoreFlag == 1:
usageSearchQuery = {
'stationName': station_name,
'startRecord': 1 + lr,
'numTransactions': 500
}
trans_data = client.service.getTransactionData(usageSearchQuery)
for (d) in trans_data.transactions.transactionData:
td = [i, str(d.stationName), d.transactionID,
d.transactionTime.strftime('%Y-%m-%d %H:%M:%S'),
d.Revenue]
i = i + 1
y.append(td)
lr = lr + len(trans_data.transactions.transactionData)

Python, sorting extracted youtube data

I'm trying to retrieve the top 10 most watched videos in a youtube channel. I'm not quite sure how to do that, the results returns 10 videos of a certain timeframe I believe. Also, the y-axis('views') from the plotted bar graph is not in order. In summary, I need help plotting a graph of the number of views in relation to each video(len(10))
Obtaining statistics
youtube = build('youtube', 'v3', developerKey=api_key)
request = youtube.channels().list(
part='statistics',
id='UC-lHJZR3Gqxt24_Td_AJ5Yw'
)
#To get a response, use execute()
response = request.execute()
#List indices must be intergers or slices, not str
stats = response['items'][0]['statistics']
video_count = stats['videoCount']
contentdata = youtube.channels().list(
id='UC-lHJZR3Gqxm24_Vd_AJ5Yw',
part='contentDetails'
).execute()
playlist_id = contentdata['items'][0]['contentDetails']['relatedPlaylists']['uploads']
videos = []
next_page_token = None
while 1:
res = youtube.playlistItems().list(
playlistId=playlist_id,
part='snippet',
maxResults=50,
pageToken=next_page_token
).execute()
videos += res['items']
next_page_token = res.get('nextPageToken')
if next_page_token is None:
break
#Get video ID for each video
video_ids = list(map(lambda x:x['snippet']['resourceId']['videoId'], videos))
#Get statistics for each video
stats = []
for i in range(0, len(video_ids), 40):
res = youtube.videos().list(
id=','.join(video_ids[i:i+40]),
part='statistics'
).execute()
stats+=res['items']
views, links = [], []
for i in range(len(videos[:10])):
try:
title = (videos[i]['snippet']['title'])
view = (stats[i]['statistics']['viewCount'])
link = f"<a href='{stats[i]['id']}'>{title}</a"
except KeyError:
continue
else:
views.append(view)
links.append(link)
Plotting
from youtube_bar import links, views
from plotly.graph_objs import Bar
from plotly import offline
#Create bar graph with data
data = [{
'type': 'bar',
'x': links,
'y': views,
'opacity': 0.6,
'marker': {
'color': 'rgb(150, 100, 20)',
'line': {'width':1.5, 'color': 'rgb(25, 25, 25)'}
},
}]
my_layout = {
'title': 'Top 10 most views for channel',
'titlefont': {'size':28},
'xaxis': {
'title': 'Videos',
'titlefont': {'size': 24},
'tickfont': {'size': 14},
},
'yaxis': {
'title': 'Views',
'titlefont': {'size': 24},
'tickfont': {'size': 14},
},
}
fig = {'data': data, 'layout': my_layout}
offline.plot(fig, filename='youtube_videos.html')
graph
The loop in your code:
for i in range(len(videos[:10])):
is taking videos from 1 to 10 only (most recent, that's why a 'timeframe'), you have to sort variable videos based on it's viewCount before this.

recursively collect string blocks in python

I have a custom data file formatted like this:
{
data = {
friends = {
max = 0 0,
min = 0 0,
},
family = {
cars = {
van = "honda",
car = "ford",
bike = "trek",
},
presets = {
location = "italy",
size = 10,
travelers = False,
},
version = 1,
},
},
}
I want to collect the blocks of data, meaning string between each set of {} while maintaining a hierarhcy. This data is not a typical json format so that is not a possible solution.
My idea was to create a class object like so
class Block:
def __init__(self, header, children):
self.header = header
self.children = children
Where i would then loop through the data line by line 'somehow' collecting the necessary data so my resulting output would like something like this...
Block("data = {}", [
Block("friends = {max = 0 0,\n min = 0 0,}", []),
Block("family = {version = 1}", [...])
])
In short I'm looking for help on ways I can serialize this into useful data I can then easily manipulate. So my approach is to break into objects by using the {} as dividers.
If anyone has suggestions on ways to better approach this I'm all up for ideas. Thank you again.
So far I've just implemented the basic snippets of code
class Block:
def __init__(self, content, children):
self.content = content
self.children = children
def GetBlock(strArr=[]):
print len(strArr)
# blocks = []
blockStart = "{"
blockEnd = "}"
with open(filepath, 'r') as file:
data = file.readlines()
blocks = GetBlock(strArr=data)
You can create a to_block function that takes the lines from your file as an iterator and recursively creates a nested dictionary from those. (Of course you could also use a custom Block class, but I don't really see the benefit in doing so.)
def to_block(lines):
block = {}
for line in lines:
if line.strip().endswith(("}", "},")):
break
key, value = map(str.strip, line.split(" = "))
if value.endswith("{"):
value = to_block(lines)
block[key] = value
return block
When calling it, you have to strip the first line, though. Also, evaluating the "leafs" to e.g. numbers or strings is left as an excercise to the reader.
>>> to_block(iter(data.splitlines()[1:]))
{'data': {'family': {'version': '1,',
'cars': {'bike': '"trek",', 'car': '"ford",', 'van': '"honda",'},
'presets': {'travelers': 'False,', 'size': '10,', 'location': '"italy",'}},
'friends': {'max': '0 0,', 'min': '0 0,'}}}
Or when reading from a file:
with open("data.txt") as f:
next(f) # skip first line
res = to_block(f)
Alternatively, you can do some preprocessing to transform that string into a JSON(-ish) string and then use json.loads. However, I would not go all the way here but instead just wrap the values into "" (and replace the original " with ' before that), otherwise there is too much risk to accidentally turning a string with spaces into a list or similar. You can sort those out once you've created the JSON data.
>>> data = data.replace('"', "'")
>>> data = re.sub(r'= (.+),$', r'= "\1",', data, flags=re.M)
>>> data = re.sub(r'^\s*(\w+) = ', r'"\1": ', data, flags=re.M)
>>> data = re.sub(r',$\s*}', r'}', data, flags=re.M)
>>> json.loads(data)
{'data': {'family': {'version': '1',
'presets': {'size': '10', 'travelers': 'False', 'location': "'italy'"},
'cars': {'bike': "'trek'", 'van': "'honda'", 'car': "'ford'"}},
'friends': {'max': '0 0', 'min': '0 0'}}}
You can also do with ast or json with the help of regex substitutions.
import re
a = """{
data = {
friends = {
max = 0 0,
min = 0 0,
},
family = {
cars = {
van = "honda",
car = "ford",
bike = "trek",
},
presets = {
location = "italy",
size = 10,
travelers = False,
},
version = 1,
},
},
}"""
#with ast
a = re.sub("(\w+)\s*=\s*", '"\\1":', a)
a = re.sub(":\s*((?:\d+)(?: \d+)+)", lambda x:':[' + x.group(1).replace(" ", ",") + "]", a)
import ast
print ast.literal_eval(a)
#{'data': {'friends': {'max': [0, 0], 'min': [0, 0]}, 'family': {'cars': {'car': 'ford', 'bike': 'trek', 'van': 'honda'}, 'presets': {'travelers': False, 'location': 'italy', 'size': 10}, 'version': 1}}}
#with json
import json
a = re.sub(",(\s*\})", "\\1", a)
a = a.replace(":True", ":true").replace(":False", ":false").replace(":None", ":null")
print json.loads(a)
#{u'data': {u'friends': {u'max': [0, 0], u'min': [0, 0]}, u'family': {u'cars': {u'car': u'ford', u'bike': u'trek', u'van': u'honda'}, u'presets': {u'travelers': False, u'location': u'italy', u'size': 10}, u'version': 1}}}

Categories

Resources