I am trying to replicate the Glaciers Demo using an Xarray of geospatial data. I am able to create pretty much exactly what I want but I am trying to create a Panel app that allows the user to select the data_vars, each of which has different dimensions that I want make interactable, and visualize on an interactive map with at least the continents contour. Here is what my Xarray Dataset looks like :
def plot(field):
return xds[field].hvplot.image().opts(cmap='jet',height=650,width=1300,data_aspect=1)
interact(plot, field = list(xds.data_vars))
and here is what the code above produces in a notebook :
I would like to integrate the selector for the data_vars and then depending on its dimensions have interactive maps with controls for all its dimensions (ES has (time, pres1, lat, lon) while P0 has only (time, lat, lon)) and I would like to have the controls in the sidebar and the plots in the main of the following template :
from turtle import width
from matplotlib.pyplot import title
import panel as pn
import numpy as np
import holoviews as hv
from panel.template import DefaultTheme
from pathlib import Path
import fstd2nc
import hvplot.xarray
import xarray as xr
from unicodedata import name
import hvplot
import param
from panel.interact import interact
pn.extension(sizing_mode='stretch_width')
bootstrap = pn.template.MaterialTemplate(title='Material Template', theme=DefaultTheme, )
glob_path = Path(r"C:\Users\spart\Documents\Anaconda-Work-Dir")
file_list = [str(pp).split('\\')[-1] for pp in glob_path.glob("2022*")]
phase = pn.widgets.FloatSlider(name="Phase", start=0, end=np.pi)
fileSel = pn.widgets.Select(name='Select File', options=file_list)
#pn.depends(fileSel=fileSel)
def selectedFile(fileSel):
base_path = r"C:\Users\spart\Documents\Anaconda-Work-Dir\{}".format(fileSel)
return pn.widgets.StaticText(name='Selected', value=base_path)
#pn.depends(fileSel=fileSel)
def dataXArray(fileSel):
base_path = r"C:\Users\spart\Documents\Anaconda-Work-Dir\{}".format(fileSel)
xds = fstd2nc.Buffer(base_path).to_xarray()
return xds.ES.hvplot( width=500)
bootstrap.sidebar.append(fileSel)
bootstrap.sidebar.append(selectedFile)
bootstrap.main.append(
pn.Row(
pn.Card(hv.DynamicMap(dataXArray), title='Plot'),
)
)
bootstrap.show()
EDIT : Here is a link to an example dataset which can be loaded with the following code
xds = fstd2nc.Buffer(PATH_TO_FILE).to_xarray()
Without the data file I can't easily run the code, but some observations:
If using bare functions like this rather than classes, I'd recommend using pn.bind rather than pn.depends; it really helps get the code organized better.
For a simple application like this, I'd use hvPlot .interactive: https://hvplot.holoviz.org/user_guide/Interactive.html
I can't seem to find this in the docs, but you can pull out the widgets from the result of dataXArray (or any other hvplot or holoviews object) using .widgets(), and you can then put that in the sidebar. You can then pull out just the plot using .panel(), and put that in the main area.
If that helps you get it done, then great; if not please post a sample data file or two so that it's runnable, and I can look into it further. And please submit a PR to the docs once you get it working so that future users have less trouble!
Related
I'm trying to plot some points on a map, and when searching on the internet, I found [this][1] tutorial with Google Maps and Bokeh library. The problem is that, after doing all the steps to get a key in google api, to set the environment variable, when I try to plot, it says that google maps weren't able to load.
Since I don't have much time, and I really need to plot some data (UTM coordinates, that I Intend to transform to latitude and longitude with pyproj), I was wondering if someone knows, another library, with examples, easy to work, with where I could plot my data (is a pandas dataframe with East, Northing, Elevation).
This is the code from the example I'm trying to reproduce:
import os
ACCESS_KEY_ID = os.environ.get('ACCESS_KEY_ID')
api_key = os.environ['SECRET_ACCESS_KEY']
import pandas as pd
from bokeh.io import output_notebook
df = pd.read_csv('dvf_gex.csv')
lat, lon = 46.2437, 6.0251
from bokeh.io import show
from bokeh.plotting import gmap
from bokeh.models import GMapOptions
bokeh_width=500
bokeh_height=500
def plot(lat, lng, zoom=10, map_type='roadmap'):
gmap_options = GMapOptions(lat=lat, lng=lng,
map_type=map_type, zoom=zoom)
p = gmap(api_key, gmap_options, title='Pays de Gex',
width=bokeh_width, height=bokeh_height)
show(p)
return p
this is the error I got:
[![enter image description here][2]][2]
The error I get on my browser console is:
[![enter image description here][3]][3]
I have activated the Maps Embed API, is that enough? should I have another API activated?
[1]: https://thedatafrog.com/en/articles/show-data-google-map-python/#commento-login-box-container
[2]: https://i.stack.imgur.com/SxoXS.png
[3]: https://i.stack.imgur.com/rjqc2.png
I guess Google has retired the GMap version that Bokeh 2.4.2 specifies by default? That is pretty annoying and user-unfriendly of them. However, you can specify any API version to use by passing it to gmap, e.g.
gmap(api_key, api_version="3.47", ...)
I am using PyQGIS to import a csv file with a lat and long, when doing this I am using the appropriate crs of EPSG:4326.
I'm plotting this onto Google Maps.
I load my basemap, then import my CSV. The issue is that my basemap projection then changes to 4326 and I need it to remain on 3857.
I've tried importing the basemap after the CSV and moving it down in the layers, however this still changes the projections.
import requests
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from qgis.core import *
from qgis.utils import iface
from qgis import core
#Use Google Street Map as QGIS basemap.
service_url = "mt1.google.com/vt/lyrs=m&x={x}&y={y}&z={z}"
service_uri = "type=xyz&zmin=0&zmax=21&url=https://"+requests.utils.quote(service_url)
tms_layer = iface.addRasterLayer(service_uri, "GoogleSat", "wms")
#Import CSV and plot.
uri = 'file:///home/user/fred.csv?type=csv&xField=%s&yField=%s&crs=%s' % ("Site Longitude", "Site Latitude", "EPSG:4326")
layer_csv = QgsVectorLayer(uri, 'fred', 'delimitedtext')
layer_csv.isValid()
QgsProject.instance().addMapLayer(layer_csv)
I'll be the first to admit I'm a novice with QGIS!
It seems this has something to do with the application not refreshing properly as mentioned in this answer on gis stack. You may want to look into it for details.
To answer your question in brief, you can add QApplication.instance().processEvents() after QgsProject.instance().addMapLayer(layer_csv) and then use setCrs() to set your basemap CRS to whatever value you need. It will hold.
proj = QgsProject.instance()
proj.addMapLayer(layer_csv)
# This line makes the difference
QApplication.instance().processEvents()
# This sets the project CRS back to 3857
proj.setCrs(QgsCoordinateReferenceSystem(3857))
I have this code based on this question, just a different point Extract constrained polygon using OSMnx
I am trying to plot the block in which the point is located but it does nothing, it just prints "Done" but I cannot see any image
import osmnx as ox
import geopandas as gpd
import shapely
point = (50.090464, 14.400070)
streets_graph = ox.graph_from_point(point, distance=500, network_type='drive')
streets_graph = ox.project_graph(streets_graph)
streets = ox.save_load.graph_to_gdfs(streets_graph, nodes=False, edges=True,
node_geometry=False, fill_edge_geometry=True)
point = streets.unary_union.centroid
polygons = shapely.ops.polygonize(streets.geometry)
polygons = gpd.GeoSeries(polygons)
target = polygons.loc[polygons.contains(point)]
target_streets = streets.loc[streets.intersection(target.iloc[0]).type == 'MultiLineString']
ax = target_streets.plot()
gpd.GeoSeries([point]).plot(ax=ax, color='r')
print("Done")
I do not think this may help but I am using Visual Studio Code
Thank you very much
Since my comment answered your question, I will summarize it here for other people:
When using plotting library dependent on matplotlib, like geopandas or seaborn, you will need to import matplotlib in order to show the plot. The way matplotlib is imported will depend on whether you are using Jupyter or simple scripting (.py) files.
For Jupyter you need to import it like this:
%matplotlib inline
For simple scripting (.py) file you need to import it like this:
import matplotlib.pyplot as plt
Then when you want to show your plot you simply do
plt.show()
Hope it helps!
Plotly.js includes all the parameters needed to configure the ModeBar, which allows one to take away options from the display bar (such as the link to edit the graph online). However, this does not appear implemented in the Plotly.py API. In the js version:
Plotly.newPlot('myDiv', data, layout, {displayModeBar: false});
Removes the modebar entirely.
Plotly.newPlot('myDiv', data, layout, {displaylogo: false}, {modeBarButtonsToRemove: ['sendDataToCloud','hoverCompareCartesian']}) allows one to specify each button to remove which I'd like to implement.
I've edited this as I've found a workaround... see the answer I posted below. Can come in handy for those that have other parameters that they would like to use.
Open the HTML file, search for modeBarButtonsToRemove:[] then replace with the buttons you want removed, for my purpose modeBarButtonsToRemove:['sendDataToCloud']
To remove the Plotly Logo and link, search for displaylogo:!0 and replace with displaylogo:!1
Here is a demo using Python:
from plotly.offline import plot
import plotly.graph_objs as go
import webbrowser
import numpy as np
import pandas as pd
# generate your Plotly graph here
N = 500
y = np.linspace(0, 1, N)
x = np.random.randn(N)
df = pd.DataFrame({'x': x, 'y': y})
data = [go.Histogram(x=df['x'])]
# plot it for offline editing
HTMLlink = plot(data, show_link=False, auto_open=False)[7:] #remove the junk characters
# now need to open the HTML file
with open(HTMLlink, 'r') as file :
tempHTML = file.read()
# Replace the target strings
tempHTML = tempHTML.replace('displaylogo:!0', 'displaylogo:!1')
tempHTML = tempHTML.replace('modeBarButtonsToRemove:[]', 'modeBarButtonsToRemove:["sendDataToCloud"]')
with open(HTMLlink, 'w') as file:
file.write(tempHTML)
del tempHTML
webbrowser.open(HTMLlink)
This is the compact code. No need in the workaround.
plot(figure, filename='my_chart.html', show_link=False,
config=dict(displaylogo=False,
modeBarButtonsToRemove=['sendDataToCloud']))
cool workaround. There's a PR for this here: https://github.com/plotly/plotly.py/pull/410.
However there was some debate as to the implementation and thus it hasn't been merged.
I am trying to learn how to read .nc (netcdf) files using Python in the most easiest/fastest way. I heard that it can be done with 3 lines of code but I really don't know how.
I am running the MITgcm numerical model. I'm trying to get an easy way to visualize the output data in the same way as programs like NCview does but with Python, so I can customise the parameters to read and everything.
I found this:
from matplotlib import pyplot as plt
import pandas as pd
import netCDF4
fp='uwstemp.nc'
nc = netCDF4.Dataset(fp)
plt.imshow(nc['Temp'][1,:,0,:])
plt.show()
It worked roughly like I want it, but I would like to understand word by word what is it doing. I guess 'Temp' is one of my variables, but I don't know how to figure out what all my variables are.
Specially, I don't understand plt.imshow(nc['Temp'][1,:,0,:]) thhat [1,:,0,:] I tried to change it and does not compile; but I don't understand what is it doing and why this numbers.
I use the MITgcm too. Say you have your state.nc output.
First of all make sure you import all you need:
from scipy.io import netcdf
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
The easiest way to read the data is:
file2read = netcdf.NetCDFFile(path+'state.nc','r')
temp = file2read.variables[var] # var can be 'Theta', 'S', 'V', 'U' etc..
data = temp[:]*1
file2read.close()
Then a quick way to plot say layer z at time t is:
plt.contourf(data[t,z,:,:])
To answer your question I commented the code:
from matplotlib import pyplot as plt # import libraries
import pandas as pd # import libraries
import netCDF4 # import libraries
fp='uwstemp.nc' # your file name with the eventual path
nc = netCDF4.Dataset(fp) # reading the nc file and creating Dataset
""" in this dataset each component will be
in the form nt,nz,ny,nx i.e. all the variables will be flipped. """
plt.imshow(nc['Temp'][1,:,0,:])
""" imshow is a 2D plot function
according to what I have said before this will plot the second
iteration of the vertical slize with y = 0, one of the vertical
boundaries of your model. """
plt.show() # this shows the plot
If you want to check the various dimensions of your data so you know what you can plot simply do print(nc['Temp'].shape)
For netCDF4 files (with python 3), use:
import netCDF4
file2read = netCDF4.Dataset(cwd+'\filename.nc','r')
var1 = file2read.variables['var1'] # access a variable in the file
where cwd is my current working directory for getting the file path for the .nc file in order to read it:
import os
cwd = os.getcwd()
I am using Windows, so file directory will be different than for Mac or Linux.
To look at all of the variable keys:
print(file2read.variables.keys())
Which will give an output like this:
dict_keys(['ap', 'ap_bnds', 'b', 'b_bnds', 'bnds', 'ch4', 'lat', 'lat_bnds', 'lev', 'lev_bnds', 'lon', 'lon_bnds', 'time', 'time_bnds'])
Or to look at all of the variables in your netcfd4 file, you can just print 'file2read':
print(file2read)
And the output will include something like this (look at the end specifically):
source_id: GFDL-ESM4
source_type: AOGCM AER CHEM BGC
sub_experiment: none
sub_experiment_id: none
title: NOAA GFDL GFDL-ESM4 model output prepared for CMIP6 update of RCP8.5 based on SSP5
variable_id: ch4
variant_info: N/A
references: see further_info_url attribute
variant_label: r1i1p1f1
dimensions(sizes): lev(49), bnds(2), time(1032), lat(180), lon(288)
variables(dimensions): float64 ap(lev), float64 ap_bnds(lev, bnds), float64 b(lev), float64 b_bnds(lev, bnds), float64 bnds(bnds), float32 ch4(time, lev, lat, lon), float64 lat(lat), float64 lat_bnds(lat, bnds), float64 lev(lev), float64 lev_bnds(lev, bnds), float64 lon(lon), float64 lon_bnds(lon, bnds), float64 time(time), float64 time_bnds(time, bnds)
You can notice that the last part includes the dimensions of the variables along with the type and name of the variables.
Check out this website for more info and examples:
https://www.earthinversion.com/utilities/reading-NetCDF4-data-in-python/
If you are working in Linux, my package nctoolkit (toolkit.readthedocs.io/en/latest/) offers similar functionality to ncview, but within Python. It can autoplot the contents of NetCDF files either within a Jupyter notebook or a web browser. The following should work for the data given:
import nctoolkit as nc
fp='uwstemp.nc'
data = nc.open_data(fp)
data.plot()