diff --git a/plots/altair/bar/histogram-basic/default.py b/plots/altair/bar/histogram-basic/default.py new file mode 100644 index 0000000000..a98f8eb813 --- /dev/null +++ b/plots/altair/bar/histogram-basic/default.py @@ -0,0 +1,26 @@ +""" +histogram-basic: Basic Histogram +Library: altair +""" + +import altair as alt +import numpy as np +import pandas as pd + + +# Data +np.random.seed(42) +data = pd.DataFrame({"value": np.random.normal(100, 15, 500)}) + +# Create histogram chart +chart = ( + alt.Chart(data) + .mark_bar(color="#306998", opacity=0.8) + .encode(alt.X("value:Q", bin=alt.Bin(maxbins=30), title="Value"), alt.Y("count()", title="Frequency")) + .properties(width=1600, height=900, title="Basic Histogram") + .configure_axis(labelFontSize=16, titleFontSize=20) + .configure_title(fontSize=20) +) + +# Save as PNG (1600 × 900 at scale 3 = 4800 × 2700) +chart.save("plot.png", scale_factor=3.0) diff --git a/plots/bokeh/quad/histogram-basic/default.py b/plots/bokeh/quad/histogram-basic/default.py new file mode 100644 index 0000000000..07bb421191 --- /dev/null +++ b/plots/bokeh/quad/histogram-basic/default.py @@ -0,0 +1,51 @@ +""" +histogram-basic: Basic Histogram +Library: bokeh +""" + +import numpy as np +from bokeh.io import export_png +from bokeh.plotting import figure + + +# Data - 500 normally distributed values (mean=100, std=15) +np.random.seed(42) +values = np.random.normal(100, 15, 500) + +# Compute histogram bins +hist, edges = np.histogram(values, bins=30) + +# Create figure (4800 x 2700 px for high resolution) +p = figure(width=4800, height=2700, title="Basic Histogram", x_axis_label="Value", y_axis_label="Frequency") + +# Draw histogram using quad glyph +p.quad( + top=hist, + bottom=0, + left=edges[:-1], + right=edges[1:], + fill_color="#306998", + fill_alpha=0.7, + line_color="white", + line_width=1, +) + +# Style title +p.title.text_font_size = "20pt" +p.title.align = "center" + +# Style axis labels +p.xaxis.axis_label_text_font_size = "20pt" +p.yaxis.axis_label_text_font_size = "20pt" +p.xaxis.major_label_text_font_size = "16pt" +p.yaxis.major_label_text_font_size = "16pt" + +# Style grid - subtle +p.xgrid.grid_line_alpha = 0.3 +p.ygrid.grid_line_alpha = 0.3 + +# Ensure y-axis starts at zero +p.y_range.start = 0 + +# Save output +export_png(p, filename="plot.png") diff --git a/plots/highcharts/histogram/histogram-basic/default.py b/plots/highcharts/histogram/histogram-basic/default.py new file mode 100644 index 0000000000..1d39589cd2 --- /dev/null +++ b/plots/highcharts/histogram/histogram-basic/default.py @@ -0,0 +1,124 @@ +""" +histogram-basic: Basic Histogram +Library: highcharts +""" + +import tempfile +import time +import urllib.request +from pathlib import Path + +import numpy as np +from highcharts_core.chart import Chart +from highcharts_core.options import HighchartsOptions +from highcharts_core.options.series.bar import ColumnSeries +from selenium import webdriver +from selenium.webdriver.chrome.options import Options + + +# Data +np.random.seed(42) +values = np.random.normal(100, 15, 500) # 500 values, mean=100, std=15 + +# Calculate histogram bins +bins = 30 +counts, bin_edges = np.histogram(values, bins=bins) + +# Create bin labels (center of each bin) +bin_centers = [(bin_edges[i] + bin_edges[i + 1]) / 2 for i in range(len(counts))] +bin_labels = [f"{bin_edges[i]:.1f}-{bin_edges[i + 1]:.1f}" for i in range(len(counts))] + +# Create chart with container ID +chart = Chart(container="container") +chart.options = HighchartsOptions() + +# Chart configuration +chart.options.chart = { + "type": "column", + "width": 4800, + "height": 2700, + "backgroundColor": "#ffffff", + "spacingBottom": 120, # Add space for x-axis title +} + +# Title +chart.options.title = {"text": "Basic Histogram", "style": {"fontSize": "48px", "fontWeight": "bold"}} + +# X-axis configuration +chart.options.x_axis = { + "categories": bin_labels, + "title": {"text": "Value", "style": {"fontSize": "40px"}}, + "labels": { + "rotation": 315, # 315 degrees = -45 degrees + "style": {"fontSize": "28px"}, + "step": 3, # Show every 3rd label to avoid overlap + }, +} + +# Y-axis configuration +chart.options.y_axis = { + "title": {"text": "Frequency", "style": {"fontSize": "40px"}}, + "min": 0, + "gridLineWidth": 1, + "gridLineDashStyle": "Dot", + "gridLineColor": "rgba(0, 0, 0, 0.15)", + "labels": {"style": {"fontSize": "32px"}}, +} + +# Create series with histogram data +series = ColumnSeries() +series.data = counts.tolist() +series.name = "Frequency" +series.color = "#306998" # Python Blue +series.border_color = "white" +series.border_width = 1 + +# Plot options for histogram appearance +chart.options.plot_options = {"column": {"pointPadding": 0, "groupPadding": 0, "borderWidth": 1, "opacity": 0.8}} + +chart.add_series(series) + +# Legend (single series, hide) +chart.options.legend = {"enabled": False} + +# Credits +chart.options.credits = {"enabled": False} + +# Download Highcharts JS (required for headless Chrome) +highcharts_url = "https://code.highcharts.com/highcharts.js" +with urllib.request.urlopen(highcharts_url, timeout=30) as response: + highcharts_js = response.read().decode("utf-8") + +# Generate HTML with inline scripts +html_str = chart.to_js_literal() +html_content = f""" + + + + + + +
+ + +""" + +# Write temp HTML and take screenshot +with tempfile.NamedTemporaryFile(mode="w", suffix=".html", delete=False, encoding="utf-8") as f: + f.write(html_content) + temp_path = f.name + +chrome_options = Options() +chrome_options.add_argument("--headless") +chrome_options.add_argument("--no-sandbox") +chrome_options.add_argument("--disable-dev-shm-usage") +chrome_options.add_argument("--disable-gpu") +chrome_options.add_argument("--window-size=4800,2800") # Slightly larger to capture full chart + +driver = webdriver.Chrome(options=chrome_options) +driver.get(f"file://{temp_path}") +time.sleep(5) # Wait for chart to render +driver.save_screenshot("plot.png") +driver.quit() + +Path(temp_path).unlink() # Clean up temp file diff --git a/plots/letsplot/histogram/histogram-basic/default.py b/plots/letsplot/histogram/histogram-basic/default.py new file mode 100644 index 0000000000..ca5a3afb99 --- /dev/null +++ b/plots/letsplot/histogram/histogram-basic/default.py @@ -0,0 +1,28 @@ +""" +histogram-basic: Basic Histogram +Library: letsplot +""" + +import numpy as np +import pandas as pd +from lets_plot import LetsPlot, aes, element_text, geom_histogram, ggplot, ggsave, ggsize, labs, theme, theme_minimal + + +LetsPlot.setup_html() + +# Data +np.random.seed(42) +data = pd.DataFrame({"value": np.random.normal(100, 15, 500)}) + +# Plot +plot = ( + ggplot(data, aes(x="value")) + + geom_histogram(bins=30, fill="#306998", color="white", alpha=0.8) + + labs(x="Value", y="Frequency", title="Basic Histogram") + + theme_minimal() + + theme(plot_title=element_text(size=20), axis_title=element_text(size=20), axis_text=element_text(size=16)) + + ggsize(1600, 900) +) + +# Save - scale 3x to get 4800 x 2700 px +ggsave(plot, "plot.png", path=".", scale=3) diff --git a/plots/matplotlib/hist/histogram-basic/default.py b/plots/matplotlib/hist/histogram-basic/default.py new file mode 100644 index 0000000000..ac2191c2ab --- /dev/null +++ b/plots/matplotlib/hist/histogram-basic/default.py @@ -0,0 +1,27 @@ +""" +histogram-basic: Basic Histogram +Library: matplotlib +""" + +import matplotlib.pyplot as plt +import numpy as np +import pandas as pd + + +# Data +np.random.seed(42) +data = pd.DataFrame({"value": np.random.normal(100, 15, 500)}) + +# Create plot +fig, ax = plt.subplots(figsize=(16, 9)) +ax.hist(data["value"], bins=30, alpha=0.8, color="#306998", edgecolor="white", linewidth=0.5) + +# Labels and styling +ax.set_xlabel("Value", fontsize=20) +ax.set_ylabel("Frequency", fontsize=20) +ax.set_title("Basic Histogram", fontsize=20) +ax.tick_params(axis="both", labelsize=16) +ax.grid(True, alpha=0.3, axis="y") + +plt.tight_layout() +plt.savefig("plot.png", dpi=300, bbox_inches="tight") diff --git a/plots/plotly/histogram/histogram-basic/default.py b/plots/plotly/histogram/histogram-basic/default.py new file mode 100644 index 0000000000..c64ca0d2f4 --- /dev/null +++ b/plots/plotly/histogram/histogram-basic/default.py @@ -0,0 +1,31 @@ +""" +histogram-basic: Basic Histogram +Library: plotly +""" + +import numpy as np +import plotly.graph_objects as go + + +# Data +np.random.seed(42) +values = np.random.normal(100, 15, 500) # 500 values, mean=100, std=15 + +# Create figure +fig = go.Figure() +fig.add_trace(go.Histogram(x=values, marker={"color": "#306998", "line": {"color": "white", "width": 1}}, opacity=0.85)) + +# Layout +fig.update_layout( + title={"text": "Basic Histogram", "font": {"size": 40}, "x": 0.5, "xanchor": "center"}, + xaxis_title="Value", + yaxis_title="Frequency", + template="plotly_white", + font={"size": 32}, + xaxis={"title_font": {"size": 40}, "tickfont": {"size": 32}, "showgrid": True, "gridcolor": "rgba(0,0,0,0.1)"}, + yaxis={"title_font": {"size": 40}, "tickfont": {"size": 32}, "showgrid": True, "gridcolor": "rgba(0,0,0,0.1)"}, + bargap=0.05, +) + +# Save +fig.write_image("plot.png", width=1600, height=900, scale=3) diff --git a/plots/plotnine/histogram/histogram-basic/default.py b/plots/plotnine/histogram/histogram-basic/default.py new file mode 100644 index 0000000000..657ace1c28 --- /dev/null +++ b/plots/plotnine/histogram/histogram-basic/default.py @@ -0,0 +1,30 @@ +""" +histogram-basic: Basic Histogram +Library: plotnine +""" + +import numpy as np +import pandas as pd +from plotnine import aes, element_text, geom_histogram, ggplot, labs, theme, theme_minimal + + +# Data +np.random.seed(42) +data = pd.DataFrame({"value": np.random.normal(100, 15, 500)}) + +# Plot +plot = ( + ggplot(data, aes(x="value")) + + geom_histogram(bins=30, fill="#306998", color="white", alpha=0.8) + + labs(x="Value", y="Frequency", title="Basic Histogram") + + theme_minimal() + + theme( + figure_size=(16, 9), + plot_title=element_text(size=20), + axis_title=element_text(size=20), + axis_text=element_text(size=16), + ) +) + +# Save +plot.save("plot.png", dpi=300) diff --git a/plots/pygal/histogram/histogram-basic/default.py b/plots/pygal/histogram/histogram-basic/default.py new file mode 100644 index 0000000000..debf7edcdf --- /dev/null +++ b/plots/pygal/histogram/histogram-basic/default.py @@ -0,0 +1,55 @@ +""" +histogram-basic: Basic Histogram +Library: pygal +""" + +import numpy as np +import pygal +from pygal.style import Style + + +# Data +np.random.seed(42) +values = np.random.normal(100, 15, 500) # 500 values, mean=100, std=15 + +# Calculate histogram bins +counts, bin_edges = np.histogram(values, bins=20) + +# Convert to pygal histogram format: (height, start, end) +histogram_data = [(int(count), float(bin_edges[i]), float(bin_edges[i + 1])) for i, count in enumerate(counts)] + +# Custom style matching default style guide colors +custom_style = Style( + background="white", + plot_background="white", + foreground="#333333", + foreground_strong="#333333", + foreground_subtle="#666666", + opacity="0.8", + opacity_hover="0.9", + colors=("#306998",), # Python Blue + guide_stroke_color="#cccccc", + major_guide_stroke_color="#cccccc", + title_font_size=48, + label_font_size=36, + major_label_font_size=36, +) + +# Create histogram chart +chart = pygal.Histogram( + width=4800, + height=2700, + title="Basic Histogram", + x_title="Value", + y_title="Frequency", + style=custom_style, + show_legend=False, + show_y_guides=True, + show_x_guides=False, +) + +# Add histogram data +chart.add("Distribution", histogram_data) + +# Save to PNG +chart.render_to_png("plot.png") diff --git a/plots/seaborn/histplot/histogram-basic/default.py b/plots/seaborn/histplot/histogram-basic/default.py index 09bd3f3583..37918c4162 100644 --- a/plots/seaborn/histplot/histogram-basic/default.py +++ b/plots/seaborn/histplot/histogram-basic/default.py @@ -1,113 +1,28 @@ """ histogram-basic: Basic Histogram -Implementation for: seaborn -Variant: default -Python: 3.10+ +Library: seaborn """ -from typing import TYPE_CHECKING, Optional - import matplotlib.pyplot as plt +import numpy as np import pandas as pd import seaborn as sns -if TYPE_CHECKING: - from matplotlib.figure import Figure - - -def create_plot( - data: pd.DataFrame, - column: str, - bins: int = 30, - color: str = "steelblue", - alpha: float = 0.8, - edgecolor: str = "black", - title: Optional[str] = None, - xlabel: Optional[str] = None, - ylabel: Optional[str] = None, - figsize: tuple[float, float] = (16, 9), - **kwargs, -) -> "Figure": - """ - Create a basic histogram showing the distribution of numeric data using seaborn. - - Args: - data: Input DataFrame with required column - column: Column name for numeric values to visualize - bins: Number of bins for histogram (default: 30) - color: Bar color (default: "steelblue") - alpha: Transparency level 0.0-1.0 (default: 0.8) - edgecolor: Border color for bins (default: "black") - title: Plot title (default: None) - xlabel: Custom x-axis label (default: column name) - ylabel: Custom y-axis label (default: "Frequency") - figsize: Figure size as (width, height) (default: (16, 9)) - **kwargs: Additional parameters passed to sns.histplot() - - Returns: - Matplotlib Figure object - - Raises: - ValueError: If data is empty - KeyError: If required column not found - ValueError: If column contains no numeric values - - Example: - >>> data = pd.DataFrame({'Values': [1.5, 2.1, 2.3, 3.2, 3.5, 4.1, 4.5]}) - >>> fig = create_plot(data, column='Values', bins=20) - """ - # Input validation - if data.empty: - raise ValueError("Data cannot be empty") - - # Check required column - if column not in data.columns: - available = ", ".join(data.columns) - raise KeyError(f"Column '{column}' not found. Available: {available}") - - # Check if column has numeric data - if not pd.api.types.is_numeric_dtype(data[column]): - raise ValueError(f"Column '{column}' must contain numeric values") - - # Remove NaN values for histogram - values = data[column].dropna() - - if len(values) == 0: - raise ValueError(f"Column '{column}' contains no valid numeric values") - - # Create figure - fig, ax = plt.subplots(figsize=figsize) - - # Create histogram using seaborn - sns.histplot(data=data, x=column, bins=bins, color=color, alpha=alpha, edgecolor=edgecolor, ax=ax, **kwargs) - - # Apply styling - ax.set_xlabel(xlabel or column) - ax.set_ylabel(ylabel or "Frequency") - ax.grid(True, axis="y", alpha=0.3, linestyle="--") - - # Title - if title: - ax.set_title(title, fontsize=14, fontweight="bold") - - # Tight layout to avoid label clipping - plt.tight_layout() - - return fig - - -if __name__ == "__main__": - # Sample data for testing - import numpy as np +# Data +np.random.seed(42) +data = pd.DataFrame({"value": np.random.normal(100, 15, 500)}) - np.random.seed(42) - data = pd.DataFrame({"Values": np.random.normal(loc=100, scale=15, size=1000)}) +# Create plot +fig, ax = plt.subplots(figsize=(16, 9)) +sns.histplot(data=data, x="value", bins=30, color="#306998", alpha=0.8, edgecolor="white", ax=ax) - # Create plot - fig = create_plot(data, column="Values", bins=40, title="Distribution of Values") +# Labels and styling +ax.set_xlabel("Value", fontsize=20) +ax.set_ylabel("Frequency", fontsize=20) +ax.set_title("Basic Histogram", fontsize=20) +ax.tick_params(axis="both", labelsize=16) +ax.grid(True, alpha=0.3, linestyle="-", linewidth=0.5) - # Save for inspection - plt.savefig("plot.png", dpi=300, bbox_inches="tight") - print("Plot saved to plot.png") - plt.show() +plt.tight_layout() +plt.savefig("plot.png", dpi=300, bbox_inches="tight")