import sqlite3
import matplotlib.animation as animation
import matplotlib.pyplot as plt
def animate(i):
con = sqlite3.connect('newbase1.db')
c = con.cursor()
c.execute('SELECT Cell_1_V,Cell_2_V,Cell_1_T, time_stamp FROM Measurements')
data = c.fetchall()
Cell_1_V = []
Cell_2_V = []
Cell_1_T = []
tim = []
for row in data:
Cell_1_V.append(row[0])
Cell_2_V.append(row[1])
Cell_1_T.append(row[2])
tim.append(row[3])
fig , (sb1,sb2) = plt.subplots(nrows=2,ncols= 1)
sb1.set_xlabel("TIME---->")
sb1.set_ylabel("VOLTAGE--->")
sb2.set_xlabel("TIME---->")
sb2.set_ylabel("TEMP--->")
sb1.plot(tim,Cell_1_V,label='Cell_1_V')
sb2.plot(tim, Cell_1_T, label='Cell_1_T')
sb1.legend(loc='upper right')
sb2.legend(loc='upper right')
ani = animation.FuncAnimation(plt.gcf(), animate, interval=500)
plt.tight_layout()
plt.show()
The above is the code where I am trying to animate both subplots in the same figure but all i get is an empty plot. Any help would be appreciated.
Thanks in advance.
The basics of animation are initialization and updating data within the animation function. This is the same for a single graph and a subplot. The data has been created appropriately; the x-axis is graphed as a date.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import matplotlib.dates as mdates
from matplotlib.dates import DateFormatter
time_rng = pd.date_range('2021-01-01', freq='1d', periods=100)
vol1 = np.random.randn(100)*10
vol2 = np.random.randn(100)*10
temp1 = np.random.randn(100)+30
data = pd.DataFrame({'VOLTAGE1':vol1, 'VOLTAGE2':vol2, 'TEMP':temp1,'TIME':pd.to_datetime(time_rng)})
Cell_1_V, Cell_2_V, Cell_1_T, tim = [], [], [], []
for idx,row in data.iterrows():
Cell_1_V.append(row[0])
Cell_2_V.append(row[1])
Cell_1_T.append(row[2])
tim.append(row[3])
fig , (sb1,sb2) = plt.subplots(nrows=2,ncols= 1)
sb1.set(xlim=(mdates.date2num(tim[0]),mdates.date2num(tim[-1])), ylim=(data.VOLTAGE1.min(), data.VOLTAGE1.max()))
sb2.set(xlim=(mdates.date2num(tim[0]),mdates.date2num(tim[-1])), ylim=(data.TEMP.min(), data.TEMP.max()))
fig.subplots_adjust(hspace=0.4)
sb1.set_xlabel("TIME---->")
sb1.set_ylabel("VOLTAGE--->")
sb2.set_xlabel("TIME---->")
sb2.set_ylabel("TEMP--->")
line1, = sb1.plot([], [], label='Cell_1_V', color='C0')
line2, = sb2.plot([], [], label='Cell_1_T', color='C1')
sb1.legend(loc='upper right')
sb2.legend(loc='upper right')
date_fmt = DateFormatter("%Y-%m-%d")
sb1.xaxis.set_major_formatter(date_fmt)
sb2.xaxis.set_major_formatter(date_fmt)
line = [line1, line2]
def animate(i):
line[0].set_data(mdates.date2num(tim[:i]), Cell_1_V[:i])
line[1].set_data(mdates.date2num(tim[:i]), Cell_1_T[:i])
return line
ani = FuncAnimation(fig, animate, frames=len(data), interval=200, repeat=False)
# plt.tight_layout()
plt.show()
Related
I am trying to make a virtual flight tracker with Python and API data, and I have managed so far to draw the points, update their location every 10 seconds and annotate them. Unfortunately, they are being annotated for each position they are drawn in when in fact I want them to only be shown in the spot where the point is at that time, or else there is a constant trail of labels.
The code is below:
import requests
import json
import time
import cartopy.crs as ccrs
import cartopy
import matplotlib.pyplot as plt
from cartopy.io.img_tiles import GoogleTiles
from matplotlib import animation
#SET AXES
fig, ax = plt.subplots()
ax=plt.axes(projection=ccrs.PlateCarree())
'''
ax.set_ylim(48,61.5)
ax.set_xlim(-12.5, 3.3)
'''
#ADD OSM BASEMAP
osm_tiles=GoogleTiles(style='satellite')
ax.add_image(osm_tiles,8)
ax.stock_img()
ax.set_extent([-12.5, 3.3, 48, 61.55])
ax.add_feature(cartopy.feature.BORDERS)
#mplcursors.cursor(hover=True)
#PLOT TRACK
track, = ax.plot([], [], 'wo')
# RELOAD API EVERY 15"
def update (self):
vapi = requests.get("https://data.vatsim.net/v3/vatsim-data.json")
# LOAD DATA AS JSON
data = vapi.text
parse_json = json.loads(data)
# LOAD PILOTS
pilots = parse_json['pilots']
no_pilots = len(pilots)
# GET INFO FOR EACH AIRCRAFT
x = 0
callsigns, lat, lon, alt, head, gspeed = [], [], [], [], [], []
while x < no_pilots:
xcall = pilots[x]['callsign']
xlat = pilots[x]['latitude']
xlon = pilots[x]['longitude']
xgspeed = pilots[x]['groundspeed']
xalt = pilots[x]['altitude']
xhead = pilots[x]['heading']
callsigns.append(xcall)
lat.append(xlat)
lon.append(xlon)
alt.append(xalt)
head.append(xhead)
gspeed.append(xgspeed)
x += 1
for i, txt in enumerate(callsigns):
ax.annotate(txt, (lon[i], lat[i]))
track.set_data(lon,lat)
return track, callsigns,
anim = animation.FuncAnimation(fig, update,interval=10000, blit=False)
plt.show()
It leaves a trail of annotations like this
I am trying to remove capital N and E symbols in Cartopy gridline tick-labels. Just I want to keep the numeric value with degree symbol(°), e.g., 10°,15°,20°... instead of, 10°N,15°N,20°N..., as shown in below example map.
Data.plot.pcolormesh(ax=ax ,cmap=plt.cm.get_cmap('seismic'),
add_colorbar=False,add_labels=False,
transform=ccrs.PlateCarree())
ax.add_feature(cartopy.feature.COASTLINE)
ax.add_feature(cartopy.feature.BORDERS, linestyle='-')
ax.add_feature(cartopy.feature.LAND, zorder=100, edgecolor='k')
gl = ax.gridlines(draw_labels=True, linestyle='--')
gl.yformatter=LATITUDE_FORMATTER
gl.ylabels_right=False
gl.ylabels_left=False
gl.xlabels_bottom=True
gl.xlabels_top=False
gl.ylabel_style={'size':10,'weight':'bold'}
Any guess to hack this!!
Thanks
You should be able to do this by passing appropriate parameters to the gridline method and using the appropriate formatters, like this:
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
import cartopy
from cartopy.mpl.ticker import LongitudeFormatter, LatitudeFormatter
plt.figure(figsize=[10, 8.5])
proj = ccrs.PlateCarree()
ax = plt.axes(projection=proj)
ax.add_feature(cartopy.feature.COASTLINE)
ax.add_feature(cartopy.feature.BORDERS, linestyle="-")
ax.add_feature(cartopy.feature.LAND, zorder=100, edgecolor="k")
cardinal_labels = {"east": "", "west": "", "north": "", "south": ""}
latitude_formatter = LatitudeFormatter(cardinal_labels=cardinal_labels)
longitude_formatter = LongitudeFormatter(cardinal_labels=cardinal_labels)
gl = ax.gridlines(
draw_labels=["left", "bottom"],
linestyle="--",
xformatter=longitude_formatter,
yformatter=latitude_formatter,
ylabel_style={"size": 10, "weight": "bold"},
)
plt.show()
Gridliner object generated by ax.gridlines(...) provides all you need to access/manipulate the label texts.
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import matplotlib.pyplot as plt
import cartopy
from cartopy.mpl.gridliner import LONGITUDE_FORMATTER, LATITUDE_FORMATTER
plt.figure(figsize=[10, 8.5])
proj = ccrs.PlateCarree()
ax = plt.axes(projection=proj)
ax.add_feature(cartopy.feature.COASTLINE)
ax.add_feature(cartopy.feature.BORDERS, linestyle='-')
ax.add_feature(cartopy.feature.LAND, zorder=100, edgecolor='k')
gl = ax.gridlines(draw_labels=True, linestyle='--')
gl.yformatter=LATITUDE_FORMATTER
# Use the more recent methods
#gl.ylabels_right=False
gl.right_labels =False
#gl.ylabels_left=False
gl.left_labels =True
#gl.xlabels_bottom=True
gl.bottom_labels =True
#gl.xlabels_top=False
gl.top_labels =False
gl.ylabel_style={'size':10,'weight':'bold'}
# Generate/draw the plot so that `gl`'s properties are created
# and the subsequent lines of code are possible
plt.draw()
# Manipulate 'gl' by accessing all the texts
# and chnage their contents as required
for ea in gl._labels:
oldtxt = ea[2].get_text()
#print("Original:", ea[2].get_text())
newtxt = oldtxt.replace("W","")
newtxt = newtxt.replace("N","")
newtxt = newtxt.replace("E","")
newtxt = newtxt.replace("S","")
#print("New", newtxt)
ea[2].set_text(newtxt)
plt.show()
Hello i'm making an application that allows you to effectively create a youtube poll by counting certain responses and then displaying the results realtime in a graph. My current problem is that my code won't start to loop through youtube chat until i've closed the graph, and if i have the graph appear after the loop then there is no information for the graph to update in real-time as the loop will have stopped. how do i get the graph to appear and then for the loop to go through youtube chat, or is there a more elegant way of achieving the same objective?
def animate(i):
x.append(next(index))
y1.append(numprompt1)
y2.append(numprompt2)
plt.cla()
plt.plot(x, numprompt1, label ='prompt 1')
plt.plot(x, numprompt2, label ='prompt 2')
plt.legend(loc='upper left')
FuncAnimation(plt.gcf(), animate, interval=1000)
#livechat code
while livechat.is_alive():
try:
chatdata = livechat.get()
for c in chatdata.items:
print(f"{c.datetime} [{c.author.name}]- {c.message}")
message = str({c.message})
if prompt1 in message:
numprompt1 += 1
print (prompt1, "has been said", numprompt1, "times")
elif prompt2 in message:
numprompt2 += 1
print (prompt2, "has been said", numprompt2, "times")
chatdata.tick()
except KeyboardInterrupt:
livechat.terminate()
break
You can try this example:
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.animation as animation
y1 = []
y2 = []
numprompt1 = 0
numprompt2 = 0
fig=plt.figure()
ax = fig.add_subplot(1,1,1)
def animate(i):
global y1
global y2
global numprompt1
global numprompt2
a = ax.clear()
numprompt1 += 1.1
numprompt2 += 1.2
y1.append(numprompt1)
y2.append(numprompt2)
x = np.arange(len(y1))
a = ax.plot(x, y1, color = 'green', label = 'prompt 1')
a = ax.plot(x, y2, color = 'red', label = 'prompt 2')
a = ax.legend()
ani = animation.FuncAnimation(fig, animate, interval=1000)
a = plt.show()
Matplotlib axes have Major and Minor ticks. How do I add a third level of tick below Minor?
For example
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.ticker
t = np.arange(0.0, 100.0, 0.1)
s = np.sin(0.1*np.pi*t)*np.exp(-t*0.01)
fig, ax = plt.subplots()
plt.plot(t, s)
ax1 = ax.twiny()
ax1.plot(t, s)
ax1.xaxis.set_ticks_position('bottom')
majors = np.linspace(0, 100, 6)
minors = np.linspace(0, 100, 11)
thirds = np.linspace(0, 100, 101)
ax.xaxis.set_major_locator(matplotlib.ticker.FixedLocator(majors))
ax.xaxis.set_minor_locator(matplotlib.ticker.FixedLocator(minors))
ax1.xaxis.set_major_locator(matplotlib.ticker.FixedLocator([]))
ax1.xaxis.set_minor_locator(matplotlib.ticker.FixedLocator(thirds))
ax1.tick_params(which='minor', length=2)
ax.tick_params(which='minor', length=4)
ax.tick_params(which='major', length=6)
ax.grid(which='both',axis='x',linestyle='--')
plt.axhline(color='gray')
plt.show()
produces the effect I want using twinned x-axes.
Is there a better way?
As I stated that you can achieve what you want by deriving from some key classes, I decided to do so (but as I said, it's probably not worth the effort). Anyway, here is what I've got:
from matplotlib import pyplot as plt
from matplotlib import axes as maxes
from matplotlib import axis as maxis
import matplotlib.ticker as mticker
import matplotlib.cbook as cbook
from matplotlib.projections import register_projection
from matplotlib import ticker
import numpy as np
class SubMinorXAxis(maxis.XAxis):
def __init__(self,*args,**kwargs):
self.subminor = maxis.Ticker()
self.subminorTicks = []
self._subminor_tick_kw = dict()
super(SubMinorXAxis,self).__init__(*args,**kwargs)
def reset_ticks(self):
cbook.popall(self.subminorTicks)
##self.subminorTicks.extend([self._get_tick(major=False)])
self.subminorTicks.extend([maxis.XTick(self.axes, 0, '', major=False, **self._subminor_tick_kw)])
self._lastNumSubminorTicks = 1
super(SubMinorXAxis,self).reset_ticks()
def set_subminor_locator(self, locator):
"""
Set the locator of the subminor ticker
ACCEPTS: a :class:`~matplotlib.ticker.Locator` instance
"""
self.isDefault_minloc = False
self.subminor.locator = locator
locator.set_axis(self)
self.stale = True
def set_subminor_formatter(self, formatter):
"""
Set the formatter of the subminor ticker
ACCEPTS: A :class:`~matplotlib.ticker.Formatter` instance
"""
self.isDefault_minfmt = False
self.subminor.formatter = formatter
formatter.set_axis(self)
self.stale = True
def get_subminor_ticks(self, numticks=None):
'get the subminor tick instances; grow as necessary'
if numticks is None:
numticks = len(self.get_subminor_locator()())
if len(self.subminorTicks) < numticks:
# update the new tick label properties from the old
for i in range(numticks - len(self.subminorTicks)):
##tick = self._get_tick(major=False)
tick = maxis.XTick(self.axes, 0, '', major=False, **self._subminor_tick_kw)
self.subminorTicks.append(tick)
if self._lastNumSubminorTicks < numticks:
protoTick = self.subminorTicks[0]
for i in range(self._lastNumSubminorTicks, len(self.subminorTicks)):
tick = self.subminorTicks[i]
tick.gridOn = False
self._copy_tick_props(protoTick, tick)
self._lastNumSubminorTicks = numticks
ticks = self.subminorTicks[:numticks]
return ticks
def set_tick_params(self, which='major', reset=False, **kwargs):
if which == 'subminor':
kwtrans = self._translate_tick_kw(kwargs, to_init_kw=True)
if reset:
self.reset_ticks()
self._subminor_tick_kw.clear()
self._subminor_tick_kw.update(kwtrans)
for tick in self.subminorTicks:
tick._apply_params(**self._subminor_tick_kw)
else:
super(SubMinorXAxis, self).set_tick_params(which=which, reset=reset, **kwargs)
def cla(self):
'clear the current axis'
self.set_subminor_locator(mticker.NullLocator())
self.set_subminor_formatter(mticker.NullFormatter())
super(SubMinorXAxis,self).cla()
def iter_ticks(self):
"""
Iterate through all of the major and minor ticks.
...and through the subminors
"""
majorLocs = self.major.locator()
majorTicks = self.get_major_ticks(len(majorLocs))
self.major.formatter.set_locs(majorLocs)
majorLabels = [self.major.formatter(val, i)
for i, val in enumerate(majorLocs)]
minorLocs = self.minor.locator()
minorTicks = self.get_minor_ticks(len(minorLocs))
self.minor.formatter.set_locs(minorLocs)
minorLabels = [self.minor.formatter(val, i)
for i, val in enumerate(minorLocs)]
subminorLocs = self.subminor.locator()
subminorTicks = self.get_subminor_ticks(len(subminorLocs))
self.subminor.formatter.set_locs(subminorLocs)
subminorLabels = [self.subminor.formatter(val, i)
for i, val in enumerate(subminorLocs)]
major_minor = [
(majorTicks, majorLocs, majorLabels),
(minorTicks, minorLocs, minorLabels),
(subminorTicks, subminorLocs, subminorLabels),
]
for group in major_minor:
for tick in zip(*group):
yield tick
class SubMinorAxes(maxes.Axes):
name = 'subminor'
def _init_axis(self):
self.xaxis = SubMinorXAxis(self)
self.spines['top'].register_axis(self.xaxis)
self.spines['bottom'].register_axis(self.xaxis)
self.yaxis = maxis.YAxis(self)
self.spines['left'].register_axis(self.yaxis)
self.spines['right'].register_axis(self.yaxis)
register_projection(SubMinorAxes)
if __name__ == '__main__':
fig = plt.figure()
ax = fig.add_subplot(111,projection = 'subminor')
t = np.arange(0.0, 100.0, 0.1)
s = np.sin(0.1*np.pi*t)*np.exp(-t*0.01)
majors = np.linspace(0, 100, 6)
minors = np.linspace(0, 100, 11)
thirds = np.linspace(0, 100, 101)
ax.plot(t, s)
ax.xaxis.set_ticks_position('bottom')
ax.xaxis.set_major_locator(ticker.FixedLocator(majors))
ax.xaxis.set_minor_locator(ticker.FixedLocator(minors))
ax.xaxis.set_subminor_locator(ticker.FixedLocator(thirds))
##some things in set_tick_params are not being set correctly
##by default. For instance 'top=False' must be stated
##explicitly
ax.tick_params(which='subminor', length=2, top=False)
ax.tick_params(which='minor', length=4)
ax.tick_params(which='major', length=6)
ax.grid(which='both',axis='x',linestyle='--')
plt.show()
It's not perfect, but for the use case you provided it's working fine. I drew some ideas from this matplotlib example and by going through the source codes directly. The result looks like this:
I tested the code on both Python 2.7 and Python 3.5.
EDIT:
I noticed that the subminor gridlines would always be drawn if the grid is turned on (while I had intended for it not to be drawn at all). I rectified this in the code above, i.e. the subminor ticks should never produce grid lines. If gridlines should be implemented properly, some more work will be needed.
I have multiple functions in which I input an array or dict as well as a path as an argument, and the function will save a figure to the path of a particular path.
Trying to keep example as minimal as possible, but here are two functions:
def valueChartPatterns(dict,path):
seen_values = Counter()
for data in dict.itervalues():
seen_values += Counter(data.values())
seen_values = seen_values.most_common()
seen_values_pct = map(itemgetter(1), tupleCounts2Percents(seen_values))
seen_values_pct = ['{:.2%}'.format(item)for item in seen_values_pct]
plt.figure()
numberchart = plt.bar(range(len(seen_values)), map(itemgetter(1), seen_values), width=0.9,align='center')
plt.xticks(range(len(seen_values)), map(itemgetter(0), seen_values))
plt.title('Values in Pattern Dataset')
plt.xlabel('Values in Data')
plt.ylabel('Occurrences')
plt.tick_params(axis='both', which='major', labelsize=6)
plt.tick_params(axis='both', which='minor', labelsize=6)
plt.tight_layout()
plt.savefig(path)
plt.clf()
def countryChartPatterns(dict,path):
seen_countries = Counter()
for data in dict.itervalues():
seen_countries += Counter(data.keys())
seen_countries = seen_countries.most_common()
seen_countries_percentage = map(itemgetter(1), tupleCounts2Percents(seen_countries))
seen_countries_percentage = ['{:.2%}'.format(item)for item in seen_countries_percentage]
yvals = map(itemgetter(1), seen_countries)
xvals = map(itemgetter(0), seen_countries)
plt.figure()
countrychart = plt.bar(range(len(seen_countries)), yvals, width=0.9,align='center')
plt.xticks(range(len(seen_countries)), xvals)
plt.title('Countries in Pattern Dataset')
plt.xlabel('Countries in Data')
plt.ylabel('Occurrences')
plt.tick_params(axis='both', which='major', labelsize=6)
plt.tick_params(axis='both', which='minor', labelsize=6)
plt.tight_layout()
plt.savefig(path)
plt.clf()
A very minimal example dict is, but the actual dict contains 56000 values:
dict = {"a": {"Germany": 20006.0, "United Kingdom": 20016.571428571428}, "b": {"Chad": 13000.0, "South Africa": 3000000.0},"c":{"Chad": 200061.0, "South Africa": 3000000.0}
}
And in my script, I call:
if __name__ == "__main__":
plt.close('all')
print "Starting pattern charting...\n"
countryChartPatterns(dict,'newPatternCountries.png'))
valueChartPatterns(dict,'newPatternValues.png'))
Note, I load import matplotlib.pyplot as plt.
When running this script in PyCharm, I get Starting pattern charting... in my console but the functions take super long to plot.
What am I doing wrong? Should I be using a histogram instead of a bar plot as this should achieve the same aim of giving the number of occurrences of countries/values? Can I change my GUI backend somehow? Any advice welcome.
This is the test that I mentioned in the comments above, resulting in:
Elapsed pre-processing = 13.79 s
Elapsed plotting = 0.17 s
Pre-processing / plotting = 83.3654562565
Test script:
import matplotlib.pylab as plt
from collections import Counter
from operator import itemgetter
import time
def countryChartPatterns(dict,path):
# pre-processing -------------------
t0 = time.time()
seen_countries = Counter()
for data in dict.itervalues():
seen_countries += Counter(data.keys())
seen_countries = seen_countries.most_common()
yvals = map(itemgetter(1), seen_countries)
xvals = map(itemgetter(0), seen_countries)
dt1 = time.time() - t0
print("Elapsed pre-processing = {0:.2f} s".format(dt1))
t0 = time.time()
# plotting -------------------
plt.figure()
countrychart = plt.bar(range(len(seen_countries)), yvals, width=0.9,align='center')
plt.xticks(range(len(seen_countries)), xvals)
plt.title('Countries in Pattern Dataset')
plt.xlabel('Countries in Data')
plt.ylabel('Occurrences')
plt.tick_params(axis='both', which='major', labelsize=6)
plt.tick_params(axis='both', which='minor', labelsize=6)
plt.tight_layout()
plt.savefig(path)
plt.clf()
dt2 = time.time() - t0
print("Elapsed plotting = {0:.2f} s".format(dt2))
print("Pre-processing / plotting = {}".format(dt1/dt2))
if __name__ == "__main__":
import random as rd
import numpy as np
countries = ["United States of America", "Afghanistan", "Albania", "Algeria", "Andorra", "Angola", "Antigua & Deps", "Argentina", "Armenia", "Australia", "Austria", "Azerbaijan"]
def item():
return {rd.choice(countries): np.random.randint(1e3), rd.choice(countries): np.random.randint(1e3)}
dict = {}
for i in range(1000000):
dict[i] = item()
print("Starting pattern charting...")
countryChartPatterns(dict,'newPatternCountries.png')