How do i annotate with a subscripted text in matplotlib? - python

Im attempting to plot some data with matplotlib and i need some of the annotate to be formated like math/chem formulas.
here is some of my code.
#!/usr/bin/python2
import numpy as np
import matplotlib.pyplot as pytl
from matplotlib import rc
rc('font',**{'family':'sans-serif','sans-serif':['Helvetica']})
rc('text', usetex=True)
recdt = np.dtype([('compound',str,4),('H_v','f4'),('B_o','f4')]);
gat = np.loadtxt('tra',dtype=object, usecols=(0,1,2),unpack=True);
gct,ght,gbt=[],[],[]
for c,h,b in np.transpose(gat):
gct=np.append(gct,c)
ght=np.append(ght,h)
gbt=np.append(gbt,b)
ght= ght.astype(np.float)
gbt= gbt.astype(np.float)
hard = pytl
four = hard #####
four.scatter(gbt,ght)
hard.title( 'physical stuff' )
hard.xlabel('physical prop 1')
hard.ylabel('physical prop2 ')
for l,x1,y2 in zip ( gct,gbt,ght):
hard.annotate( l,xy=(x1,y2),xytext=(-24,12),textcoords = 'offset points', arrowprops = dict(arrowstyle = '->', connectionstyle = 'arc3,rad=0'),rotation=0 )
hard.ylim([0,10])
hard.savefig('hardcomp.png')
hard.show()
and here is some test data
ZrC 6.8 1
NbC 8 2
NbN 7 13
RuB2 30 5
BP 3 1
AlP 9.4 3
InSb 2.2 47
C 6 4
the data is in three columns one text the other two are numbers.
i'd like the '2' in 'RbB2' to end up as a subscript.

We can display the 2 in 'RbB2' with a subscript, by using TeX notation: $\tt{RbB_{2}}$. In the code, you just have to modify c:
import re
for c,h,b in np.transpose(gat):
c = r'$\tt{{{c}}}$'.format(c = re.sub(r'(\d+)',r'_{\1}', c))
which yields
import re
import numpy as np
import matplotlib.pyplot as pytl
from matplotlib import rc
rc('font', **{'family':'sans-serif', 'sans-serif':['Helvetica']})
rc('text', usetex = True)
recdt = np.dtype([('compound', str, 4), ('H_v', 'f4'), ('B_o', 'f4')]);
gat = np.loadtxt('tra', dtype = object, usecols = (0, 1, 2), unpack = True);
gct, ght, gbt = [], [], []
for c, h, b in np.transpose(gat):
c = r'$\tt{{{c}}}$'.format(c = re.sub(r'(\d+)', r'_{\1}', c))
gct = np.append(gct, c)
ght = np.append(ght, h)
gbt = np.append(gbt, b)
ght = ght.astype(np.float)
gbt = gbt.astype(np.float)
hard = pytl
four = hard #####
four.scatter(gbt, ght)
hard.title( 'physical stuff' )
hard.xlabel('physical prop 1')
hard.ylabel('physical prop2 ')
for l, x1, y2 in zip ( gct, gbt, ght):
print(l, x1, y2)
hard.annotate(
l, xy = (x1, y2), xytext = (-24, 12), textcoords = 'offset points',
arrowprops = dict(arrowstyle = '->', connectionstyle = 'arc3,rad=0'),
rotation = 0 )
hard.ylim([0, 10])
hard.savefig('hardcomp.png')
hard.show()

Related

How to animate a 2D scatter plot given X, Y coordinates and time with appearing and disappearing points?

