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

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()

Related

What can I do to avoid race conditions for multiple callbacks in plotly?

I have a dashboard very similar to this one-
import datetime
import dash
from dash import dcc, html
import plotly
from dash.dependencies import Input, Output
# pip install pyorbital
from pyorbital.orbital import Orbital
satellite = Orbital('TERRA')
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div(
html.Div([
html.H4('TERRA Satellite Live Feed'),
html.Div(id='live-update-text'),
dcc.Graph(id='live-update-graph'),
dcc.Interval(
id='interval-component',
interval=1*1000, # in milliseconds
n_intervals=0
)
])
)
# Multiple components can update everytime interval gets fired.
#app.callback(Output('live-update-graph', 'figure'),
Input('live-update-graph', 'relayout'),
Input('interval-component', 'n_intervals'))
def update_graph_live(relayout, n):
if ctx.triggered_id == 'relayout':
* code that affects the y axis *
return fig
else:
satellite = Orbital('TERRA')
data = {
'time': [],
'Latitude': [],
'Longitude': [],
'Altitude': []
}
# Collect some data
for i in range(180):
time = datetime.datetime.now() - datetime.timedelta(seconds=i*20)
lon, lat, alt = satellite.get_lonlatalt(
time
)
data['Longitude'].append(lon)
data['Latitude'].append(lat)
data['Altitude'].append(alt)
data['time'].append(time)
# Create the graph with subplots
fig = plotly.tools.make_subplots(rows=2, cols=1, vertical_spacing=0.2)
fig['layout']['margin'] = {
'l': 30, 'r': 10, 'b': 30, 't': 10
}
fig['layout']['legend'] = {'x': 0, 'y': 1, 'xanchor': 'left'}
fig.append_trace({
'x': data['time'],
'y': data['Altitude'],
'name': 'Altitude',
'mode': 'lines+markers',
'type': 'scatter'
}, 1, 1)
fig.append_trace({
'x': data['Longitude'],
'y': data['Latitude'],
'text': data['time'],
'name': 'Longitude vs Latitude',
'mode': 'lines+markers',
'type': 'scatter'
}, 2, 1)
return fig
if __name__ == '__main__':
app.run_server(debug=True)
In my case, I have three different intputs. One input gets triggered by an dcc.interval timer, like in the example. Another input gets triggered when a user zooms in on the dashboard using the Input('live-update-graph', 'relayoutData' input and the last triggeres when a button gets pressed.
All three inputs are totally independent. One updates the data stored in fig['data'], another updates the data stored in fig['layout']['xaxis'] and the last updates the stuff in fig['layout']['yaxis'].
I am concerned about the this situation:
The dcc interval input gets triggered and the function starts to update the data
The user zooms in on the dashboard and triggers the relayout data
The dcc.interval returns a figure
Now, because the relayout input got triggered second, it has stale data. There is a race condition and it is possible that the dcc interval gets undone as a result.
What can I do to avoid the race condition? I wonder if it's possible to update only a part of the figure with a callback rather than editing the whole object.
I think this code does what you want. Update data, while keeping layout. You can adapt to exactly what you would like, your example is copied anyhow and not really working (ex: you have a ctx there that is not defined)
The idea of the code below is: rather than update the complete object server side (in the callback) have different "parts" of the object (data-patch1, data-patch2, etc) and "merge" them in the browser (see deep_merge).
Depending on what you want to keep/adjust you can adjust that function and fill accordingly the data-patch.
For the code below you can just zoom in/zoom out, but you could also patch colors, sizes, etc.
# From https://github.com/plotly/dash-core-components/issues/881
import dash
import datetime
import random
import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Input, Output
import plotly.express as px
import plotly.graph_objects as go
import plotly
figure = go.Figure()
app = dash.Dash(__name__)
app.layout = html.Div(children = [
html.Div(id="patchstore",
**{'data-figure':figure, 'data-patch1':{}, 'data-patch2':{}, 'data-patch3':{}}),
dcc.Graph(id="graph"),
dcc.Interval(
id='interval-component',
interval=2*1000, # in milliseconds
n_intervals=0)
])
deep_merge = """
function batchAssign(patches) {
function recursiveAssign(input, patch){
var outputR = Object(input);
for (var key in patch) {
if(outputR[key] && typeof patch[key] == "object" && key!="data") {
outputR[key] = recursiveAssign(outputR[key], patch[key])
}
else {
outputR[key] = patch[key];
}
}
return outputR;
}
return Array.prototype.reduce.call(arguments, recursiveAssign, {});
}
"""
app.clientside_callback(
deep_merge,
Output('graph', 'figure'),
[Input('patchstore', 'data-figure'),
Input('patchstore', 'data-patch1'),
Input('patchstore', 'data-patch2'),
Input('patchstore', 'data-patch3')]
)
#app.callback(Output('patchstore', 'data-patch1'),[Input('interval-component', 'n_intervals')])
def callback_data_generation(n_intervals):
data = {
'time': [],
'Latitude': [],
'Longitude': [],
'Altitude': []
}
# Collect some data
for i in range(30):
time = datetime.datetime.now() - datetime.timedelta(seconds=i*20)
data['Longitude'].append(random.randint(1,10))
data['Latitude'].append(random.randint(1,10))
data['Altitude'].append(random.randint(1,10))
data['time'].append(time)
# Create the graph with subplots
fig = plotly.tools.make_subplots(rows=2, cols=1, vertical_spacing=0.2)
fig['layout']['margin'] = {
'l': 30, 'r': 10, 'b': 30, 't': 10
}
fig['layout']['legend'] = {'x': 0, 'y': 1, 'xanchor': 'left'}
fig.append_trace({
'x': data['time'],
'y': data['Altitude'],
'name': 'Altitude',
'mode': 'lines+markers',
'type': 'scatter'
}, 1, 1)
fig.append_trace({
'x': data['Longitude'],
'y': data['Latitude'],
'text': data['time'],
'name': 'Longitude vs Latitude',
'mode': 'lines+markers',
'type': 'scatter'
}, 2, 1)
if n_intervals==0:
fig.layout = None
return fig
app.run_server()

How to change plotly bar size

I am trying to plot a bar chart using python and plotly, but the size of the bar is high. I want to reduce the size of the bar.
Can anyone help me?
and I am sharing my code.
data_plots = go.Bar(x=df1['MeterReading_DateTime'], y= df1['ACT_IMP_TOT'],marker = {'color' : '#060805'},width = 1)
layout = {'title': '','xaxis': {'title': 'Date and time'},'yaxis': {'title': 'Total Import(KWH)'},'plot_bgcolor':'#8099b3' }
fig = {'data': data_plots, 'layout': layout}
plot_div = offline.plot(fig, output_type='div')
return plot_div

time_slider_drag_update for TimestampedGeoJson not updating

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

plotly graph_objects (go) selecting two lines from two dropdowns menu to compare in the same figure

i am trying to compare two lines in the same fig in plotly go, the goal is to let the user to select two entities (i.e. countries) from two dropdown menu in the chart
this is the chart with all entities active
when i select different country in the two dropdown:
i.e. dropdown1 = Italy, dropdown2= France
the chart shows just one line (the last selected from the dropdown, so it update)but it doesn't plot the two lines in the same figure
Plot with just one line
this is the dataframe:
dataframe head
this is the code i am working on:
fig1 = go.Figure()
for column in df.columns.to_list():
fig1.add_trace(
go.Scatter(
x = df.index,
y = df[column],
name = column
)
)
button_all = dict(label = 'All',
method = 'restyle',
args = [{'visible': df.columns.isin(df.columns),
'title': 'All',
'showlegend':True}])
button_none = dict(label = 'None',
method = 'update',
args = [{'visible': df.columns.isin(df.columns),
'title': 'All',
'showlegend':True}])
def create_layout_button(column):
return dict(label = column,
method = 'restyle',
args = [{'visible': df.columns.isin([column]),
'title': column,
'showlegend': True}])
def create_layout_buttonE(column):
return dict(label = column,
method = 'update',
args = [{'visible': df.columns.isin([column]),
'title': column,
'showlegend': True}])
addAll = True
# Update plot sizing
fig1.update_layout(
width=700,
height=500,
autosize=False,
margin=dict(t=120, b=0, l=0, r=0),
)
# Add dropdowns
button_layer_1_height = 1.08
fig1.update_layout(
updatemenus=[
dict(
buttons=([button_all] * addAll) + list(df.columns.map(lambda column: create_layout_button(column))),
direction="down",
pad={"r": 10, "t": 0},
showactive=True,
x=0.1,
xanchor="left",
y=button_layer_1_height,
yanchor="top"
),
dict(
buttons=([button_none] * addAll) + list(df.columns.map(lambda column: create_layout_buttonE(column))),
direction="down",
pad={"r": 10, "t": 0},
showactive=True,
x=0.37,
xanchor="left",
y=button_layer_1_height,
yanchor="top"
),
]
)
fig1.show()
synthesized dataframe in same structure as you defined
taken a different approach. Rather than creating all traces and controlling visibility in updatemenus. Create two traces and control name and contents of y in updatemenus
import pandas as pd
import numpy as np
import plotly.graph_objects as go
# get some countries
countries = (
pd.read_csv(
"https://raw.githubusercontent.com/owid/covid-19-data/master/public/data/vaccinations/locations.csv"
)
.loc[lambda d: d["iso_code"].str.len() == 3, "location"]
.sample(20)
.sort_values()
.values
)
# build data frame of same struct
df = pd.DataFrame(
np.random.randint(200, 1500, [22, len(countries)]),
columns=countries,
index=range(2000, 2022),
)
# create a figure with two place holder traces
fig = go.Figure(
[
go.Scatter(x=df.index, y=np.full(len(df), np.nan), meta=i, name=i)
for i in range(2)
]
)
# but data for y and name in when country is selected
fig.update_layout(
updatemenus=[
{
"x": b / 3,
"y": 1.4,
"active": None,
"buttons": [
{
"label": c,
"method": "restyle",
"args": [{"y": [df[c]], "name": c}, [b]],
}
for c in df.columns
],
}
for b in range(2)
]
)

how to hide plotly yaxis title (in python)?

Editing:
The following example from Plotly for reference:
import plotly.express as px
df = px.data.gapminder().query("continent == 'Europe' and year == 2007 and pop > 2.e6")
fig = px.bar(df, y='pop', x='country', text='pop')
fig.update_traces(texttemplate='%{text:.2s}', textposition='outside')
fig.update_layout(uniformtext_minsize=8, uniformtext_mode='hide')
fig.show()
How to remove the word 'pop'.
What I want to hide the y-axis title of'value'.
The following syntax doesn't work.
fig.update_yaxes(showticklabels=False)
Thanks.
Solution
You need to use visible=False inside fig.update_yaxes() or
fig.update_layout() as follows. For more details see the
documentation for plotly.graph_objects.Figure.
# Option-1: using fig.update_yaxes()
fig.update_yaxes(visible=False, showticklabels=False)
# Option-2: using fig.update_layout()
fig.update_layout(yaxis={'visible': False, 'showticklabels': False})
# Option-3: using fig.update_layout() + dict-flattening shorthand
fig.update_layout(yaxis_visible=False, yaxis_showticklabels=False)
Try doing the following to test this:
# Set the visibility ON
fig.update_yaxes(title='y', visible=True, showticklabels=False)
# Set the visibility OFF
fig.update_yaxes(title='y', visible=False, showticklabels=False)
A. How to create the figure directly with hidden-yaxis label and tickmarks
You can do this directly by using the layout keyword and
supplying a dict to go.Figure() constructor.
import plotly.graph_objects as go
fig = go.Figure(
data=[go.Bar(y=[2, 1, 3])],
layout_title_text="A Figure Displaying Itself",
layout = {'xaxis': {'title': 'x-label',
'visible': True,
'showticklabels': True},
'yaxis': {'title': 'y-label',
'visible': False,
'showticklabels': False}
}
)
fig
B. How to create the figure without the margin space around
Say, you suppressed the titles for both the axes. By default plotly
would still leave a default amount of space all around the figure:
this is known as the margin in Plotly's documention.
What if you want to reduce or even completely remove the margin?
This can be done using fig.update_layout(margin=dict(l = ..., r = ..., t = ..., b = ...)) as mentioned in the documentation:
https://plotly.com/python/reference/#layout-margin.
In the following example, I have reduced the left, right
and bottom margins to 10 px and set the top margin to 50 px.
import plotly.graph_objects as go
fig = go.Figure(
data=[go.Bar(y=[2, 1, 3])],
layout_title_text="A Figure with no axis-title and modified margins",
layout = {
'xaxis': {'title': 'x-label',
'visible': False,
'showticklabels': True},
'yaxis': {'title': 'y-label',
'visible': False,
'showticklabels': False},
# specify margins in px
'margin': dict(
l = 10, # left
r = 10, # right
t = 50, # top
b = 10, # bottom
),
},
)
fig
C. An Interesting Feature of Plotly: A hidden shorthand
It turns out that Plotly has a convenient shorthand notation
allowing dict-flattening available for input arguments such as this:
## ALL THREE METHODS BELOW ARE EQUIVALENT
# No dict-flattening
# layout = dict with yaxis as key
layout = {'yaxis': {'title': 'y-label',
'visible': False,
'showticklabels': False}
}
# Partial dict-flattening
# layout_yaxis = dict with key-names
# title, visible, showticklabels
layout_yaxis = {'title': 'y-label',
'visible': False,
'showticklabels': False}
# Complete dict-flattening
# layout_yaxis_key-name for each of the key-names
layout_yaxis_title = 'y-label'
layout_yaxis_visible = False
layout_yaxis_showticklabels = False
Now try running all three of the following and compare the outputs.
import plotly.graph_objects as go
# Method-1: Shortest (less detailed)
fig = go.Figure(
data=[go.Bar(y=[2, 1, 3])],
layout_title_text="A Figure Displaying Itself",
layout_yaxis_visible = False,
layout_xaxis_title = 'x-label'
)
fig.show()
# Method-2: A hibrid of dicts and underscore-separated-syntax
fig = go.Figure(
data=[go.Bar(y=[2, 1, 3])],
layout_title_text="A Figure Displaying Itself",
layout_xaxis_title = 'x-label',
layout_yaxis = {'title': 'y-label',
'visible': False,
'showticklabels': False}
)
fig.show()
# Method-3: A complete dict syntax
fig = go.Figure(
data=[go.Bar(y=[2, 1, 3])],
layout_title_text="A Figure Displaying Itself",
layout = {'xaxis': {'title': 'x-label',
'visible': True,
'showticklabels': True},
'yaxis': {'title': 'y-label',
'visible': False,
'showticklabels': False}
}
)
fig.show()
How to remove the word 'pop'?
Just pass yaxis_title=None to fig.update_layout to hide default title of Y axis (similarly for xaxis_title=None for X axis).
import plotly.express as px
df = px.data.gapminder().query("continent == 'Europe' and year == 2007 and pop > 2.e6")
fig = px.bar(df, y='pop', x='country', text='pop')
fig.update_traces(texttemplate='%{text:.2s}', textposition='outside')
fig.update_layout(uniformtext_minsize=8, uniformtext_mode='hide', yaxis_title=None)
fig.show()

Categories

Resources