How to create a circular frequency histogram - python

Dear members of stackoverflow,
I want to create a circular frequency histogram (rose diagram) using the the frequencies for each bin listed as a single column in a text file. How could I do this using matplotlib.pyplot and numpy in python3?
I did an initial attempt with a code I found on the internet, but when I get the rose diagram the bins are overlapped when they should be beside each other. Other detail: the radius of the circle for each bin should be the frequency, but this also changes and does not match my frequencies.
I want my bins to go from 0 to 360 degrees with width of 10 degrees; example: 0-10, 10-20 etc.
This is a sample of the txt file with the frequencies(frequencies.txt):
0
0
0
0
0
2
0
1
1
0
1
0
0
1
2
29
108
262
290
184
81
25
7
2
3
1
1
0
0
0
0
0
0
0
0
0

You could create a polar bar plot. The angles need to be converted from degrees to radians.
frequencies = np.loadtxt('filename.txt') would read the values from file (docs).
import numpy as np
import matplotlib.pyplot as plt
frequencies = [0, 0, 0, 0, 0, 2, 0, 1, 1, 0, 1, 0, 0, 1, 2, 29, 108, 262, 290,
184, 81, 25, 7, 2, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
fig = plt.figure()
ax = plt.axes(polar=True)
theta = np.radians(np.arange(0, 360, 10))
width = np.radians(10)
ax.bar(theta, frequencies, width=width,
facecolor='lightblue', edgecolor='red', alpha=0.5, align='edge')
ax.set_xticks(theta)
plt.show()

Related

How to convert the following trigonometric function into a python function for boundary curvature calculation?

I am trying to understand a few slides from this source
Specifically, this example at slide 59:
The part I do not understand is how to go from the chain-code to the curvature.
I believe the formula is given in slide 56:
But if I try to implement this in python I get different results.
For example:
import matplotlib.pyplot as plt
# Dataset
x = [0, 1, 2, 2, 3, 4, 5, 6, 6, 7, 8]
y = [0, 0, 0, 1, 1, 2, 2, 1, 0, 0, 0]
# Show data
plt.scatter(x, y)
plt.plot(x, y)
plt.axis('equal')
plt.show()
import math
i = 4 # Taking the 5th point, at index 4, with supposed curvature of 1 from the slide
k = 1
a = math.atan((y[i+k]-y[i])/(x[i+k]-x[i]))
b = math.atan((y[i]-y[i-k])/(x[i]-x[i-k]))
result = (a - b) % (2 * math.pi) # = 0.7853981633974483
So clearly I a missing something, but what?
The "curvature" in the first image is the difference between two subsequent "chain-codes" modulo 8. So for example for chain codes 0 0 2 0 1 0 7 6 0 0 the 4th entry in curvature is 1-0 = 1 while the sixth is 7-0 = 7 = -1 (mod 8). In Python you can calculate it like this:
>>> def mod8(x):
... m = x % 8
... return m if m < 4 else m - 8
...
>>> cc = [0, 0, 2, 0, 1, 0, 7, 6, 0, 0]
>>> [mod8(a - b) for (a, b) in zip(cc[1:], cc[:-1])]
[0, 2, -2, 1, -1, -1, -1, 2, 0]
If you compare this with the formula that uses atan, what the formula is missing is the conversion of the angles from radians to the units where 1 is 45 degrees (pi/4). Your result 0.7853981633974483 is correct according to the formula, but if you expected to get 1.0 you would have to divide the result by math.pi/4.

Plotting (x,y) point to point connections with python

I am trying to plot a point to point line plot in python.
My data is in a pandas dataframe as below..
df = pd.DataFrame({
'x_coordinate': [0, 0, 0, 0, 1, 1,-1,-1,-2,0],
'y_coordinate': [0, 2, 1, 3, 3, 1,1,-2,2,-1],
})
print(df)
x_coordinate y_coordinate
0 0 0
1 0 2
2 0 1
3 0 3
4 1 3
5 1 1
6 -1 1
7 -1 -2
8 -2 2
9 0 -1
when I plot this, it is joining from point to point as in the order in the df.
df.plot('x_coordinate','y_coordinate')
But, is there a way, I can plot an order number next to it ? I mean the order it is travelling. Say 1 for the first connection from (0,0) to (0,2) and 2 from (0,2) to (0,1) and so on ?
The plot is OK. If you want to check how each vertex is plotted, you need modified data. Here is the modified data (x only) and the plot.
df = pd.DataFrame({
'x_coordinate': [0.1, 0.2, 0.3, 0.4, 1.5, 1.6,-1.7,-1.8,-2.9,0.1],
'y_coordinate': [0, 2, 1, 3, 3, 1,1,-2,2,-1],
})
Edit
For your new request, the code is modified as follows (full runnable code).
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
df = pd.DataFrame({
'x_coordinate': [0.1, 0.2, 0.3, 0.4, 1.5, 1.6,-1.7,-1.8,-2.9,0.1],
'y_coordinate': [0, 2, 1, 3, 3, 1,1,-2,2,-1],
})
fig = plt.figure(figsize=(6,5))
ax1 = fig.add_subplot(1, 1, 1)
df.plot('x_coordinate','y_coordinate', legend=False, ax=ax1)
for ea in zip(np.array((range(len(df)))), df.x_coordinate.values, df.y_coordinate.values):
text, x, y = "P"+str(ea[0]), ea[1], ea[2]
ax1.annotate(text, (x,y))
I found an easier way to do it.. Thought to share..
fig, ax = plt.subplots()
df.plot('x_coordinate','y_coordinate',ax=ax)
for k, v in df[['x_coordinate','y_coordinate']].iterrows():
ax.annotate('p'+str(k+1), v)
plt.show()

Pyplot contourf don't fill in "0" level

I'm plotting precipitation data from weather model output. I'm contouring the data I have, using contourf. However, I don't want it to fill in the "0" level with color (only the values >0). Is there a good way to do this? I've tried messing around with the levels.
Here's the code I'm using to plot:
m = Basemap(projection='stere', lon_0=centlon, lat_0=centlat,
lat_ts=centlat, width=width, height=height)
m.drawcoastlines()
m.drawstates()
m.drawcountries()
parallels = np.arange(0., 90, 10.)
m.drawparallels(parallels, labels=[1, 0, 0, 0], fontsize=10)
meridians = np.arange(180., 360, 10.)
m.drawmeridians(meridians, labels=[0, 0, 0, 1], fontsize=10)
lons, lats = m.makegrid(nx, ny)
x, y = m(lons, lats)
cs = m.contourf(x, y, snowfall)
cbar = plt.colorbar(cs)
cbar.ax.set_ylabel("Accumulated Snow (km/m^2)")
plt.show()
And here's the image I'm getting.
An example snowfall dataset would look something like:
0 0 0 0 0 0
0 0 1 1 1 0
0 1 2 2 1 0
0 2 3 2 1 0
0 1 0 1 2 0
0 0 0 0 0 0
This can also be achieved using 'locator' with MaxNLocator('prune = 'lower') from the ticker subclass. See docs.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
a = np.array([
[0, 0, 0, 0, 0, 0],
[0, 0, 1, 1, 1, 0],
[0, 1, 2, 2, 1, 0],
[0, 2, 3, 2, 1, 0],
[0, 1, 0, 1, 2, 0],
[0, 0, 0, 0, 0, 0]
])
fig, ax = plt.subplots(1)
p = ax.contourf(a, locator = ticker.MaxNLocator(prune = 'lower'))
fig.colorbar(p)
plt.show()
Image of output
The 'nbins' parameter can be used to control the number of intervals (levels)
p = ax.contourf(a, locator = ticker.MaxNLocator(prune = 'lower'), nbins = 5)
If you don't include 0 in your levels, you won't plot a contour at the 0 level.
For example:
import numpy as np
import matplotlib.pyplot as plt
a = np.array([
[0, 0, 0, 0, 0, 0],
[0, 0, 1, 1, 1, 0],
[0, 1, 2, 2, 1, 0],
[0, 2, 3, 2, 1, 0],
[0, 1, 0, 1, 2, 0],
[0, 0, 0, 0, 0, 0]
])
fig, ax = plt.subplots(1)
p = ax.contourf(a, levels=np.linspace(0.5, 3.0, 11))
fig.colorbar(p)
plt.show()
yields:
An alternative is to mask any datapoints which are 0:
p = ax.contourf(np.ma.masked_array(a, mask=(a==0)),
levels=np.linspace(0.0, 3.0, 13))
fig.colorbar(p)
Which looks like:
I suppose its up to you which of those matches your desired plot the most.
I was able to figure things out myself, there are two ways I found of solving this problem.
Mask out all data <0.01 from the data set using
np.ma.masked_less(snowfall, 0.01)
or
Set the levels of the plot to be from 0.01 -> whatever maximum value
levels = np.linspace(0.1, 10, 100)
then
cs = m.contourf(x, y, snowfall, levels)
I found that option 1 worked best for me.

Assigning unique colours to different value combinations Python

I have a pivot table array with factors and X and Y coordinates such as the one below, and I have a look up table with 64 colours that have RGB values. I am trying to assign a colour to each factor combination and I'm not too sure how to go about doing so. For example, I need all A(0) B(1) C(0) D(0) to be RGB value (1 0 103) so that I can then paint those colours onto an image at point XY.
A B C D Xpoint Ypoint
0 1 0 0 20 20
0 1 1 0 30 30
0 1 0 0 40 40
1 0 1 0 50 50
1 0 1 0 60 60
So far I only have code to open both my LUT and pivot table file and code to see the length of the pivot table.
import pandas as pd
from PIL import Image, ImageDraw
## load in LUT of 64 colours ##
with open('LUT64.csv') as d:
LUT64 = pd.read_table(d, sep=',')
print LUT64
## load in XY COordinates ##
with open('PivotTable_2017-07-13_001.txt') as e:
PivotTable = pd.read_table(e, sep='\t')
print PivotTable
## Bring in image ##
IM = Image.open("mothTest.tif")
IM.show()
#bring in number of factors
numFactors = 16
#assign colour vectors to each factor combo
numPTrows = len(PivotTable)
print numPTrows
#Apply colour dots to image at XY coordinates
Any help would be greatly appreciated!
You can use a dict for your colour values with the first four values of your table as key (cast into a tuple):
table = [
[0, 1, 0, 0, 20, 20],
[0, 1, 1, 0, 30, 30],
[0, 1, 0, 0, 40, 40],
[1, 0, 1, 0, 50, 50],
[1, 0, 1, 0, 60, 60],
]
##generating some colors
colors = [ (i,i,i) for i in range(0,256, 5)]
##defining iterator over color table
c_it = iter(colors)
##the dictionary for the color values
color_dict = dict()
##assigning one color for each unique (A,B,C,D) tuple:
for entry in table:
key = tuple(entry[0:4])
if key not in color_dict:
color_dict[key] = next(c_it)
print(color_dict)
The output of this is:
{
(1, 0, 1, 0): (10, 10, 10),
(0, 1, 1, 0): (5, 5, 5),
(0, 1, 0, 0): (0, 0, 0)
}
EDIT:
In correspondence the edit of the OP's question, here a rough sketch of how to manipulate your Pillow Image (untested):
##looping through table:
for entry in table:
key = tuple(entry[0:4])
coord = tuple(entry[4:6])
color = color_dict[key]
IM.putpixel(coord,color)

Matplotlib skips data -

I am trying to plot a bar chart using matplotlib. My issue is I have some "0" values in the list and matplotlib eats some of these values, how do I make sure it always plots all the values.
Here is the code:
counter_trim = counter[6:(len(counter)-6)]
pos = np.arange(len(Test_names[6:]))
width =.65
ax = plt.axes()
ax.set_ylabel('Number of failures')
ax.set_title('Distribution of ABT failures')
ax.set_xticks(pos + (width/2))
xtickNames= ax.set_xticklabels(Test_names[6:])
plt.setp(xtickNames, rotation=90, fontsize=10)
plt.bar(pos, counter_trim, width, color='b')
plt.tight_layout()
print 'Distribution plot can be found here:' +image_filepath
plt.savefig(image_filepath)
To make things more clear,
here are the values of pos : [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16]
and values of counter_trim: [0, 0, 0, 1, 17, 6, 0, 14, 32, 11, 0, 0, 2, 0, 1, 0, 0]
The code above skips first 3 and last 2 zeros, but rest everything is same!
Any ideas how to avoid this?
try out something like this:
plt.xlim(0, len(counter_trim))
as he is drawing no actual bar I guess the plot command omits these entries. I could not try it with your labels on x as they are not with the text but this worked with a standard axis.

Categories

Resources