I have a data frame like the below:
Every row represents a person. They stay at 3 different locations for some time given on the dataframe. The first few people don't stay at location1 but they "born" at location2. The rest of them stay at every locations (3 locations).
I would like to animate every person at the given X, Y coordinates given on the data frame and represent them as dots or any other shape. Here is the flow:
Every person should appear at the first given location (location1) at the given time. Their color should be blue at this state.
Stay at location1 until location2_time and then appear at location2. Their color should be red at this state.
Stay at location2 until location3_time and then appear at location3. Their color should be red at this state.
Stay at location3 for 3 seconds and disappear forever.
There can be several people on the visual at the same time. How can I do that?
There are some good answers on the below links. However, on these solutions, points don't disappear.
How can i make points of a python plot appear over time?
How to animate a scatter plot?
The following is an implementation with python-ffmpeg, pandas, matplotlib, and seaborn. You can find output video on my YouTube channel (link is unlisted).
Each frame with figures is saved directly to memory. New figures are generated only when the state of the population changes (person appears/moves/disappears).
You should definetely separate this code into smaller chunks if you are using this in a Python package:
from numpy.random import RandomState, SeedSequence
from numpy.random import MT19937
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import numpy as np
import ffmpeg
RESOLUTION = (12.8, 7.2) # * 100 pixels
NUMBER_OF_FRAMES = 900
class VideoWriter:
# Courtesy of https://github.com/kylemcdonald/python-utils/blob/master/ffmpeg.py
def __init__(
self,
filename,
video_codec="libx265",
fps=15,
in_pix_fmt="rgb24",
out_pix_fmt="yuv420p",
input_args=None,
output_args=None,
):
self.filename = filename
self.process = None
self.input_args = {} if input_args is None else input_args
self.output_args = {} if output_args is None else output_args
self.input_args["r"] = self.input_args["framerate"] = fps
self.input_args["pix_fmt"] = in_pix_fmt
self.output_args["pix_fmt"] = out_pix_fmt
self.output_args["vcodec"] = video_codec
def add(self, frame):
if self.process is None:
height, width = frame.shape[:2]
self.process = (
ffmpeg.input(
"pipe:",
format="rawvideo",
s="{}x{}".format(width, height),
**self.input_args,
)
.filter("crop", "iw-mod(iw,2)", "ih-mod(ih,2)")
.output(self.filename, **self.output_args)
.global_args("-loglevel", "quiet")
.overwrite_output()
.run_async(pipe_stdin=True)
)
conv = frame.astype(np.uint8).tobytes()
self.process.stdin.write(conv)
def close(self):
if self.process is None:
return
self.process.stdin.close()
self.process.wait()
def figure_to_array(figure):
"""adapted from: https://stackoverflow.com/questions/21939658/"""
figure.canvas.draw()
buf = figure.canvas.tostring_rgb()
n_cols, n_rows = figure.canvas.get_width_height()
return np.frombuffer(buf, dtype=np.uint8).reshape(n_rows, n_cols, 3)
# Generate data for the figure
rs1 = RandomState(MT19937(SeedSequence(123456789)))
time_1 = np.round(rs1.rand(232) * NUMBER_OF_FRAMES).astype(np.int16)
time_2 = time_1 + np.round(rs1.rand(232) * (NUMBER_OF_FRAMES - time_1)).astype(np.int16)
time_3 = time_2 + np.round(rs1.rand(232) * (NUMBER_OF_FRAMES - time_2)).astype(np.int16)
loc_1_x, loc_1_y, loc_2_x, loc_2_y, loc_3_x, loc_3_y = np.round(rs1.rand(6, 232) * 100, 1)
df = pd.DataFrame({
"loc_1_time": time_1,
"loc_1_x": loc_1_x,
"loc_1_y": loc_1_y,
"loc_2_time": time_2,
"loc_2_x": loc_2_x,
"loc_2_y": loc_2_y,
"loc_3_time": time_3,
"loc_3_x": loc_3_x,
"loc_3_y": loc_3_y,
})
"""The stack answer starts here"""
# Add extra column for disappear time
df["disappear_time"] = df["loc_3_time"] + 3
all_times = df[["loc_1_time", "loc_2_time", "loc_3_time", "disappear_time"]]
change_times = np.unique(all_times)
# Prepare ticks for plotting the figure across frames
x_values = df[["loc_1_x", "loc_2_x", "loc_3_x"]].values.flatten()
x_ticks = np.array(np.linspace(x_values.min(), x_values.max(), 6), dtype=np.uint8)
y_values = df[["loc_1_y", "loc_2_y", "loc_3_y"]].values.flatten()
y_ticks = np.array(np.round(np.linspace(y_values.min(), y_values.max(), 6)), dtype=np.uint8)
sns.set_theme(style="whitegrid")
video_writer = VideoWriter("endermen.mp4")
if 0 not in change_times:
# Generate empty figure if no person arrive at t=0
fig, ax = plt.subplots(figsize=RESOLUTION)
ax.set_xticklabels(x_ticks)
ax.set_yticklabels(y_ticks)
ax.set_title("People movement. T=0")
video_writer.add(figure_to_array(fig))
loop_range = range(1, NUMBER_OF_FRAMES)
else:
loop_range = range(NUMBER_OF_FRAMES)
palette = sns.color_palette("tab10") # Returns three colors from the palette (we have three groups)
animation_data_df = pd.DataFrame(columns=["x", "y", "location", "index"])
for frame_idx in loop_range:
if frame_idx in change_times:
plt.close("all")
# Get person who appears/moves/disappears
indexes, loc_nums = np.where(all_times == frame_idx)
loc_nums += 1
for i, loc in zip(indexes, loc_nums):
if loc != 4:
x, y = df[[f"loc_{loc}_x", f"loc_{loc}_y"]].iloc[i]
if loc == 1: # location_1
animation_data_df = animation_data_df.append(
{"x": x, "y": y, "location": loc, "index": i},
ignore_index=True
)
else:
data_index = np.where(animation_data_df["index"] == i)[0][0]
if loc in (2, 3): # location_2 or 3
animation_data_df.loc[[data_index], :] = x, y, loc, i
elif loc == 4: # Disappear
animation_data_df.iloc[data_index] = np.nan
current_palette_size = np.sum(~np.isnan(np.unique(animation_data_df["location"])))
fig, ax = plt.subplots(figsize=RESOLUTION)
sns.scatterplot(
x="x", y="y", hue="location", data=animation_data_df, ax=ax, palette=palette[:current_palette_size]
)
ax.set_xticks(x_ticks)
ax.set_xticklabels(x_ticks)
ax.set_yticks(y_ticks)
ax.set_yticklabels(y_ticks)
ax.legend(loc="center left", bbox_to_anchor=(1, 0.5))
ax.set_title(f"People movement. T={frame_idx}")
video_writer.add(figure_to_array(fig))
video_writer.close()
Edit: There was a bug in which location_3 wasn't removed after 3 seconds. Fixed now.
Modifying the code from this question to only include the positions you want automatically removes the old ones if the old position isn't included in the new ones. This doesn't change if you want to animate by time or iterations or anything else. I have opted to use iterations here since it's easier and I don't know how you are handling your dataset. The code does have one bug though, the last point (or points if they last the same amount of time) remaining won't disappear, this can be solved easily if you don't want to draw anything again, if you do though for exaple in case you there is a gap in the data with no people and then the data resumes I haven't found any workarounds
import math
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
#The t0,t1,t2,t3 are the times (in iterations) that the position changes
#If t0 is None then the person will never be displayed
people = [
# t0 x1 y1 t1 x2 y2 t2 x3 y3 t4
[ 0, 1, 0.1, 1, 2, 0.2, 2, 3, 0.3, 3],
[ 2, None, None, None, 2, 1, 3, 4, 1, 7],
[ 2, float("NaN"), float("NaN"), float("NaN"), 2, 0.8, 4, 4, 0.8, 10],
]
fig = plt.figure()
plt.xlim(0, 5)
plt.ylim(0, 1)
graph = plt.scatter([], [])
def animate(i):
points = []
colors = []
for person in people:
if person[0] is None or math.isnan(person[0]) or i < person[0]:
continue
# Position 1
elif person[3] is not None and not (math.isnan(person[3])) and i <= person[3]:
new_point = [person[1], person[2]]
color = "b"
# Position 2
elif person[6] is not None and not (math.isnan(person[6])) and i <= person[6]:
new_point = [person[4], person[5]]
color = "r"
# Position 3
elif person[9] is not None and not (math.isnan(person[9])) and i <= person[9]:
new_point = [person[7], person[8]]
color = "r"
else:
people.remove(person)
new_point = []
if new_point != []:
points.append(new_point)
colors.append(color)
if points != []:
graph.set_offsets(points)
graph.set_facecolors(colors)
else:
# You can use graph.remove() to fix the last point not disappiring but you won't be able to plot anything after that
# graph.remove()
pass
return graph
ani = FuncAnimation(fig, animate, repeat=False, interval=500)
plt.show()

