最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

python - Have a 3D Effect on Y-axis of a Matplotlib Graph - Stack Overflow

programmeradmin3浏览0评论

I have been trying to mimic this bar graph style that I found online. I was able to mimic several different parts, however, I am unable to mimic this 3D feel on the Y-axis. Using Python, any ideas of how could I make this happen? I am happy to use a different library if needed (tried Seaborn but same problem, no 3D effect.

Don't expect you to change my code as it is too long but if you wanna check what I have:

def create_bar_chart(
countries,
values,
date_str,
title
):

"""
Create an equity allocation chart with countries sorted by allocation percentage

Parameters
----------
- countries: list of country names
- values: list of allocation percentages (0-100)
- date_str: date to display as subtitle
- title: main chart title
"""
# ---- DATA PREPARATION ----
# Sort data by values in descending order (highest allocation first)
data = sorted(zip(countries, values, strict=False), key=lambda x: x[1], reverse=True)
sorted_countries = [item[0] for item in data]
sorted_values = [item[1] for item in data]

# Reverse the lists to get highest value at the top of the chart
# This makes the chart more intuitive to read (largest values at the top)
sorted_countries.reverse()
sorted_values.reverse()

# ---- FIGURE SETUP ----
# Create figure and axis with specified dimensions (width=12, height=6 inches)
fig, ax = plt.subplots(figsize=(12, 6))

# ---- PLOTTING THE BARS ----
# Create horizontal bars with yellow color (#FFDC00)
# zorder=3 ensures bars appear in front of grid lines
# height=0.5 controls the thickness of each bar
bars = ax.barh(sorted_countries, sorted_values, color="#FFDC00", height=0.5, zorder=3)

# ---- ADDING PERCENTAGE LABELS ----
# Add text labels showing the exact percentage at the end of each bar
for i, bar in enumerate(bars):
    value = sorted_values[i]  # Get the correct value for this bar
    width = bar.get_width()
    label_pos = width + 1  # Position label 1 unit to the right of bar end
    # Place text vertically centered on the bar with 1 decimal place precision
    ax.text(label_pos, bar.get_y() + bar.get_height() / 2, f"{value:.1f}%", va="center", fontsize=9)

# ---- ADDING 3D VISUAL EFFECTS ----
# Create gray divider strip on left side of chart (3D effect)
divider_width = 2
ax.add_patch(Rectangle((-divider_width, -0.5), divider_width, len(sorted_countries), color="#E6E6E6", zorder=1))

# Add 3D effect details for each country row
for i, country in enumerate(sorted_countries):
    # Right shadow edge - creates depth illusion
    ax.add_patch(
        Polygon(
            [(0, i - 0.25), (0, i + 0.25), (-0.15, i + 0.25), (-0.15, i - 0.25)],
            closed=True,
            color="#AAAAAA",
            zorder=2,
        )
    )
    # Top shadow edge - enhances 3D appearance
    ax.add_patch(
        Polygon(
            [(-divider_width, i + 0.25), (0, i + 0.25), (-0.15, i + 0.25), (-divider_width - 0.15, i + 0.25)],
            closed=True,
            color="#C0C0C0",
            zorder=2,
        )
    )

# ---- GRID AND AXES STYLING ----
# Add light gray grid lines for x-axis only
# zorder=0 places grid behind all other elements
ax.grid(axis="x", color="#DDDDDD", linestyle="-", linewidth=0.5, zorder=0)
ax.set_axisbelow(True)  # Ensures grid is behind other elements

# Position x-axis ticks and labels at the top of the chart
ax.xaxis.tick_top()
# Create ticks from 0% to 100% in increments of 10%
ax.set_xticks(np.arange(0, 110, 10))
ax.set_xticklabels([f"{x}%" for x in range(0, 110, 10)])

# Remove all border lines around the plot
for spine in ax.spines.values():
    spine.set_visible(False)

# ---- TITLE AND SUBTITLE ----
# Add main title in bold at specific position
title_obj = plt.figtext(0.09, 0.925, title, fontsize=14, fontweight="bold")
# Add date subtitle in gray below the title
date_obj = plt.figtext(0.09, 0.875, f"as of {date_str}", fontsize=10, color="gray")

# Remove y-axis tick marks but keep the country labels
ax.tick_params(axis="y", which="both", left=False)

# Set x-axis limit to 105 to leave room for percentage labels
ax.set_xlim(0, 105)

# Add padding to left margin for better appearance
plt.subplots_adjust(left=0.09)

# Adjust overall layout to accommodate title and subtitle area
plt.tight_layout(rect=[0.0, 0.0, 1.0, 0.85])

# Return the figure and axis for further customization if needed
return fig, ax

Disclosure - I changed part of the code but I generated above Python using Chatgpt. (I also tried using Claude)

发布评论

评论列表(0)

  1. 暂无评论