I am attempting to plot a downloaded .nc file containing geographical climate data.
In the last step, I get a syntax error for the following line: plt.gcf().set_size_inches(20,10). I cannot seem to locate the error.
After successfully downloading the file, this is the code I used to plot the data:
import numpy as np
import xarray # used for reading the data.
import matplotlib.pyplot as plt # used to plot the data.
import ipywidgets as widgets # For ease in selecting variables.
import cartopy.crs as ccrs # Used to georeference data.
filelist_arr = [save_dir + os.path.basename(file) for file in filelist]
selected_file = widgets.Dropdown(options=filelist_arr, description='data file')
display(selected_file)
# Now to load in the data to xarray
ds = xarray.open_dataset(selected_file.value)
# Helper methods# Define function to get standard dimensions
def get_time(dataset):
for _,cur_coord in dataset.coords.items:
if cur_coord.attrs['standard_name'] == 'time':
return cur_coord
def get_lat(dataset):
for _,cur_coord in dataset.coords.items:
if cur_coord.attrs['standard_name'] == 'longitude':
return cur_coord
def get_lon(dataset):
for _,cur_coord in dataset.coords.items:
if cur_coord.attrs['standard_name'] == 'latitude':
return cur_coord
def get_primary(dataset):
primary_variables = {}
coords = dataset.coords.keys()
highest_dims = 0
for cur_key,cur_var in dataset.variables.items():
if cur_key not in coords:
primary_variables[cur_key] = cur_var
return primary_variables
var = widgets.Dropdown(
options=get_primary(ds).keys(),
description='Variable')
display(var)
So far so good. Now, in the final block, I get a syntax error in line 3.
var = widgets.Dropdown(
proj = ccrs.Mercator()
plt.gcf().set_size_inches(20,10)
ax = plt.axes(projection=proj)
data_slice = ds[var.value].isel(time=10)
data_slice.plot.contourf(ax=ax, transform=ccrs.PlateCarree())
ax.set_global()
ax.coastlines()
This is the error:
File "<ipython-input-80-8848cc5cc689>", line 3
plt.gcf().set_size_inches(20,10)
^
SyntaxError: invalid syntax
Can anybody explain what I am doing wrong?
I think you got a little bit confused by trying to wrap the code inside the widgets.Dropdown() code.
Perhaps it's a good idea to write the code without widgets first, and then add them later if your code works. Can you try the following code, and see which errors appears then:
import numpy as np
import xarray
import matplotlib.pyplot as plt
import ipywidgets as widgets
import cartopy.crs as ccrs
# Load data into memory
filelist_arr = [save_dir + os.path.basename(file) for file in filelist]
selected_file = widgets.Dropdown(options=filelist_arr, description='data file')
# Create xarray
ds = xarray.open_dataset(selected_file.value)
# Helper methods
def get_time(dataset):
for _,cur_coord in dataset.coords.items:
if cur_coord.attrs['standard_name'] == 'time':
return cur_coord
def get_lat(dataset):
for _,cur_coord in dataset.coords.items:
if cur_coord.attrs['standard_name'] == 'longitude':
return cur_coord
def get_lon(dataset):
for _,cur_coord in dataset.coords.items:
if cur_coord.attrs['standard_name'] == 'latitude':
return cur_coord
def get_primary(dataset):
primary_variables = {}
coords = dataset.coords.keys()
highest_dims = 0
for cur_key,cur_var in dataset.variables.items():
if cur_key not in coords:
primary_variables[cur_key] = cur_var
return primary_variables
# Ask user to select dataset
var = widgets.Dropdown(
options=get_primary(ds).keys(),
description='Variable')
display(var)
# Initialize new figure and specify figure size
plt.figure(num=None, figsize=(20, 10))
# Create Mercator projection with dateline in the middle
ax = plt.axes(projection=ccrs.Mercator(central_longitude=180))
# Draw coastlines
ax.coastlines()
# Select the appropriate data and plot to the axes
data_slice = ds[var.value].isel(time=10)
data_slice.plot.contourf(ax=ax, transform=ccrs.PlateCarree())
# Optional: set the map extent, for geographical coordinates
# ax.set_extent([90, 270, -40, 40], crs=ccrs.PlateCarree())
# Optional: add title
# plt.title('Geographical climate data at time = 10')
# Show the plot
plt.show()
If this still gives an error, please let me know in the comments below.
Related
I have a dictionary named density, I am trying to create a US state map as the color shows the density of the state. I am trying to replicate this use Basemap (Python) to plot US with 50 states
however I am getting error.
This is my data:
density = {'NY': 648.0,
'FL': 696.0,
'TX': 833.0,
'CA': 927.0,
'PA': 472.0,
'OH': 721.0,
'NJ': 645.0,
'IL': 607.0,
'MI': 570.0,
'AZ': 616.0,
'GA': 799.0,
'MD': 652.0,
'NC': 720.0,
'LA': 546.0,
'TN': 806.0,
'MO': 564.0,
'SC': 574.0,
'VA': 818.0,
'IN': 780.0,
'AL': 619.0,
'MA': 626.0,
'WA': 749.0,
'KY': 680.0,
'WI': 615.0,
'OK': 633.0,
'MN': 743.0,
'IA': 543.0,
'WV': 599.0,
'MS': 695.0,
'AR': 698.0,
'OR': 878.0,
'CO': 782.0,
'NV': 930.0,
'KS': 637.0,
'CT': 1078.0,
'UT': 580.0,
'NM': 667.0,
'NE': 552.0,
'PR': 698.0,
'ME': 702.0,
'ID': 679.0,
'DE': 845.0,
'NH': 668.0,
'RI': 616.0,
'HI': 1131.0,
'DC': 711.0,
'MT': 653.0,
'SD': 495.0,
'ND': 685.0,
'VT': 754.0,
'AK': 1080.0,
'WY': 1028.0,
'VI': 1261.0,
'GU': 889.0}
Here is my code which I get the error.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap as Basemap
from matplotlib.colors import rgb2hex
from matplotlib.patches import Polygon
m = Basemap(llcrnrlon=-119,llcrnrlat=22,urcrnrlon=-64,urcrnrlat=49,
projection='lcc',lat_1=33,lat_2=45,lon_0=-95)
shp_info = m.readshapefile('st99_d00','states',drawbounds=True)
colors={}
statenames=[]
cmap = plt.cm.hot # use 'hot' colormap
vmin = 0; vmax = 450 # set range.
for shapedict in m.states_info:
statename = shapedict['NAME']
if statename not in ['District of Columbia','Puerto Rico']:
pop = popdensity[statename]
colors[statename] = cmap(1.-np.sqrt((pop-vmin)/(vmax-vmin)))[:3]
statenames.append(statename)
ax = plt.gca() # get current axes instance
for nshape,seg in enumerate(m.states):
if statenames[nshape] not in ['Puerto Rico', 'District of Columbia']:
if statenames[nshape] == 'Alaska':
seg = list(map(lambda (x,y): (0.35*x + 1100000, 0.35*y-1300000), seg))
if statenames[nshape] == 'Hawaii':
seg = list(map(lambda (x,y): (x + 5100000, y-900000), seg))
color = rgb2hex(colors[statenames[nshape]])
poly = Polygon(seg,facecolor=color,edgecolor=color)
ax.add_patch(poly)
plt.title('******')
plt.show()
I am confused what I need to do to this code work.
I am new to pyhton, any help and feedback is highly appreciated.
TIA!
I am trying to create a choropleth map of the uk using plotly, but every time I try, it outputs an empty page, or the json doesn't match with the dataframe.this is where i obtained the url for the dataframe Here's my code so far:
import pandas as pd
from urllib.request import urlopen
import json
with urlopen('https://raw.githubusercontent.com/deldersveld/topojson/master/countries/united-kingdom/uk-counties.json') as response:
geojson = json.load(response)
url3 = 'https://api.coronavirus.data.gov.uk/v2/data?areaType=utla&metric=cumCasesBySpecimenDate&metric=cumPeopleVaccinatedFirstDoseByVaccinationDate&metric=cumPeopleVaccinatedSecondDoseByVaccinationDate&metric=newCasesBySpecimenDate&metric=cumPeopleVaccinatedThirdInjectionByVaccinationDate&format=csv'
df = pd.read_csv(url3)
df_new=df.replace("areaName", "NAME_2")
from plotly import graph_objects as go
fig = go.Figure(
go.Choroplethmapbox(
geojson=geojson,
featureidkey="properties.NAME_2",
locations=df["areaCode"],
z=df['cumCasesBySpecimenDate'],
zauto=True,
colorscale='Reds',
showscale=True,
)
)
fig.show()
a few things to fix this up:
uk-counties.json is in topojson format, plotly needs a geojson. can fix with the topojson module, for example (or geopandas)
no need to replace "areaName", you want this: locations=df["areaName"]
you need to specify a marker_style. centering and zooming help as well
for good result you need to use only one day's worth of data per choropleth, hence the df = df[df['date'] == '2022-11-23']
the covid data and the topojson don't match up well by districts, so there are gaps in the map
code:
"""
https://stackoverflow.com/questions/71828342/choropleth-plotly-map-displaying-a-white-background
"""
from urllib.request import urlretrieve
import json
from io import StringIO
from plotly import graph_objects as go
import pandas as pd
import topojson as tp
URL_JSON = 'https://raw.githubusercontent.com/deldersveld/topojson/master/countries/united-kingdom/uk-counties.json'
URL_DATA = 'https://api.coronavirus.data.gov.uk/v2/data?areaType=utla&metric=cumCasesBySpecimenDate&metric=cumPeopleVaccinatedFirstDoseByVaccinationDate&metric=cumPeopleVaccinatedSecondDoseByVaccinationDate&metric=newCasesBySpecimenDate&metric=cumPeopleVaccinatedThirdInjectionByVaccinationDate&format=csv'
CSV_DATA = 'uk_covid.csv'
TOPO_DATA = 'topojson.json'
GEO_DATA = 'geojson.json'
def download():
urlretrieve(URL_JSON, TOPO_DATA)
with open(TOPO_DATA, 'r') as data:
topoJSON = json.load(StringIO(data.read()))
topo = tp.Topology(topoJSON, object_name='GBR_adm2')
# convert to geojson, store in GEO_DATA
topo.to_geojson(GEO_DATA)
df = pd.read_csv(URL_DATA)
df.to_csv(CSV_DATA)
def make_map():
df = pd.read_csv(CSV_DATA)
with open(GEO_DATA, 'r') as data:
geojson = json.load(StringIO(data.read()))
# one day at a time
df = df[df['date'] == '2022-11-23']
fig = go.Figure(
go.Choroplethmapbox(
geojson=geojson,
featureidkey="properties.NAME_2",
locations=df["areaName"], # <=== not areaCode
z=df['cumCasesBySpecimenDate'],
zauto=True,
colorscale='Reds',
showscale=True
)
)
# need a mapbox_style
fig.update_layout(mapbox_style='carto-positron',
mapbox_zoom=5,
mapbox_center_lon=-2.057852,
mapbox_center_lat=53.404854,
height=700,
width=700)
fig.show()
if 0: # only needed once
download()
make_map()
Why does my figure only shows 1 legend, would like the legend to show the label for both of the DataFrames. I found a similar problem but I cant apply it to my data:Legend only shows one label when plotting with pandas
Data:https://github.com/DwightZC/Learning
data=pd.read_csv('Data gathered1.csv')
data
data['CONTAMINANTS'] = data['CONTAMINANTS'].str.split(pat=', ')
data_long = data.explode('CONTAMINANTS')
data_long['CONTAMINANTS'].value_counts()
ACT = {'0': 'No Activity',
'1A' : 'CONTAMINATION CONFIRMED',
'1B' : 'CONTAMINATION CONFIRMED',
'2A' :'INVESTIGATION',
'2B': 'INVESTIGATION',
'3':'CORRECTIVE ACTION PLANNING',
'4': 'IMPLEMENT ACTION',
'5': 'MONITOR ACTION',
'6':'INACTIVE'
}
data['STATUS'] = data['ACT-STATUS'].apply(lambda x: ACT[x])
data
color = { 'No Activity': 'black',
'CONTAMINATION CONFIRMED':'lightblue',
'INVESTIGATION':'red',
'CORRECTIVE ACTION PLANNING':'pink',
'IMPLEMENT ACTION':'yellow',
'MONITOR ACTION':'green',
'INACTIVE':'gray'
}
data['COLOR'] = data['STATUS'].apply(lambda x: color[x])
data
x=data['LONGITUDE']
y= data["LATITUDE"]
import cartopy.io.shapereader as shpreader
reader = shpreader.Reader('cb_2018_us_county_5m')
counties = list(reader.geometries())
COUNTIES = cfeature.ShapelyFeature(counties, ccrs.PlateCarree())
reader2 = shpreader.Reader('City')
city = list(reader2.geometries())
Cities = cfeature.ShapelyFeature(city, ccrs.PlateCarree())
import matplotlib.pyplot as plt
import numpy as np
import cartopy.crs as ccrs
import cartopy.io.img_tiles as cimgt
import io
from urllib.request import urlopen, Request
from PIL import Image
def image_spoof(self, tile): # this function pretends not to be a Python script
url = self._image_url(tile) # get the url of the street map API
req = Request(url) # start request
req.add_header('User-agent','Anaconda 3') # add user agent to request
fh = urlopen(req)
im_data = io.BytesIO(fh.read()) # get image
fh.close() # close url
img = Image.open(im_data) # open image with PIL
img = img.convert(self.desired_tile_form) # set image format
return img, self.tileextent(tile), 'lower' # reformat for cartopy
cimgt.OSM.get_image = image_spoof # reformat web request for street map spoofing
osm_img = cimgt.OSM() # spoofed, downloaded street map
fig = plt.figure(figsize=(12,9)) # open matplotlib figure
ax1 = plt.axes(projection=osm_img.crs) # project using coordinate reference
system (CRS) of street
mapcenter_pt = [26.2271, -98.2087] # lat/lon hidalgo
zoom = 0.5 # for zooming out of center point
extent = [center_pt[1]-(zoom*2.0),center_pt[1]+(zoom*2.0),center_pt[0]-
zoom,center_pt[0]+zoom] #
adjust to zoom
ax1.set_extent(extent) # set extents
ax1.scatter(x,y,c=data['COLOR'], transform=ccrs.PlateCarree())
scale = np.ceil(-np.sqrt(2)*np.log(np.divide(zoom,350.0))) # empirical solve
for scale based on zoom
scale = (scale<20) and scale or 19 # scale cannot be larger than 19
ax1.add_image(osm_img, int(scale)) # add OSM with zoom specification
ax1.set_title("Hidalgo County")
#ax1.add_feature(COUNTIES, facecolor='none', edgecolor='gray')
#ax1.add_feature(Cities, facecolor='none', edgecolor='gray')
plt.show()
I downloaded your data file to my PC, then I wrote the following
import numpy as np
import matplotlib.pyplot as plt
from csv import reader
# the following two dicts are copied from your question
ACT = {'0': 'No Activity', '1A' : 'CONTAMINATION CONFIRMED',
'1B' : 'CONTAMINATION CONFIRMED', '2A' :'INVESTIGATION',
'2B': 'INVESTIGATION', '3':'CORRECTIVE ACTION PLANNING',
'4': 'IMPLEMENT ACTION', '5': 'MONITOR ACTION', '6':'INACTIVE'}
color = {'No Activity': 'black', 'CONTAMINATION CONFIRMED':'lightblue',
'INVESTIGATION':'red', 'CORRECTIVE ACTION PLANNING':'pink',
'IMPLEMENT ACTION':'yellow', 'MONITOR ACTION':'green', 'INACTIVE':'gray'}
# but we don't need ACT, we need its inverse…
ACT2codes = {}
for k, v in ACT.items(): ACT2codes.setdefault(v, []). append(k)
# ######################## let's read the data ########################
# lines is a generator, returns lines split on commas (respecting quoting)
# data is a dictionary of tuples of strings, indexed by the headers
lines = reader(open('hidalgo.csv', 'r'))
data = {k:v for k, v in zip(next(lines), zip(*lines))}
# but something it's better understood as an array of floats
for k in ('LONGITUDE', 'LATITUDE'):
data[k] = np.array([float(item) for item in data[k]])
# and something else is better understood as an array of strings,
# because we'll use np.where to find the indices required for plotting
data['ACT-STATUS'] = np.array(data['ACT-STATUS'])
# ######################## ready to plot ########################
plt.figure(constrained_layout=1)
# for each action, plot some points with same color and same label
for action in ACT2codes.keys():
# what are the indices of this batch of points?
idx = []
for code in ACT2codes[action]:
idx += list(*np.where(data['ACT-STATUS']==code))
plt.scatter(data['LONGITUDE'][idx],
data['LATITUDE'][idx],
color=color[action], label=action)
plt.legend() ; plt.show()
I'm sorry but I don't know very well pandas, so I haven't used it… on the other hand it seems that slurping the data using the csv module isn't overly complicated — also, I omitted all the cartographic stuff, to keep in evidence the data processing stages.
I would like to let my code read my txt file one by one, convert it into image, and save it with different image, i.e 300s, 600s, 900s,....
I made the code down and it says only the path but did not proceed with its next code.
Could you give me some advice or find the missing or mistaken part of my codes?
import numpy as np
import matplotlib.pyplot as plt
import glob
import cv2
import os
path = './Master_thesis/Code/dnn_simulation_result/'
interval = 300
folders = []
#r=root, d=dirctories, f=files
for r, d, f in os.walk(path):
if not d:
folders.append(r)
for f in folders:
print(r)
def txt2image(folders, skiprows) :
for folder_name in folders:
IsFile=(glob.glob(folder_name+"/*.*"))
for file in IsFile:
myArray = np.loadtxt(path, skiprows = skiprows)
# Set the nodata values to nan
myArray[myArray == -9999] = np.nan
# PRISM data is stored as an integer but scaled by 100
myArray *= 1
# Plot PRISM array again
fig, ax = plt.subplots()
ax.set_title('Flood area')
# Get the img object in order to pass it to the colorbar function
img_plot = ax.imshow(myArray, cmap='jet')
# Place a colorbar next to the map
cbar = fig.colorbar(img_plot)
ax.grid(True)
plt.show()
txt2image = cv2.imwrite('D:/Master_thesis/Code/dnn_simulation_result/dnn_simulation_result/{}.jpg', img_plot)
return txt2image
txt2image(folders, 0)
When I run this code
import Scientific.IO.NetCDF as S
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import matplotlib.pyplot as plt
import xarray as xr
import metpy
import numpy as N
from metpy.plots import ContourPlot, ImagePlot, MapPanel, PanelContainer
# Any import of metpy will activate the accessors
import metpy.calc as mpcalc
#from metpy.testing import get_test_data
from metpy.units import units
# Open the netCDF file as a xarray Datase
#
datadir='C:/Users/stratus/AppData/Local/lxss/home/stratus/PROJECT/NEWPROJECT/FEB012017/nam_218_20170131_1200_000.nc'
data = xr.open_dataset(datadir,decode_cf=True)
# To parse the full dataset, we can call parse_cf without an argument, and assign the returned
# Dataset.
data = data.metpy.parse_cf()
tempatt=data['TMP_P0_L100_GLC0'].attrs
# If we instead want just a single variable, we can pass that variable name to parse_cf and
# it will return just that data variable as a DataArray.
data_var = data.metpy.parse_cf('TMP_P0_L100_GLC0')
# To rename variables, supply a dictionary between old and new names to the rename method
data.rename({
'TMP_P0_L100_GLC0': 'temperature',
}, inplace=True)
data['temperature'].metpy.convert_units('degC')
# Get multiple coordinates (for example, in just the x and y direction)
x, y = data['temperature'].metpy.coordinates('x', 'y')
# If we want to get just a single coordinate from the coordinates method, we have to use
# tuple unpacking because the coordinates method returns a generator
vertical, = data['temperature'].metpy.coordinates('vertical')
data_crs = data['temperature'].metpy.cartopy_crs
# Or, we can just get a coordinate from the property
#time = data['temperature'].metpy.time
# To verify, we can inspect all their names
#print([coord.name for coord in (x, y, vertical, time)])
#
#heights = data['height'].metpy.loc[{'time': time[0], 'vertical': 850. * units.hPa}]
#lat, lon = xr.broadcast(y, x)
#f = mpcalc.coriolis_parameter(lat)
#dx, dy = mpcalc.grid_deltas_from_dataarray(heights)
#u_geo, v_geo = mpcalc.geostrophic_wind(heights, f, dx, dy)
#print(u_geo)
#print(v_geo)
fig=plt.figure(1)
# A very simple example example of a plot of 500 hPa heights
data_crs = data['temperature'].metpy.cartopy_crs
ax = plt.axes(projection=ccrs.LambertConformal())
data['temperature'].metpy.loc[{'vertical': 850. * units.hPa}].plot(ax=ax, transform=data_crs)
ax.add_feature(cfeature.LAND)
ax.add_feature(cfeature.OCEAN)
ax.add_feature(cfeature.COASTLINE)
plt.show()
#ax.set_extent([-120,-80,20,50])
plt.title("850 mb Temperature")
#plt.suptitle("Metpy Test")
plt.show()
I had to edit the code as per some of the answers but I am getting a mostly blank map now. 850 T Map fail I am mainly trying to have the temperatures at 850 mb overlap the US so I could show it to a friend to practice for a project I am helping him with. The filling of the parentheses for the data helped a bit which is why I edited it.
As pointed out in the comments it is difficult to answer without a reproducible example. However, the following may solve your issue:
data_crs = data['temperature'].metpy.cartopy_crs
ax = plt.axes(projection=ccrs.LambertConformal())
data['temperature'].metpy.loc[{'vertical': 1000. * units.hPa}].plot(ax=ax, transform=data_crs)
ax.add_feature(cfeature.LAND)
ax.add_feature(cfeature.OCEAN)
ax.add_feature(cfeature.COASTLINE)
plt.show()