Calculating (x,y) coordinates from distance matrix

I am having problems calculating the coordinates for the for distance matrix D :
D : R D4 D6
R [[0. 234. 150.]
D4 [234. 0. 231.]
D6 [150. 231. 0.]]
My python code is as follows:
import numpy
from numpy import linalg as LA
import matplotlib.pyplot as plt
import math
def calc_points_and_plot():
distance_matric = numpy.zeros((3, 3))
weight_router_to_dongle_04 = 234
weight_router_to_dongle_06 = 150
weight_dongle_04_to_dongle_06 = 231
distance_matric[0][1] = weight_router_to_dongle_04
distance_matric[0][2] = weight_router_to_dongle_06
distance_matric[1][0] = weight_router_to_dongle_04
distance_matric[1][2] = weight_dongle_04_to_dongle_06
distance_matric[2][0] = weight_router_to_dongle_06
distance_matric[2][1] = weight_dongle_04_to_dongle_06
print(f"dist matric \n {distance_matric}")
m_matrix = numpy.zeros((3, 3))
for i in range(3):
for j in range(3):
m_matrix[i][j] = 0.5 * ((distance_matric[1][j]**2) + (distance_matric[i][1]**2) -(distance_matric[i][j]**2))
print(f"m_matrix \n {m_matrix}")
eigvals, eigvecs = LA.eig(m_matrix)
print(f"eigen vals : \n {eigvals}")
print(f"eigen vectors : \n {eigvecs}")
results = []
for i in range(3):
if eigvals[i] != 0:
results.append(math.sqrt(eigvals[i])*eigvecs[i])
print(f"results \n {results}")
coords = numpy.reshape(results, (2,3)).T
print(coords)
X_vals = [coords[i][0] for i in range(3)]
Y_vals = [coords[i][1] for i in range(3)]
plt.annotate(f"Roouter", xy=(X_vals[0], Y_vals[0]))
plt.annotate(f"device 4", xy=(X_vals[1], Y_vals[1]))
plt.annotate(f"device 6", xy=(X_vals[2], Y_vals[2]))
plt.scatter(X_vals , Y_vals, s=230, c="black", marker="D")
plt.scatter(X_vals , Y_vals, s=180, c="red", marker="D" )
plt.plot([X_vals[0], X_vals[1]], [Y_vals[0], Y_vals[1]], c="red", linewidth=1, linestyle='--')
plt.plot([X_vals[0], X_vals[2]], [Y_vals[0], Y_vals[2]], c="red", linewidth=1, linestyle='--')
plt.plot([X_vals[1], X_vals[2]], [Y_vals[1], Y_vals[2]], c="red", linewidth=1, linestyle='--')
# Verify distances to given distance matrix
dist1 = math.sqrt((X_vals[0]-X_vals[1])**2 + (Y_vals[0]- Y_vals[1])**2)
dist2 = math.sqrt((X_vals[0]-X_vals[2])**2 + (Y_vals[0]- Y_vals[2])**2)
dist3 = math.sqrt((X_vals[1]-X_vals[2])**2 + (Y_vals[1]- Y_vals[2])**2)
print(f"dist1 : {dist1}" )
print(f"dist2 : {dist2}" )
print(f"dist3 : {dist3}" )
plt.show()
if __name__ == "__main__":
calc_points_and_plot()
The following pictures are the actual output and the expected Actual output Expected output
I followed this link finding-the-coordinates-of-points-from-distance-matrix, but still didnt manage to get the correct (x,y) points.
Looking at the actual output, the distance from router to device4 has a point to point distance of 440, even though the given distance matrix says otherwise.

