简体   繁体   中英

Matplotlib Polar Plot with Lines

Trying to create a wind rose in Matplotlib using lines instead of bars. In other words, I would like something like this (which was created with Gnuplot) where the lines have a consistent thickness along the entire length and extend from the origin to the wind speed along the radial (the red is the most current observation, the indigo is peak, and the older obs get darker as they get older):

风玫瑰1

The closest I have been able to come is this (please ignore any differences except for the lines):

风玫瑰2

Everything that I've tried is plotted in a way that "fans out" from the origin--be it bars, lines, arrows, whatever. Here's the plot line:

bars = ax.bar(wind_direction, wind_speed, width=.075, linewidth=0.1, edgecolor='black', zorder=3)

SOLUTION:

解决方案

Here is the complete code to create the desired plot (right above this line) thanks to @cphlewis' fix. My mistake when trying to use plot was to plot all the data in one command, rather than 'n' number of plots (plot each line individually.)

#! /usr/bin/env python2.6
# -*- coding: utf-8 -*-

import csv
import numpy as np
import matplotlib.pyplot as plt

bar_colors     = ['#333333', '#444444', '#555555', '#666666', '#777777', '#888888', '#999999', 'red']
data_source    = '/Users/username/Dropbox/Public/charts.csv'
num_obs        = 8
final_data     = []
wind_direction = []
wind_speed     = []

# Get the data.
data_file = open(data_source, "r")
csv_data  = csv.reader(data_file, delimiter=',')
[final_data.append(item) for item in csv_data]
data_file.close()

# Grab the column headings for the labels, then delete the row from final_data.
xlabel = final_data[0][24]
ylabel = final_data[0][25]
final_data.pop(0)

# Create lists of data to plot (string -> float).
[wind_direction.append(float(item[24])) for item in final_data]
[wind_speed.append(float(item[25])) for item in final_data]

# Make them the desired length based on num_obs.
wind_direction = wind_direction[len(wind_direction)-num_obs:len(wind_direction)]
wind_speed     = wind_speed[len(wind_speed)-num_obs:len(wind_speed)]

# Polar plots are in radians (not degrees.)
wind_direction = np.radians(wind_direction)


wind = zip(wind_direction, wind_speed, bar_colors) # polar(theta,r)


# Customizations.
plt.figure(figsize=(3, 3))  # Size
ax = plt.subplot(111, polar=True)  # Create subplot
plt.grid(color='#888888')  # Color the grid
ax.set_theta_zero_location('N')  # Set zero to North
ax.set_theta_direction(-1)  # Reverse the rotation
ax.set_xticklabels(['N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW'], color='#666666', fontsize=8)  # Customize the xtick labels
ax.spines['polar'].set_visible(False)  # Show or hide the plot spine
ax.set_axis_bgcolor('#111111')  # Color the background of the plot area.

# Create the plot.
# Note: zorder of the plot must be >2.01 for the plot to be above the grid (the grid defaults to z=2.)
for w in wind:
    ax.plot((0, w[0]), (0, w[1]), color=w[2], linewidth=2, zorder=3)

# Right-size the grid (must be done after the plot), and customize the tick labels.
if max(wind_speed) <= 5:
    ax.yaxis.set_ticks(np.arange(1, 5, 1))
    ax.set_rgrids([1, 2, 3, 4, 5], angle=67, color='#FFFFFF', horizontalalignment='left', verticalalignment='center', fontsize=8)
elif 5 < max(wind_speed) <= 10:
    ax.yaxis.set_ticks(np.arange(2, 10, 2))
    ax.set_rgrids([2, 4, 6, 8, 10], angle=67, color='#FFFFFF', horizontalalignment='left', verticalalignment='center', fontsize=8)
elif 10 < max(wind_speed) <= 20:
    ax.yaxis.set_ticks(np.arange(5, 20, 5))
    ax.set_rgrids([5, 10, 15, 20], angle=67, color='#FFFFFF', horizontalalignment='left', verticalalignment='center', fontsize=8)
elif 20 < max(wind_speed) <= 50:
    ax.yaxis.set_ticks(np.arange(10, 50, 10))
    ax.set_rgrids([10, 20, 30, 40, 50], angle=67, color='#FFFFFF', horizontalalignment='left', verticalalignment='center', fontsize=8)
elif 50 < max(wind_speed):
    plt.text(0.5, 0.5, u'Holy crap!', color='white', horizontalalignment='center', verticalalignment='center', transform=ax.transAxes, bbox=dict(facecolor='red', alpha=0.5))

# Plot circles for current obs and max wind.
fig = plt.gcf()
max_wind_circle = plt.Circle((0, 0), max(wind_speed), transform=ax.transData._b, fill=False, edgecolor='indigo', linewidth=2, alpha=1, zorder=9)
fig.gca().add_artist(max_wind_circle)
last_wind_circle = plt.Circle((0, 0), wind_speed[num_obs-1], transform=ax.transData._b, fill=False, edgecolor='red', linewidth=2, alpha=1, zorder=10)
fig.gca().add_artist(last_wind_circle)

# If latest obs is a speed of zero, plot something that we can see.
if wind_speed[num_obs-1] == 0:
    zero_wind_circle = plt.Circle((0, 0), 0.1, transform=ax.transData._b, fill=False, edgecolor='red', alpha=1)
    fig.gca().add_artist(zero_wind_circle)

# Save it to a file.
plt.savefig('/Users/username/Desktop/wind.png', facecolor='black', edgecolor='none')

ETA: CSV data (I no longer have the exact data to produce the plot; the following data are an approximation.)

wind_speed.csv

timestamp, wind speed
1970-01-01 00:00:00.000000,4
1970-01-01 01:00:00.000000,4
1970-01-01 02:00:00.000000,10
1970-01-01 03:00:00.000000,7
1970-01-01 04:00:00.000000,10
1970-01-01 05:00:00.000000,8
1970-01-01 06:00:00.000000,7
1970-01-01 07:00:00.000000,4

wind_dir.csv

timestamp,wind direction
1970-01-01 00:00:00.000000,1
1970-01-01 01:00:00.000000,260
1970-01-01 02:00:00.000000,267
1970-01-01 03:00:00.000000,267
1970-01-01 04:00:00.000000,269
1970-01-01 05:00:00.000000,300
1970-01-01 06:00:00.000000,190
1970-01-01 07:00:00.000000,269

Your real question is, how to plot on a polar plot with lines instead of bars? Answer: plot . A minimal and complete example of doing that:

#! /usr/bin/env python2.6
# -*- coding: utf-8 -*-

import csv
import numpy as np
import matplotlib.pyplot as plt

bar_colors     = ['#333333', '#444444', '#555555', '#666666', '#777777', '#888888', '#999999', '#AA0000']
num_obs        = len(bar_colors)

# Make up some data
wind_direction = (2*3.14)*(np.random.random_sample(num_obs))
wind_speed = 5 * np.random.random_sample(num_obs)
wind = zip(wind_direction, wind_speed, bar_colors) # polar(theta,r)

# Polar plotting
fig = plt.figure(figsize=(3, 3))  # Size
ax = plt.subplot(111, polar=True)  # Create subplot
plt.grid(color='#888888')  # Color the grid
ax.set_theta_zero_location('N')  # Set zero to North

for w in wind:
    #ax.plot(wind_speed, wind_direction, c = bar_colors, zorder = 3)
    ax.plot((0, w[0]), ( 0, w[1]), c = w[2], zorder = 3)

fig.show()

在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM