结合geom_point与geom_col并分面的可视化实现技术问询
Got it, let's work through how to combine geom_col, geom_point, and faceting for your portfolio data—this should work perfectly for your 8 portfolios with 30 stocks each!
First, let's formalize your sample melted data into a tidy tibble for consistency:
library(tidyverse) # Your sample portfolio data portfolio_df <- tibble( Ticker = c("AAPL", "ABBV", "AAPL", "ABBV", "AAPL", "ABBV"), variable = c("Factor_Risk", "Factor_Risk", "Stock_Specific_Risk", "Stock_Specific_Risk", "Weight", "Weight"), value = c(4.66, 1.71, 0.21, 0.07, 4.00, 1.66), Portfolio = c("US", "INTL", "US", "INTL", "US", "INTL") )
Basic Combined Visualization with Faceting
The core approach is to layer your stacked bar chart (for risk components) and points (for weights) separately, then use faceting to split the view by each portfolio. Here's a straightforward implementation:
ggplot() + # Stacked bars for risk components geom_col( data = portfolio_df %>% filter(variable %in% c("Factor_Risk", "Stock_Specific_Risk")), aes(x = Ticker, y = value, fill = variable), position = "stack" ) + # Points for stock weights geom_point( data = portfolio_df %>% filter(variable == "Weight"), aes(x = Ticker, y = value, color = variable), size = 4, shape = 19 ) + # Split into facets by Portfolio (free x-axis avoids crowded tickers) facet_wrap(~Portfolio, scales = "free_x") + # Custom labels and styling labs( title = "Portfolio Risk Components & Stock Weights", x = "Stock Ticker", y = "Value", fill = "Risk Component", color = "Metric" ) + theme_minimal() + theme(plot.title = element_text(hjust = 0.5))
Key Details Explained:
- Layered Geoms: We filter the data for each geom separately—
geom_coluses only the risk variables, whilegeom_pointtargets just the weight values. This keeps each layer focused on its specific metric. - Facetting:
facet_wrap(~Portfolio)creates a separate plot for each portfolio.scales = "free_x"ensures each facet only shows the tickers present in that portfolio, which is critical for your real-world data with 30 stocks per portfolio (no more crowded x-axes!). - Styling: Using distinct
fill(for bars) andcolor(for points) makes it easy to distinguish between risk components and weights.
Enhanced Version: Weights Above Total Risk
If you want to place weight points above the total stacked risk (so they don't overlap with bars), first calculate the total risk per stock, then adjust the y-position of the points:
# Calculate total risk per stock in each portfolio total_risk <- portfolio_df %>% filter(variable %in% c("Factor_Risk", "Stock_Specific_Risk")) %>% group_by(Portfolio, Ticker) %>% summarise(total_risk = sum(value), .groups = "drop") # Merge total risk with weight data weight_with_risk <- portfolio_df %>% filter(variable == "Weight") %>% left_join(total_risk, by = c("Portfolio", "Ticker")) # Build the enhanced plot ggplot() + geom_col( data = portfolio_df %>% filter(variable %in% c("Factor_Risk", "Stock_Specific_Risk")), aes(x = Ticker, y = value, fill = variable), position = "stack" ) + # Place points above total risk, add labels for clarity geom_point( data = weight_with_risk, aes(x = Ticker, y = total_risk + value, color = variable), size = 4, shape = 19 ) + geom_text( data = weight_with_risk, aes(x = Ticker, y = total_risk + value, label = paste0("Wt: ", value)), vjust = -0.5, color = "darkred" ) + # Arrange 8 portfolios into a clean 4-column grid facet_wrap(~Portfolio, scales = "free_x", ncol = 4) + labs( title = "Portfolio Risk Components with Weights Above Total Risk", x = "Stock Ticker", y = "Value", fill = "Risk Component", color = "Metric" ) + theme_minimal() + theme(plot.title = element_text(hjust = 0.5))
This version adds context by showing weights relative to total risk, and uses ncol = 4 in facet_wrap to neatly arrange your 8 portfolios into a grid.
内容的提问来源于stack exchange,提问作者bigjdawg43