How to distinguish points below and above geolocalised polyline?

I've got two geodataframes - one with polylines and second one containing points; up until now I was working with single polyline and couple of points that look like this. I am trying to achieve an outcome somehow similiar to the one decribed here.
import numpy as np
import math
import matplotlib.pyplot as plt
import matplotlib.mlab as mlab
import pandas as pd
import geopandas as gpd
from shapely import wkt
roadpd = pd.read_csv('roads.csv',delimiter=';')
roadpd['geom'] = roadpd['geom'].apply(wkt.loads)
roadgpd = gpd.GeoDataFrame(roadpd, geometry=roadpd['geom'])
print(roadgpd)
addresspd = pd.read_csv('addresses.csv',delimiter=';')
addresspd['geom'] = addresspd['geom'].apply(wkt.loads)
addressgpd = gpd.GeoDataFrame(addresspd, geometry=addresspd['geom'])
print(addressgpd)
ROA_ID geom geometry
0 23 LINESTRING (16.8978861 52.417438, 16.8971243 5... LINESTRING (16.89789 52.41744, 16.89712 52.417...
ADG_ID geom geometry
0 6641801 POINT (16.89397537268492 52.4186416491154) POINT (16.89398 52.41864)
1 6641802 POINT (16.89458531052842 52.41814952579504) POINT (16.89459 52.41815)
2 6641803 POINT (16.89499192732443 52.41803648483478) POINT (16.89499 52.41804)
3 6641804 POINT (16.89532584370729 52.41794434305021) POINT (16.89533 52.41794)
4 6641805 POINT (16.89553809175901 52.41786913837524) POINT (16.89554 52.41787)
5 6641806 POINT (16.89429797664177 52.41856009093589) POINT (16.89430 52.41856)
6 6641807 POINT (16.89397725037543 52.41832458465358) POINT (16.89398 52.41832)
7 6641808 POINT (16.89376733989525 52.41815994989702) POINT (16.89377 52.41816)
8 6641809 POINT (16.89507474142366 52.418304817806) POINT (16.89507 52.41830)
9 6641810 POINT (16.89417332654704 52.41827195239621) POINT (16.89417 52.41827)
10 6641811 POINT (16.89432223101175 52.41829509557626) POINT (16.89432 52.41830)
So far I couldn't come up with any reasonable solution.
under_curve = addressgpd['geom'] < roadgpd['geom']
Analogical to the previous post idea meets with an obvious error:
Exception has occurred: ValueError
Can only compare identically-labeled Series objects
I have just started programming in Python, so maybe a very different approach to the matter could help. Any help or advice will be appreciated.
The reason of the error you found is already explained by Mel in the other answer. To fix it requires some data sorting and densification technique which I will explain in the form of comments within the provided code below.
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import geopandas as gpd
from shapely import wkt
#from cartopy import crs as ccrs
def xy_to_linecode(x1, y1):
"""
This creates a WKT linestring code
"""
line_code = "LINESTRING("
for ix, (x,y) in enumerate(zip(x1,y1)):
line_code += str(x) + " " + str(y)
if ix<len(x1)-1:
line_code += ", "
if ix==len(x1)-1:
line_code += ")"
return line_code
def xy_to_pntlist(x2, y2):
"""
This creates a list of WKT point codes
"""
pnt_head = "POINT("
all_pnts = []
for ix, (x,y) in enumerate(zip(x2,y2)):
pnt_code = pnt_head + str(x) + " " + str(y) + ")"
all_pnts.append(pnt_code)
return all_pnts
# Part 1 (make-up data and create geoDataFrames)
# ------
# create data for a line-string
# x1 must be sorted small to large
x1 = [15, 17, 19]
y1 = [52, 51, 54]
d1 = {'col1': [1,],
'wkt': [
xy_to_linecode(x1, y1)
#'LINESTRING (15 52, 17 51, 19 54)',
]
}
# this will be 1 row dataframe
d1f = pd.DataFrame( data=d1 )
# make a geodataframe from d1f (1 LineString)
# `shapely.wkt.loads` converts WKT code to geometry
d1f['geom'] = d1f['wkt'].apply(wkt.loads)
d1f_geo = gpd.GeoDataFrame(d1f, geometry=d1f['geom'])
# create dataframe for points
# x2 must be sorted small to large
x2 = [15.2, 16.0, 16.8, 17.2, 18.0]
y2 = [52, 51, 52, 53, 51]
ids = [101, 102, 103, 104, 105]
d2 = {'id': ids,
'wkt': xy_to_pntlist(x2, y2)
#[ 'POINT (15.2 52)',
# 'POINT (16.0 51)',
# 'POINT (16.8 52)',
# 'POINT (17.2 53)',
# 'POINT (18.0 51)']
}
d2f = pd.DataFrame( data=d2 )
# make a geodataframe from d2f (several Points)
# `shapely.wkt.loads` converts WKT code to geometry
d2f['geom'] = d2f['wkt'].apply(wkt.loads)
d2f_geo = gpd.GeoDataFrame(d2f, geometry=d2f['geom'])
# Since (x1, y1) and (x2, y2) are intentionally avoided to use
# assuming working with geodataframes from this steps on ...
# we must get (x1, y1) and (x2, y2) from the dataframes
# Part 2 (make use of the geoDataFrames)
# ------
# This will get (x1, y1) from d1f_geo, equivalent with (x1, y1) of the original data
xss = []
yss = []
for ea in d1f_geo.geometry.values:
# expect d1f_geo to have 'LineString' only
xs, ys = [], []
if ea.geom_type == 'LineString':
xs.append(ea.xy[0])
ys.append(ea.xy[1])
#print(xs)
#print(ys)
xss.append(xs[0])
yss.append(ys[0])
# intentionally avoid using original (x1, y1)
x1 = xss[0]
y1 = yss[0]
# this will get (x2, y2) from d2f_geo, equivalent with (x2, y2) from the original data
x2s, y2s = [], []
for ea in d2f_geo.geometry.values:
# expect d2f_geo to cobtain 'POINT' only
x2s.append(ea.x)
y2s.append(ea.y)
#print(ea.x, ea.y)
# intentionally avoid using original (x2, y2)
x2 = x2s
y2 = y2s
# Part 3 (visualization)
# ------
# if Cartopy is used to plot the data, ...
# crs1 = ccrs.PlateCarree()
# fig, ax = plt.subplots(subplot_kw={'projection': crs1})
# fig, ax = plt.subplots(1, 1, figsize=(8, 5), subplot_kw={'projection': crs1})
# note: axes' labels will not be plotted in this case
fig, ax = plt.subplots(1, 1, figsize=(8, 5))
# plot the single line in `d1f_geo`
kwargs={'linewidth': 1.5, 'linestyles': '--', 'alpha': 0.6}
d1f_geo.plot(color='black', ax=ax, **kwargs)
# xfill will contain all positions in x1 and x2
# that is, x1 or x2 is subset of xfill
xfill = np.sort(np.concatenate([x1, x2]))
# densify y1, y2 data to get equal shape data
y1fill = np.interp(xfill, x1, y1) # for the lineString's vertices
y2fill = np.interp(xfill, x2, y2) # for the series of points
# at this state, shapes of the arrays are equal,
# xfill.shape: (8,)
# y1fill.shape: (8,)
# y2fill.shape: (8,)
# the densified `line` data (xfill, y1fill) now have 8 vertices
# the densified `points` data (xfill, y2fill) also have 8 points
# filled color is painted here to visualize how the points/vertices are created
# if you dont need it, change True to False
if True:
ax.fill_between(xfill, y1fill, y2fill, where=y1fill < y2fill, interpolate=True, color='dodgerblue', alpha=0.1)
ax.fill_between(xfill, y1fill, y2fill, where=y1fill > y2fill, interpolate=True, color='crimson', alpha=0.1)
# plot numbers at linestring's vertices
# if you dont need this, change True to False
if True:
id = 0
for x,y in zip(xfill, y1fill):
id += 1
ax.text(x,y,str(id), color='blue')
# point is under or above the line ?
# this only works if `y2fill` and `y1fill` have equal shape
under_curve = None
if y2fill.shape == y1fill.shape:
under_curve = y2fill < y1fill
# prep list of colors, red (above line), green (below line)
colors = np.array(['green' if b else 'red' for b in under_curve])
# select only original points from (xfill, y2fill) to plot as green and red dots
# the extra (densified) points are plotted in gray
# label: "original" or "densified" are plotted at the points
for x,y,tof,cl in zip(xfill, y2fill, under_curve, colors):
tf1 = x in x2 and y in y2
if tf1:
ax.scatter(x, y, c=cl) # red or green
ax.text(x, y, "original", color=cl, alpha=0.65)
else:
# the (additional/densified) interpolated point created by `np.interp()`
# plot them in gray color
ax.scatter(x, y, c='lightgray', edgecolor='gray', linewidth=0.2)
ax.text(x, y, "densified", color='gray', alpha=0.75)
plt.show()
The output plot:
The problem is caused because the dataframes do not have the same index values. In this link it explains how to deal when "Comparison operators raise ValueError when .index are different." To do a comparison operation while ignoring the .index you can try the following:
under_curve = addressgpd['geom'].values < roadgpd['geom'].values

pvlib IV curve - TypeError: must be str, not int

I'm trying to make an IV curve from pvlib but am getting the error:
TypeError: must be str, not int.
Running on Spyder.
Could you advise please? This example taken from the web.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
rom pvlib.pvsystem import singlediode, v_from_i, i_from_v, retrieve_sam
def fivepoints_to_frame(pnt):
"""
Converts a 1 dimensional, dict-like singlediode or sapm result
to a 5 row DataFrame with columns current and voltage.
Users can iterate over the rows of a multidimensional
singlediode or sapm result, if necessary.
"""
ivframe = {'i_sc': (pnt['i_sc'], 0),
'p_mp': (pnt['i_mp'], pnt['v_mp']),
'i_x': (pnt['i_x'], 0.5*pnt['v_oc']),
'i_xx': (pnt['i_xx'], 0.5*(pnt['v_oc']+pnt['v_mp'])),
'v_oc': (0, pnt['v_oc'])}
ivframe = pd.DataFrame(ivframe, index=['current', 'voltage']).T
ivframe = ivframe.sort_values(by='voltage')
return ivframe
resistance_shunt = 16
resistance_series = 0.094
nNsVth = 0.473
saturation_current = 1.943e-09
photocurrent = 7
module_parameters = retrieve_sam('cecmod')['Example_Module']
v_oc = v_from_i(resistance_shunt, resistance_series, nNsVth, 0,
saturation_current, photocurrent)
voltage = np.linspace(0, v_oc, 100)
current = i_from_v(resistance_shunt, resistance_series, nNsVth,
voltage,saturation_current, photocurrent)
fivepnts = singlediode(
module_parameters, photocurrent, saturation_current, resistance_series,
resistance_shunt, nNsVth)
ivframe = fivepoints_to_frame(fivepnts)
fig, ax = plt.subplots()
ax.plot(voltage, current)
ax.scatter(ivframe['voltage'], ivframe['current'], c='k', s=36, zorder=10)
ax.set_xlim(0, None)
ax.set_ylim(0, None)
ax.set_ylabel('current (A)')
ax.set_xlabel('voltage (V)')
From the (Docs)
pvlib.pvsystem.singlediode(photocurrent, saturation_current, resistance_series,
resistance_shunt, nNsVth, ivcurve_pnts=None)
The first parameter to singlediode() is incorrect. If I remove it like:
fivepnts = singlediode(
photocurrent, saturation_current, resistance_series,
resistance_shunt, nNsVth)
I get:

How to draw line between point using python

How to draw line between 2 or 3 point.
I have 2 text file, first text file is list of posisition for each point.
point long lat
A 115 12
B 89 13
C 100 13
etc.
and the second file is like this:
3, 4
A, B, C
R, X, Y
V, P, O
J, M, N
2, 3
Q, S
H, K
T, W
4, 1
E, D, F, G
And I want draw the lines like this pic:
Actually, I'm not sure with my code. This is my code::
import psycopg2
import psycopg2.extensions
import matplotlib.pyplot as plt
import itertools
import collections
import numpy as np
def readRules(_dir):
#_dir = r'D:\s2\semester 3\tesis\phyton\hasil\Hasil_20160116_09.12.11'
mydict = {}
with open(os.path.join(_dir, 'rule3.csv'), 'rb') as testfile:
for line in testfile:
# first line is the next record "matrix size"
columns, rows = (int(x) for x in strip_comment(line).split(','))
# next line is the header for this record
key = tuple(strip_comment(next(testfile)).split(','))
# the next lines are the rows for this record
vals = [tuple(int(x) for x in strip_comment(next(testfile)).split(','))
for _ in range(rows)]
mydict[key] = vals
#print(mydict)
return mydict
data=getDataReference(cur) # to get location for each point
myPoints={}
myLines=[]
mydict=readRules(_dir)
# print "value :", mydict.values()
# print "key:", mydict.keys()
for value in mydict.values():
for x in value:
for s in range(len(x)):
myPoints[x[s]]= data[x[s]][0]
#print x[s]
if len(x)>1:
myLines.append(x)
myPoints_reversed = collections.defaultdict(list)
for number, string in myPoints.items():
myPoints_reversed[string].append(number)
colors = plt.cm.Spectral(np.linspace(0, 1, len(myPoints_reversed)))
myplt={}
for k, col in zip(myPoints_reversed.keys(),colors):
Long=[]
Lat=[]
for x in myPoints_reversed[k]:
Long.append(data[x][2])
Lat.append(data[x][1])
myplt[k] =plt.plot( Lat,Long , 'o', markerfacecolor=col, markeredgecolor='k', markersize=10, label=k)
#plt.legend(myplt,myPoints_reversed.keys(),loc=3,ncol=2, mode="expand", borderaxespad=0.)
plt.legend(loc =3,ncol=2, borderaxespad=0.)
#print myLines
#plt.plot(getListLat(myPoints.keys(),data), getListLong(myPoints.keys(),data),'o')
for point in myPoints:
#plt.annotate(getName(point,data), xy=getLatLong(point,data)) #Print name of point
plt.annotate(point, xy=getLatLong(point,data))
for line in myLines:
plotLine(line[0],line[1],data)
plt.show()

Categories