> ## Documentation Index
> Fetch the complete documentation index at: https://data.avert.ldeo.columbia.edu/llms.txt
> Use this file to discover all available pages before exploring further.

# CLNE

> Cleveland North East

export const WeatherAirChart = ({station, availableYears = [], defaultYear}) => {
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  const [selectedYear, setSelectedYear] = useState(defaultYear || (availableYears.length > 0 ? availableYears[0] : new Date().getFullYear()));
  const stationName = station || "vpmi";
  const years = useMemo(() => availableYears, [availableYears]);
  const chartId = `weather-air-chart-${stationName}`;
  const triggerBlobDownload = async (url, filename) => {
    try {
      const response = await fetch(url, {
        method: "GET",
        mode: "cors",
        headers: {
          Accept: "application/octet-stream, application/csv, */*"
        }
      });
      if (!response.ok) throw new Error("Download failed");
      const blob = await response.blob();
      const cd = response.headers.get("content-disposition");
      if (cd) {
        const match = cd.match(/filename=([^;]+)$/i);
        if (match && match[1]) filename = match[1].replace(/\"/g, "").trim();
      }
      const href = URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.href = href;
      a.download = filename;
      document.body.appendChild(a);
      a.click();
      a.remove();
      URL.revokeObjectURL(href);
    } catch (e) {
      console.error("Download failed:", e);
      alert("Failed to download file. Please try again.");
    }
  };
  const renderChart = (data, yearForDownload) => {
    if (typeof window !== "undefined" && window.Plotly) {
      const chartDiv = document.getElementById(chartId);
      if (chartDiv) {
        const config = {
          ...data.chart_config.config,
          modeBarButtonsToAdd: [{
            name: "Download Year CSV",
            icon: window.Plotly.Icons.disk || window.Plotly.Icons.camera,
            click: () => {
              const url = `https://avert.ldeo.columbia.edu/api/download/weather/${yearForDownload}/${stationName}/air`;
              const fname = `${stationName}_${yearForDownload}_air.csv`;
              triggerBlobDownload(url, fname);
            }
          }],
          modeBarButtonsToRemove: [...data.chart_config.config?.modeBarButtonsToRemove || [], "zoom2d", "autoScale2d"]
        };
        const layout = {
          ...data.chart_config.layout,
          height: 600,
          paper_bgcolor: "rgba(0,0,0,0)",
          plot_bgcolor: "rgba(0,0,0,0)"
        };
        try {
          window.Plotly.newPlot(chartDiv, data.chart_config.data, layout, config);
        } catch (error) {
          console.error("Error rendering chart:", error);
        }
      }
    }
  };
  useEffect(() => {
    const loadPlotlyAndFetchData = async () => {
      setLoading(true);
      setError(null);
      if (typeof window !== "undefined" && !window.Plotly) {
        await new Promise((resolve, reject) => {
          const script = document.createElement("script");
          script.src = "https://cdn.plot.ly/plotly-2.35.2.min.js";
          script.onload = () => resolve();
          script.onerror = () => reject(new Error("Failed to load Plotly"));
          document.head.appendChild(script);
        });
      }
      try {
        const url = `https://avert.ldeo.columbia.edu/api/generate-interactive-chart/weather-air/${selectedYear}/${stationName}`;
        const response = await fetch(url, {
          method: "POST",
          mode: "cors",
          headers: {
            "Content-Type": "application/json",
            Accept: "application/json"
          }
        });
        if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
        const data = await response.json();
        if (data.success) {
          setTimeout(() => renderChart(data, selectedYear), 200);
        } else {
          throw new Error("Failed to generate chart");
        }
      } catch (err) {
        setError(err.message);
        console.error("Error:", err);
      } finally {
        setLoading(false);
      }
    };
    loadPlotlyAndFetchData();
  }, [selectedYear, stationName]);
  if (loading) {
    return <div className="flex items-center justify-center h-64">
        <div className="animate-spin rounded-full h-16 w-16 border-t-2 border-b-2 border-[#0B1D26]"></div>
        <p className="ml-4 text-gray-600 dark:text-gray-300">
          Loading chart data...
        </p>
      </div>;
  }
  if (error) {
    return <div className="text-red-500 p-4 border border-red-300 rounded-md bg-red-50 dark:bg-red-900 dark:border-red-700">
        <p>{error}</p>
      </div>;
  }
  return <div className="border border-zinc-950/20 dark:border-white/20 rounded-xl overflow-hidden relative">
      <div className="bg-zinc-50 dark:bg-zinc-900 px-4 py-3 border-b border-zinc-950/20 dark:border-white/20">
        <div className="flex items-center justify-between">
          <div className="text-sm font-medium text-zinc-950 dark:text-white">
            [{selectedYear}] Air (Temperature, Humidity, Pressure) - {stationName.toUpperCase()}
          </div>
          <select value={selectedYear} onChange={e => setSelectedYear(parseInt(e.target.value))} className="text-xs px-2 py-1 border border-zinc-300 dark:border-zinc-600 rounded bg-white dark:bg-zinc-800">
            {years.map(yearOption => <option key={yearOption} value={yearOption}>
                {yearOption}
              </option>)}
          </select>
        </div>
      </div>
      <div id={chartId} style={{
    width: "100%",
    height: "600px"
  }} className="relative"></div>

      <style>{`
        #${chartId} .modebar-group {
          display: flex !important;
          flex-direction: column !important;
        }
      `}</style>
    </div>;
};

export const WeatherWindDirectionChart = ({station, availableYears = [], defaultYear}) => {
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  const [selectedYear, setSelectedYear] = useState(defaultYear || (availableYears.length > 0 ? availableYears[0] : new Date().getFullYear()));
  const stationName = station || "vpmi";
  const years = useMemo(() => availableYears, [availableYears]);
  const chartId = `weather-wind-direction-chart-${stationName}`;
  const triggerBlobDownload = async (url, filename) => {
    try {
      const response = await fetch(url, {
        method: "GET",
        mode: "cors",
        headers: {
          Accept: "application/octet-stream, application/csv, */*"
        }
      });
      if (!response.ok) throw new Error("Download failed");
      const blob = await response.blob();
      const cd = response.headers.get("content-disposition");
      if (cd) {
        const match = cd.match(/filename=([^;]+)$/i);
        if (match && match[1]) filename = match[1].replace(/\"/g, "").trim();
      }
      const href = URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.href = href;
      a.download = filename;
      document.body.appendChild(a);
      a.click();
      a.remove();
      URL.revokeObjectURL(href);
    } catch (e) {
      console.error("Download failed:", e);
      alert("Failed to download file. Please try again.");
    }
  };
  const renderChart = (data, yearForDownload) => {
    if (typeof window !== "undefined" && window.Plotly) {
      const chartDiv = document.getElementById(chartId);
      if (chartDiv) {
        const config = {
          ...data.chart_config.config,
          modeBarButtonsToAdd: [{
            name: "Download Year CSV",
            icon: window.Plotly.Icons.disk || window.Plotly.Icons.camera,
            click: () => {
              const url = `https://avert.ldeo.columbia.edu/api/download/weather/${yearForDownload}/${stationName}/wind`;
              const fname = `${stationName}_${yearForDownload}_wind.csv`;
              triggerBlobDownload(url, fname);
            }
          }],
          modeBarButtonsToRemove: [...data.chart_config.config?.modeBarButtonsToRemove || [], "zoom2d", "autoScale2d"]
        };
        const layout = {
          ...data.chart_config.layout,
          height: 600,
          paper_bgcolor: "rgba(0,0,0,0)",
          plot_bgcolor: "rgba(0,0,0,0)"
        };
        try {
          window.Plotly.newPlot(chartDiv, data.chart_config.data, layout, config);
        } catch (error) {
          console.error("Error rendering chart:", error);
        }
      }
    }
  };
  useEffect(() => {
    const loadPlotlyAndFetchData = async () => {
      setLoading(true);
      setError(null);
      if (typeof window !== "undefined" && !window.Plotly) {
        await new Promise((resolve, reject) => {
          const script = document.createElement("script");
          script.src = "https://cdn.plot.ly/plotly-2.35.2.min.js";
          script.onload = () => resolve();
          script.onerror = () => reject(new Error("Failed to load Plotly"));
          document.head.appendChild(script);
        });
      }
      try {
        const url = `https://avert.ldeo.columbia.edu/api/generate-interactive-chart/weather-wind-direction/${selectedYear}/${stationName}`;
        const response = await fetch(url, {
          method: "POST",
          mode: "cors",
          headers: {
            "Content-Type": "application/json",
            Accept: "application/json"
          }
        });
        if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
        const data = await response.json();
        if (data.success) {
          setTimeout(() => renderChart(data, selectedYear), 200);
        } else {
          throw new Error("Failed to generate chart");
        }
      } catch (err) {
        setError(err.message);
        console.error("Error:", err);
      } finally {
        setLoading(false);
      }
    };
    loadPlotlyAndFetchData();
  }, [selectedYear, stationName]);
  if (loading) {
    return <div className="flex items-center justify-center h-64">
        <div className="animate-spin rounded-full h-16 w-16 border-t-2 border-b-2 border-[#0B1D26]"></div>
        <p className="ml-4 text-gray-600 dark:text-gray-300">
          Loading chart data...
        </p>
      </div>;
  }
  if (error) {
    return <div className="text-red-500 p-4 border border-red-300 rounded-md bg-red-50 dark:bg-red-900 dark:border-red-700">
        <p>{error}</p>
      </div>;
  }
  return <div className="border border-zinc-950/20 dark:border-white/20 rounded-xl overflow-hidden relative">
      <div className="bg-zinc-50 dark:bg-zinc-900 px-4 py-3 border-b border-zinc-950/20 dark:border-white/20">
        <div className="flex items-center justify-between">
          <div className="text-sm font-medium text-zinc-950 dark:text-white">
            [{selectedYear}] Wind Direction - {stationName.toUpperCase()}
          </div>
          <select value={selectedYear} onChange={e => setSelectedYear(parseInt(e.target.value))} className="text-xs px-2 py-1 border border-zinc-300 dark:border-zinc-600 rounded bg-white dark:bg-zinc-800">
            {years.map(yearOption => <option key={yearOption} value={yearOption}>
                {yearOption}
              </option>)}
          </select>
        </div>
      </div>
      <div id={chartId} style={{
    width: "100%",
    height: "600px"
  }} className="relative"></div>

      <style>{`
        #${chartId} .modebar-group {
          display: flex !important;
          flex-direction: column !important;
        }
      `}</style>
    </div>;
};

export const WeatherWindSpeedChart = ({station, availableYears = [], defaultYear}) => {
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  const [selectedYear, setSelectedYear] = useState(defaultYear || (availableYears.length > 0 ? availableYears[0] : new Date().getFullYear()));
  const stationName = station || "vpmi";
  const years = useMemo(() => availableYears, [availableYears]);
  const chartId = `weather-wind-speed-chart-${stationName}`;
  const triggerBlobDownload = async (url, filename) => {
    try {
      const response = await fetch(url, {
        method: "GET",
        mode: "cors",
        headers: {
          Accept: "application/octet-stream, application/csv, */*"
        }
      });
      if (!response.ok) throw new Error("Download failed");
      const blob = await response.blob();
      const cd = response.headers.get("content-disposition");
      if (cd) {
        const match = cd.match(/filename=([^;]+)$/i);
        if (match && match[1]) filename = match[1].replace(/\"/g, "").trim();
      }
      const href = URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.href = href;
      a.download = filename;
      document.body.appendChild(a);
      a.click();
      a.remove();
      URL.revokeObjectURL(href);
    } catch (e) {
      console.error("Download failed:", e);
      alert("Failed to download file. Please try again.");
    }
  };
  const renderChart = (data, yearForDownload) => {
    if (typeof window !== "undefined" && window.Plotly) {
      const chartDiv = document.getElementById(chartId);
      if (chartDiv) {
        const config = {
          ...data.chart_config.config,
          modeBarButtonsToAdd: [{
            name: "Download Year CSV",
            icon: window.Plotly.Icons.disk || window.Plotly.Icons.camera,
            click: () => {
              const url = `https://avert.ldeo.columbia.edu/api/download/weather/${yearForDownload}/${stationName}/wind`;
              const fname = `${stationName}_${yearForDownload}_wind.csv`;
              triggerBlobDownload(url, fname);
            }
          }],
          modeBarButtonsToRemove: [...data.chart_config.config?.modeBarButtonsToRemove || [], "zoom2d", "autoScale2d"]
        };
        const layout = {
          ...data.chart_config.layout,
          height: 600,
          paper_bgcolor: "rgba(0,0,0,0)",
          plot_bgcolor: "rgba(0,0,0,0)"
        };
        try {
          window.Plotly.newPlot(chartDiv, data.chart_config.data, layout, config);
        } catch (error) {
          console.error("Error rendering chart:", error);
        }
      }
    }
  };
  useEffect(() => {
    const loadPlotlyAndFetchData = async () => {
      setLoading(true);
      setError(null);
      if (typeof window !== "undefined" && !window.Plotly) {
        await new Promise((resolve, reject) => {
          const script = document.createElement("script");
          script.src = "https://cdn.plot.ly/plotly-2.35.2.min.js";
          script.onload = () => resolve();
          script.onerror = () => reject(new Error("Failed to load Plotly"));
          document.head.appendChild(script);
        });
      }
      try {
        const url = `https://avert.ldeo.columbia.edu/api/generate-interactive-chart/weather-wind-speed/${selectedYear}/${stationName}`;
        const response = await fetch(url, {
          method: "POST",
          mode: "cors",
          headers: {
            "Content-Type": "application/json",
            Accept: "application/json"
          }
        });
        if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
        const data = await response.json();
        if (data.success) {
          setTimeout(() => renderChart(data, selectedYear), 200);
        } else {
          throw new Error("Failed to generate chart");
        }
      } catch (err) {
        setError(err.message);
        console.error("Error:", err);
      } finally {
        setLoading(false);
      }
    };
    loadPlotlyAndFetchData();
  }, [selectedYear, stationName]);
  if (loading) {
    return <div className="flex items-center justify-center h-64">
        <div className="animate-spin rounded-full h-16 w-16 border-t-2 border-b-2 border-[#0B1D26]"></div>
        <p className="ml-4 text-gray-600 dark:text-gray-300">
          Loading chart data...
        </p>
      </div>;
  }
  if (error) {
    return <div className="text-red-500 p-4 border border-red-300 rounded-md bg-red-50 dark:bg-red-900 dark:border-red-700">
        <p>{error}</p>
      </div>;
  }
  return <div className="border border-zinc-950/20 dark:border-white/20 rounded-xl overflow-hidden relative">
      <div className="bg-zinc-50 dark:bg-zinc-900 px-4 py-3 border-b border-zinc-950/20 dark:border-white/20">
        <div className="flex items-center justify-between">
          <div className="text-sm font-medium text-zinc-950 dark:text-white">
            [{selectedYear}] Wind Speed - {stationName.toUpperCase()}
          </div>
          <select value={selectedYear} onChange={e => setSelectedYear(parseInt(e.target.value))} className="text-xs px-2 py-1 border border-zinc-300 dark:border-zinc-600 rounded bg-white dark:bg-zinc-800">
            {years.map(yearOption => <option key={yearOption} value={yearOption}>
                {yearOption}
              </option>)}
          </select>
        </div>
      </div>
      <div id={chartId} style={{
    width: "100%",
    height: "600px"
  }} className="relative"></div>

      <style>{`
        #${chartId} .modebar-group {
          display: flex !important;
          flex-direction: column !important;
        }
      `}</style>
    </div>;
};

<Tabs>
  <Tab title="Wind Speed">
    <WeatherWindSpeedChart station="clne" availableYears={[2024, 2023, 2022]} defaultYear={2024} />
  </Tab>

  <Tab title="Wind Direction">
    <WeatherWindDirectionChart station="clne" availableYears={[2024, 2023, 2022]} defaultYear={2024} />
  </Tab>

  <Tab title="Air">
    <WeatherAirChart station="clne" availableYears={[2024, 2023, 2022]} defaultYear={2024} />
  </Tab>
</Tabs>

## Download Data

Download CSV files for each year:

* **Download 2024 Data:**
  [Wind](https://avert.ldeo.columbia.edu/api/download/weather/2024/clne/wind) |
  [Air](https://avert.ldeo.columbia.edu/api/download/weather/2024/clne/air) |
  [Combined](https://avert.ldeo.columbia.edu/api/download/weather/2024/clne/combined)
* **Download 2023 Data:**
  [Wind](https://avert.ldeo.columbia.edu/api/download/weather/2023/clne/wind) |
  [Air](https://avert.ldeo.columbia.edu/api/download/weather/2023/clne/air) |
  [Combined](https://avert.ldeo.columbia.edu/api/download/weather/2023/clne/combined)
* **Download 2022 Data:**
  [Wind](https://avert.ldeo.columbia.edu/api/download/weather/2022/clne/wind) |
  [Air](https://avert.ldeo.columbia.edu/api/download/weather/2022/clne/air) |
  [Combined](https://avert.ldeo.columbia.edu/api/download/weather/2022/clne/combined)

### Wind Data Columns

| Column | Description       |
| ------ | ----------------- |
| Dn     | Direction minimum |
| Dm     | Direction average |
| Dx     | Direction maximum |
| Sn     | Speed minimum     |
| Sm     | Speed average     |
| Sx     | Speed maximum     |

### Air Data Columns

| Column | Description     |
| ------ | --------------- |
| Pa     | Air pressure    |
| Ta     | Air temperature |
| Ua     | Air humidity    |

## Station Information

**Location:** North-eastern flank of Cleveland volcano, Alaska

**Installation Date:** September 2022 (AVERT project)

**Instrumentation:**

* Vaisala WXT536 meteorological station

**Data Collection:**

* Air temperature
* Atmospheric pressure
* Relative humidity
* Precipitation
* Wind speed and direction

**Co-located instruments:**

* Broadband seismometer
* Visible and IR cameras
* 3-component fluxgate magnetometer
* Scanning DOAS sensor
* GNSS antenna
